phaser.js 3.2 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343443444434544346443474434844349443504435144352443534435444355443564435744358443594436044361443624436344364443654436644367443684436944370443714437244373443744437544376443774437844379443804438144382443834438444385443864438744388443894439044391443924439344394443954439644397443984439944400444014440244403444044440544406444074440844409444104441144412444134441444415444164441744418444194442044421444224442344424444254442644427444284442944430444314443244433444344443544436444374443844439444404444144442444434444444445444464444744448444494445044451444524445344454444554445644457444584445944460444614446244463444644446544466444674446844469444704447144472444734447444475444764447744478444794448044481444824448344484444854448644487444884448944490444914449244493444944449544496444974449844499445004450144502445034450444505445064450744508445094451044511445124451344514445154451644517445184451944520445214452244523445244452544526445274452844529445304453144532445334453444535445364453744538445394454044541445424454344544445454454644547445484454944550445514455244553445544455544556445574455844559445604456144562445634456444565445664456744568445694457044571445724457344574445754457644577445784457944580445814458244583445844458544586445874458844589445904459144592445934459444595445964459744598445994460044601446024460344604446054460644607446084460944610446114461244613446144461544616446174461844619446204462144622446234462444625446264462744628446294463044631446324463344634446354463644637446384463944640446414464244643446444464544646446474464844649446504465144652446534465444655446564465744658446594466044661446624466344664446654466644667446684466944670446714467244673446744467544676446774467844679446804468144682446834468444685446864468744688446894469044691446924469344694446954469644697446984469944700447014470244703447044470544706447074470844709447104471144712447134471444715447164471744718447194472044721447224472344724447254472644727447284472944730447314473244733447344473544736447374473844739447404474144742447434474444745447464474744748447494475044751447524475344754447554475644757447584475944760447614476244763447644476544766447674476844769447704477144772447734477444775447764477744778447794478044781447824478344784447854478644787447884478944790447914479244793447944479544796447974479844799448004480144802448034480444805448064480744808448094481044811448124481344814448154481644817448184481944820448214482244823448244482544826448274482844829448304483144832448334483444835448364483744838448394484044841448424484344844448454484644847448484484944850448514485244853448544485544856448574485844859448604486144862448634486444865448664486744868448694487044871448724487344874448754487644877448784487944880448814488244883448844488544886448874488844889448904489144892448934489444895448964489744898448994490044901449024490344904449054490644907449084490944910449114491244913449144491544916449174491844919449204492144922449234492444925449264492744928449294493044931449324493344934449354493644937449384493944940449414494244943449444494544946449474494844949449504495144952449534495444955449564495744958449594496044961449624496344964449654496644967449684496944970449714497244973449744497544976449774497844979449804498144982449834498444985449864498744988449894499044991449924499344994449954499644997449984499945000450014500245003450044500545006450074500845009450104501145012450134501445015450164501745018450194502045021450224502345024450254502645027450284502945030450314503245033450344503545036450374503845039450404504145042450434504445045450464504745048450494505045051450524505345054450554505645057450584505945060450614506245063450644506545066450674506845069450704507145072450734507445075450764507745078450794508045081450824508345084450854508645087450884508945090450914509245093450944509545096450974509845099451004510145102451034510445105451064510745108451094511045111451124511345114451154511645117451184511945120451214512245123451244512545126451274512845129451304513145132451334513445135451364513745138451394514045141451424514345144451454514645147451484514945150451514515245153451544515545156451574515845159451604516145162451634516445165451664516745168451694517045171451724517345174451754517645177451784517945180451814518245183451844518545186451874518845189451904519145192451934519445195451964519745198451994520045201452024520345204452054520645207452084520945210452114521245213452144521545216452174521845219452204522145222452234522445225452264522745228452294523045231452324523345234452354523645237452384523945240452414524245243452444524545246452474524845249452504525145252452534525445255452564525745258452594526045261452624526345264452654526645267452684526945270452714527245273452744527545276452774527845279452804528145282452834528445285452864528745288452894529045291452924529345294452954529645297452984529945300453014530245303453044530545306453074530845309453104531145312453134531445315453164531745318453194532045321453224532345324453254532645327453284532945330453314533245333453344533545336453374533845339453404534145342453434534445345453464534745348453494535045351453524535345354453554535645357453584535945360453614536245363453644536545366453674536845369453704537145372453734537445375453764537745378453794538045381453824538345384453854538645387453884538945390453914539245393453944539545396453974539845399454004540145402454034540445405454064540745408454094541045411454124541345414454154541645417454184541945420454214542245423454244542545426454274542845429454304543145432454334543445435454364543745438454394544045441454424544345444454454544645447454484544945450454514545245453454544545545456454574545845459454604546145462454634546445465454664546745468454694547045471454724547345474454754547645477454784547945480454814548245483454844548545486454874548845489454904549145492454934549445495454964549745498454994550045501455024550345504455054550645507455084550945510455114551245513455144551545516455174551845519455204552145522455234552445525455264552745528455294553045531455324553345534455354553645537455384553945540455414554245543455444554545546455474554845549455504555145552455534555445555455564555745558455594556045561455624556345564455654556645567455684556945570455714557245573455744557545576455774557845579455804558145582455834558445585455864558745588455894559045591455924559345594455954559645597455984559945600456014560245603456044560545606456074560845609456104561145612456134561445615456164561745618456194562045621456224562345624456254562645627456284562945630456314563245633456344563545636456374563845639456404564145642456434564445645456464564745648456494565045651456524565345654456554565645657456584565945660456614566245663456644566545666456674566845669456704567145672456734567445675456764567745678456794568045681456824568345684456854568645687456884568945690456914569245693456944569545696456974569845699457004570145702457034570445705457064570745708457094571045711457124571345714457154571645717457184571945720457214572245723457244572545726457274572845729457304573145732457334573445735457364573745738457394574045741457424574345744457454574645747457484574945750457514575245753457544575545756457574575845759457604576145762457634576445765457664576745768457694577045771457724577345774457754577645777457784577945780457814578245783457844578545786457874578845789457904579145792457934579445795457964579745798457994580045801458024580345804458054580645807458084580945810458114581245813458144581545816458174581845819458204582145822458234582445825458264582745828458294583045831458324583345834458354583645837458384583945840458414584245843458444584545846458474584845849458504585145852458534585445855458564585745858458594586045861458624586345864458654586645867458684586945870458714587245873458744587545876458774587845879458804588145882458834588445885458864588745888458894589045891458924589345894458954589645897458984589945900459014590245903459044590545906459074590845909459104591145912459134591445915459164591745918459194592045921459224592345924459254592645927459284592945930459314593245933459344593545936459374593845939459404594145942459434594445945459464594745948459494595045951459524595345954459554595645957459584595945960459614596245963459644596545966459674596845969459704597145972459734597445975459764597745978459794598045981459824598345984459854598645987459884598945990459914599245993459944599545996459974599845999460004600146002460034600446005460064600746008460094601046011460124601346014460154601646017460184601946020460214602246023460244602546026460274602846029460304603146032460334603446035460364603746038460394604046041460424604346044460454604646047460484604946050460514605246053460544605546056460574605846059460604606146062460634606446065460664606746068460694607046071460724607346074460754607646077460784607946080460814608246083460844608546086460874608846089460904609146092460934609446095460964609746098460994610046101461024610346104461054610646107461084610946110461114611246113461144611546116461174611846119461204612146122461234612446125461264612746128461294613046131461324613346134461354613646137461384613946140461414614246143461444614546146461474614846149461504615146152461534615446155461564615746158461594616046161461624616346164461654616646167461684616946170461714617246173461744617546176461774617846179461804618146182461834618446185461864618746188461894619046191461924619346194461954619646197461984619946200462014620246203462044620546206462074620846209462104621146212462134621446215462164621746218462194622046221462224622346224462254622646227462284622946230462314623246233462344623546236462374623846239462404624146242462434624446245462464624746248462494625046251462524625346254462554625646257462584625946260462614626246263462644626546266462674626846269462704627146272462734627446275462764627746278462794628046281462824628346284462854628646287462884628946290462914629246293462944629546296462974629846299463004630146302463034630446305463064630746308463094631046311463124631346314463154631646317463184631946320463214632246323463244632546326463274632846329463304633146332463334633446335463364633746338463394634046341463424634346344463454634646347463484634946350463514635246353463544635546356463574635846359463604636146362463634636446365463664636746368463694637046371463724637346374463754637646377463784637946380463814638246383463844638546386463874638846389463904639146392463934639446395463964639746398463994640046401464024640346404464054640646407464084640946410464114641246413464144641546416464174641846419464204642146422464234642446425464264642746428464294643046431464324643346434464354643646437464384643946440464414644246443464444644546446464474644846449464504645146452464534645446455464564645746458464594646046461464624646346464464654646646467464684646946470464714647246473464744647546476464774647846479464804648146482464834648446485464864648746488464894649046491464924649346494464954649646497464984649946500465014650246503465044650546506465074650846509465104651146512465134651446515465164651746518465194652046521465224652346524465254652646527465284652946530465314653246533465344653546536465374653846539465404654146542465434654446545465464654746548465494655046551465524655346554465554655646557465584655946560465614656246563465644656546566465674656846569465704657146572465734657446575465764657746578465794658046581465824658346584465854658646587465884658946590465914659246593465944659546596465974659846599466004660146602466034660446605466064660746608466094661046611466124661346614466154661646617466184661946620466214662246623466244662546626466274662846629466304663146632466334663446635466364663746638466394664046641466424664346644466454664646647466484664946650466514665246653466544665546656466574665846659466604666146662466634666446665466664666746668466694667046671466724667346674466754667646677466784667946680466814668246683466844668546686466874668846689466904669146692466934669446695466964669746698466994670046701467024670346704467054670646707467084670946710467114671246713467144671546716467174671846719467204672146722467234672446725467264672746728467294673046731467324673346734467354673646737467384673946740467414674246743467444674546746467474674846749467504675146752467534675446755467564675746758467594676046761467624676346764467654676646767467684676946770467714677246773467744677546776467774677846779467804678146782467834678446785467864678746788467894679046791467924679346794467954679646797467984679946800468014680246803468044680546806468074680846809468104681146812468134681446815468164681746818468194682046821468224682346824468254682646827468284682946830468314683246833468344683546836468374683846839468404684146842468434684446845468464684746848468494685046851468524685346854468554685646857468584685946860468614686246863468644686546866468674686846869468704687146872468734687446875468764687746878468794688046881468824688346884468854688646887468884688946890468914689246893468944689546896468974689846899469004690146902469034690446905469064690746908469094691046911469124691346914469154691646917469184691946920469214692246923469244692546926469274692846929469304693146932469334693446935469364693746938469394694046941469424694346944469454694646947469484694946950469514695246953469544695546956469574695846959469604696146962469634696446965469664696746968469694697046971469724697346974469754697646977469784697946980469814698246983469844698546986469874698846989469904699146992469934699446995469964699746998469994700047001470024700347004470054700647007470084700947010470114701247013470144701547016470174701847019470204702147022470234702447025470264702747028470294703047031470324703347034470354703647037470384703947040470414704247043470444704547046470474704847049470504705147052470534705447055470564705747058470594706047061470624706347064470654706647067470684706947070470714707247073470744707547076470774707847079470804708147082470834708447085470864708747088470894709047091470924709347094470954709647097470984709947100471014710247103471044710547106471074710847109471104711147112471134711447115471164711747118471194712047121471224712347124471254712647127471284712947130471314713247133471344713547136471374713847139471404714147142471434714447145471464714747148471494715047151471524715347154471554715647157471584715947160471614716247163471644716547166471674716847169471704717147172471734717447175471764717747178471794718047181471824718347184471854718647187471884718947190471914719247193471944719547196471974719847199472004720147202472034720447205472064720747208472094721047211472124721347214472154721647217472184721947220472214722247223472244722547226472274722847229472304723147232472334723447235472364723747238472394724047241472424724347244472454724647247472484724947250472514725247253472544725547256472574725847259472604726147262472634726447265472664726747268472694727047271472724727347274472754727647277472784727947280472814728247283472844728547286472874728847289472904729147292472934729447295472964729747298472994730047301473024730347304473054730647307473084730947310473114731247313473144731547316473174731847319473204732147322473234732447325473264732747328473294733047331473324733347334473354733647337473384733947340473414734247343473444734547346473474734847349473504735147352473534735447355473564735747358473594736047361473624736347364473654736647367473684736947370473714737247373473744737547376473774737847379473804738147382473834738447385473864738747388473894739047391473924739347394473954739647397473984739947400474014740247403474044740547406474074740847409474104741147412474134741447415474164741747418474194742047421474224742347424474254742647427474284742947430474314743247433474344743547436474374743847439474404744147442474434744447445474464744747448474494745047451474524745347454474554745647457474584745947460474614746247463474644746547466474674746847469474704747147472474734747447475474764747747478474794748047481474824748347484474854748647487474884748947490474914749247493474944749547496474974749847499475004750147502475034750447505475064750747508475094751047511475124751347514475154751647517475184751947520475214752247523475244752547526475274752847529475304753147532475334753447535475364753747538475394754047541475424754347544475454754647547475484754947550475514755247553475544755547556475574755847559475604756147562475634756447565475664756747568475694757047571475724757347574475754757647577475784757947580475814758247583475844758547586475874758847589475904759147592475934759447595475964759747598475994760047601476024760347604476054760647607476084760947610476114761247613476144761547616476174761847619476204762147622476234762447625476264762747628476294763047631476324763347634476354763647637476384763947640476414764247643476444764547646476474764847649476504765147652476534765447655476564765747658476594766047661476624766347664476654766647667476684766947670476714767247673476744767547676476774767847679476804768147682476834768447685476864768747688476894769047691476924769347694476954769647697476984769947700477014770247703477044770547706477074770847709477104771147712477134771447715477164771747718477194772047721477224772347724477254772647727477284772947730477314773247733477344773547736477374773847739477404774147742477434774447745477464774747748477494775047751477524775347754477554775647757477584775947760477614776247763477644776547766477674776847769477704777147772477734777447775477764777747778477794778047781477824778347784477854778647787477884778947790477914779247793477944779547796477974779847799478004780147802478034780447805478064780747808478094781047811478124781347814478154781647817478184781947820478214782247823478244782547826478274782847829478304783147832478334783447835478364783747838478394784047841478424784347844478454784647847478484784947850478514785247853478544785547856478574785847859478604786147862478634786447865478664786747868478694787047871478724787347874478754787647877478784787947880478814788247883478844788547886478874788847889478904789147892478934789447895478964789747898478994790047901479024790347904479054790647907479084790947910479114791247913479144791547916479174791847919479204792147922479234792447925479264792747928479294793047931479324793347934479354793647937479384793947940479414794247943479444794547946479474794847949479504795147952479534795447955479564795747958479594796047961479624796347964479654796647967479684796947970479714797247973479744797547976479774797847979479804798147982479834798447985479864798747988479894799047991479924799347994479954799647997479984799948000480014800248003480044800548006480074800848009480104801148012480134801448015480164801748018480194802048021480224802348024480254802648027480284802948030480314803248033480344803548036480374803848039480404804148042480434804448045480464804748048480494805048051480524805348054480554805648057480584805948060480614806248063480644806548066480674806848069480704807148072480734807448075480764807748078480794808048081480824808348084480854808648087480884808948090480914809248093480944809548096480974809848099481004810148102481034810448105481064810748108481094811048111481124811348114481154811648117481184811948120481214812248123481244812548126481274812848129481304813148132481334813448135481364813748138481394814048141481424814348144481454814648147481484814948150481514815248153481544815548156481574815848159481604816148162481634816448165481664816748168481694817048171481724817348174481754817648177481784817948180481814818248183481844818548186481874818848189481904819148192481934819448195481964819748198481994820048201482024820348204482054820648207482084820948210482114821248213482144821548216482174821848219482204822148222482234822448225482264822748228482294823048231482324823348234482354823648237482384823948240482414824248243482444824548246482474824848249482504825148252482534825448255482564825748258482594826048261482624826348264482654826648267482684826948270482714827248273482744827548276482774827848279482804828148282482834828448285482864828748288482894829048291482924829348294482954829648297482984829948300483014830248303483044830548306483074830848309483104831148312483134831448315483164831748318483194832048321483224832348324483254832648327483284832948330483314833248333483344833548336483374833848339483404834148342483434834448345483464834748348483494835048351483524835348354483554835648357483584835948360483614836248363483644836548366483674836848369483704837148372483734837448375483764837748378483794838048381483824838348384483854838648387483884838948390483914839248393483944839548396483974839848399484004840148402484034840448405484064840748408484094841048411484124841348414484154841648417484184841948420484214842248423484244842548426484274842848429484304843148432484334843448435484364843748438484394844048441484424844348444484454844648447484484844948450484514845248453484544845548456484574845848459484604846148462484634846448465484664846748468484694847048471484724847348474484754847648477484784847948480484814848248483484844848548486484874848848489484904849148492484934849448495484964849748498484994850048501485024850348504485054850648507485084850948510485114851248513485144851548516485174851848519485204852148522485234852448525485264852748528485294853048531485324853348534485354853648537485384853948540485414854248543485444854548546485474854848549485504855148552485534855448555485564855748558485594856048561485624856348564485654856648567485684856948570485714857248573485744857548576485774857848579485804858148582485834858448585485864858748588485894859048591485924859348594485954859648597485984859948600486014860248603486044860548606486074860848609486104861148612486134861448615486164861748618486194862048621486224862348624486254862648627486284862948630486314863248633486344863548636486374863848639486404864148642486434864448645486464864748648486494865048651486524865348654486554865648657486584865948660486614866248663486644866548666486674866848669486704867148672486734867448675486764867748678486794868048681486824868348684486854868648687486884868948690486914869248693486944869548696486974869848699487004870148702487034870448705487064870748708487094871048711487124871348714487154871648717487184871948720487214872248723487244872548726487274872848729487304873148732487334873448735487364873748738487394874048741487424874348744487454874648747487484874948750487514875248753487544875548756487574875848759487604876148762487634876448765487664876748768487694877048771487724877348774487754877648777487784877948780487814878248783487844878548786487874878848789487904879148792487934879448795487964879748798487994880048801488024880348804488054880648807488084880948810488114881248813488144881548816488174881848819488204882148822488234882448825488264882748828488294883048831488324883348834488354883648837488384883948840488414884248843488444884548846488474884848849488504885148852488534885448855488564885748858488594886048861488624886348864488654886648867488684886948870488714887248873488744887548876488774887848879488804888148882488834888448885488864888748888488894889048891488924889348894488954889648897488984889948900489014890248903489044890548906489074890848909489104891148912489134891448915489164891748918489194892048921489224892348924489254892648927489284892948930489314893248933489344893548936489374893848939489404894148942489434894448945489464894748948489494895048951489524895348954489554895648957489584895948960489614896248963489644896548966489674896848969489704897148972489734897448975489764897748978489794898048981489824898348984489854898648987489884898948990489914899248993489944899548996489974899848999490004900149002490034900449005490064900749008490094901049011490124901349014490154901649017490184901949020490214902249023490244902549026490274902849029490304903149032490334903449035490364903749038490394904049041490424904349044490454904649047490484904949050490514905249053490544905549056490574905849059490604906149062490634906449065490664906749068490694907049071490724907349074490754907649077490784907949080490814908249083490844908549086490874908849089490904909149092490934909449095490964909749098490994910049101491024910349104491054910649107491084910949110491114911249113491144911549116491174911849119491204912149122491234912449125491264912749128491294913049131491324913349134491354913649137491384913949140491414914249143491444914549146491474914849149491504915149152491534915449155491564915749158491594916049161491624916349164491654916649167491684916949170491714917249173491744917549176491774917849179491804918149182491834918449185491864918749188491894919049191491924919349194491954919649197491984919949200492014920249203492044920549206492074920849209492104921149212492134921449215492164921749218492194922049221492224922349224492254922649227492284922949230492314923249233492344923549236492374923849239492404924149242492434924449245492464924749248492494925049251492524925349254492554925649257492584925949260492614926249263492644926549266492674926849269492704927149272492734927449275492764927749278492794928049281492824928349284492854928649287492884928949290492914929249293492944929549296492974929849299493004930149302493034930449305493064930749308493094931049311493124931349314493154931649317493184931949320493214932249323493244932549326493274932849329493304933149332493334933449335493364933749338493394934049341493424934349344493454934649347493484934949350493514935249353493544935549356493574935849359493604936149362493634936449365493664936749368493694937049371493724937349374493754937649377493784937949380493814938249383493844938549386493874938849389493904939149392493934939449395493964939749398493994940049401494024940349404494054940649407494084940949410494114941249413494144941549416494174941849419494204942149422494234942449425494264942749428494294943049431494324943349434494354943649437494384943949440494414944249443494444944549446494474944849449494504945149452494534945449455494564945749458494594946049461494624946349464494654946649467494684946949470494714947249473494744947549476494774947849479494804948149482494834948449485494864948749488494894949049491494924949349494494954949649497494984949949500495014950249503495044950549506495074950849509495104951149512495134951449515495164951749518495194952049521495224952349524495254952649527495284952949530495314953249533495344953549536495374953849539495404954149542495434954449545495464954749548495494955049551495524955349554495554955649557495584955949560495614956249563495644956549566495674956849569495704957149572495734957449575495764957749578495794958049581495824958349584495854958649587495884958949590495914959249593495944959549596495974959849599496004960149602496034960449605496064960749608496094961049611496124961349614496154961649617496184961949620496214962249623496244962549626496274962849629496304963149632496334963449635496364963749638496394964049641496424964349644496454964649647496484964949650496514965249653496544965549656496574965849659496604966149662496634966449665496664966749668496694967049671496724967349674496754967649677496784967949680496814968249683496844968549686496874968849689496904969149692496934969449695496964969749698496994970049701497024970349704497054970649707497084970949710497114971249713497144971549716497174971849719497204972149722497234972449725497264972749728497294973049731497324973349734497354973649737497384973949740497414974249743497444974549746497474974849749497504975149752497534975449755497564975749758497594976049761497624976349764497654976649767497684976949770497714977249773497744977549776497774977849779497804978149782497834978449785497864978749788497894979049791497924979349794497954979649797497984979949800498014980249803498044980549806498074980849809498104981149812498134981449815498164981749818498194982049821498224982349824498254982649827498284982949830498314983249833498344983549836498374983849839498404984149842498434984449845498464984749848498494985049851498524985349854498554985649857498584985949860498614986249863498644986549866498674986849869498704987149872498734987449875498764987749878498794988049881498824988349884498854988649887498884988949890498914989249893498944989549896498974989849899499004990149902499034990449905499064990749908499094991049911499124991349914499154991649917499184991949920499214992249923499244992549926499274992849929499304993149932499334993449935499364993749938499394994049941499424994349944499454994649947499484994949950499514995249953499544995549956499574995849959499604996149962499634996449965499664996749968499694997049971499724997349974499754997649977499784997949980499814998249983499844998549986499874998849989499904999149992499934999449995499964999749998499995000050001500025000350004500055000650007500085000950010500115001250013500145001550016500175001850019500205002150022500235002450025500265002750028500295003050031500325003350034500355003650037500385003950040500415004250043500445004550046500475004850049500505005150052500535005450055500565005750058500595006050061500625006350064500655006650067500685006950070500715007250073500745007550076500775007850079500805008150082500835008450085500865008750088500895009050091500925009350094500955009650097500985009950100501015010250103501045010550106501075010850109501105011150112501135011450115501165011750118501195012050121501225012350124501255012650127501285012950130501315013250133501345013550136501375013850139501405014150142501435014450145501465014750148501495015050151501525015350154501555015650157501585015950160501615016250163501645016550166501675016850169501705017150172501735017450175501765017750178501795018050181501825018350184501855018650187501885018950190501915019250193501945019550196501975019850199502005020150202502035020450205502065020750208502095021050211502125021350214502155021650217502185021950220502215022250223502245022550226502275022850229502305023150232502335023450235502365023750238502395024050241502425024350244502455024650247502485024950250502515025250253502545025550256502575025850259502605026150262502635026450265502665026750268502695027050271502725027350274502755027650277502785027950280502815028250283502845028550286502875028850289502905029150292502935029450295502965029750298502995030050301503025030350304503055030650307503085030950310503115031250313503145031550316503175031850319503205032150322503235032450325503265032750328503295033050331503325033350334503355033650337503385033950340503415034250343503445034550346503475034850349503505035150352503535035450355503565035750358503595036050361503625036350364503655036650367503685036950370503715037250373503745037550376503775037850379503805038150382503835038450385503865038750388503895039050391503925039350394503955039650397503985039950400504015040250403504045040550406504075040850409504105041150412504135041450415504165041750418504195042050421504225042350424504255042650427504285042950430504315043250433504345043550436504375043850439504405044150442504435044450445504465044750448504495045050451504525045350454504555045650457504585045950460504615046250463504645046550466504675046850469504705047150472504735047450475504765047750478504795048050481504825048350484504855048650487504885048950490504915049250493504945049550496504975049850499505005050150502505035050450505505065050750508505095051050511505125051350514505155051650517505185051950520505215052250523505245052550526505275052850529505305053150532505335053450535505365053750538505395054050541505425054350544505455054650547505485054950550505515055250553505545055550556505575055850559505605056150562505635056450565505665056750568505695057050571505725057350574505755057650577505785057950580505815058250583505845058550586505875058850589505905059150592505935059450595505965059750598505995060050601506025060350604506055060650607506085060950610506115061250613506145061550616506175061850619506205062150622506235062450625506265062750628506295063050631506325063350634506355063650637506385063950640506415064250643506445064550646506475064850649506505065150652506535065450655506565065750658506595066050661506625066350664506655066650667506685066950670506715067250673506745067550676506775067850679506805068150682506835068450685506865068750688506895069050691506925069350694506955069650697506985069950700507015070250703507045070550706507075070850709507105071150712507135071450715507165071750718507195072050721507225072350724507255072650727507285072950730507315073250733507345073550736507375073850739507405074150742507435074450745507465074750748507495075050751507525075350754507555075650757507585075950760507615076250763507645076550766507675076850769507705077150772507735077450775507765077750778507795078050781507825078350784507855078650787507885078950790507915079250793507945079550796507975079850799508005080150802508035080450805508065080750808508095081050811508125081350814508155081650817508185081950820508215082250823508245082550826508275082850829508305083150832508335083450835508365083750838508395084050841508425084350844508455084650847508485084950850508515085250853508545085550856508575085850859508605086150862508635086450865508665086750868508695087050871508725087350874508755087650877508785087950880508815088250883508845088550886508875088850889508905089150892508935089450895508965089750898508995090050901509025090350904509055090650907509085090950910509115091250913509145091550916509175091850919509205092150922509235092450925509265092750928509295093050931509325093350934509355093650937509385093950940509415094250943509445094550946509475094850949509505095150952509535095450955509565095750958509595096050961509625096350964509655096650967509685096950970509715097250973509745097550976509775097850979509805098150982509835098450985509865098750988509895099050991509925099350994509955099650997509985099951000510015100251003510045100551006510075100851009510105101151012510135101451015510165101751018510195102051021510225102351024510255102651027510285102951030510315103251033510345103551036510375103851039510405104151042510435104451045510465104751048510495105051051510525105351054510555105651057510585105951060510615106251063510645106551066510675106851069510705107151072510735107451075510765107751078510795108051081510825108351084510855108651087510885108951090510915109251093510945109551096510975109851099511005110151102511035110451105511065110751108511095111051111511125111351114511155111651117511185111951120511215112251123511245112551126511275112851129511305113151132511335113451135511365113751138511395114051141511425114351144511455114651147511485114951150511515115251153511545115551156511575115851159511605116151162511635116451165511665116751168511695117051171511725117351174511755117651177511785117951180511815118251183511845118551186511875118851189511905119151192511935119451195511965119751198511995120051201512025120351204512055120651207512085120951210512115121251213512145121551216512175121851219512205122151222512235122451225512265122751228512295123051231512325123351234512355123651237512385123951240512415124251243512445124551246512475124851249512505125151252512535125451255512565125751258512595126051261512625126351264512655126651267512685126951270512715127251273512745127551276512775127851279512805128151282512835128451285512865128751288512895129051291512925129351294512955129651297512985129951300513015130251303513045130551306513075130851309513105131151312513135131451315513165131751318513195132051321513225132351324513255132651327513285132951330513315133251333513345133551336513375133851339513405134151342513435134451345513465134751348513495135051351513525135351354513555135651357513585135951360513615136251363513645136551366513675136851369513705137151372513735137451375513765137751378513795138051381513825138351384513855138651387513885138951390513915139251393513945139551396513975139851399514005140151402514035140451405514065140751408514095141051411514125141351414514155141651417514185141951420514215142251423514245142551426514275142851429514305143151432514335143451435514365143751438514395144051441514425144351444514455144651447514485144951450514515145251453514545145551456514575145851459514605146151462514635146451465514665146751468514695147051471514725147351474514755147651477514785147951480514815148251483514845148551486514875148851489514905149151492514935149451495514965149751498514995150051501515025150351504515055150651507515085150951510515115151251513515145151551516515175151851519515205152151522515235152451525515265152751528515295153051531515325153351534515355153651537515385153951540515415154251543515445154551546515475154851549515505155151552515535155451555515565155751558515595156051561515625156351564515655156651567515685156951570515715157251573515745157551576515775157851579515805158151582515835158451585515865158751588515895159051591515925159351594515955159651597515985159951600516015160251603516045160551606516075160851609516105161151612516135161451615516165161751618516195162051621516225162351624516255162651627516285162951630516315163251633516345163551636516375163851639516405164151642516435164451645516465164751648516495165051651516525165351654516555165651657516585165951660516615166251663516645166551666516675166851669516705167151672516735167451675516765167751678516795168051681516825168351684516855168651687516885168951690516915169251693516945169551696516975169851699517005170151702517035170451705517065170751708517095171051711517125171351714517155171651717517185171951720517215172251723517245172551726517275172851729517305173151732517335173451735517365173751738517395174051741517425174351744517455174651747517485174951750517515175251753517545175551756517575175851759517605176151762517635176451765517665176751768517695177051771517725177351774517755177651777517785177951780517815178251783517845178551786517875178851789517905179151792517935179451795517965179751798517995180051801518025180351804518055180651807518085180951810518115181251813518145181551816518175181851819518205182151822518235182451825518265182751828518295183051831518325183351834518355183651837518385183951840518415184251843518445184551846518475184851849518505185151852518535185451855518565185751858518595186051861518625186351864518655186651867518685186951870518715187251873518745187551876518775187851879518805188151882518835188451885518865188751888518895189051891518925189351894518955189651897518985189951900519015190251903519045190551906519075190851909519105191151912519135191451915519165191751918519195192051921519225192351924519255192651927519285192951930519315193251933519345193551936519375193851939519405194151942519435194451945519465194751948519495195051951519525195351954519555195651957519585195951960519615196251963519645196551966519675196851969519705197151972519735197451975519765197751978519795198051981519825198351984519855198651987519885198951990519915199251993519945199551996519975199851999520005200152002520035200452005520065200752008520095201052011520125201352014520155201652017520185201952020520215202252023520245202552026520275202852029520305203152032520335203452035520365203752038520395204052041520425204352044520455204652047520485204952050520515205252053520545205552056520575205852059520605206152062520635206452065520665206752068520695207052071520725207352074520755207652077520785207952080520815208252083520845208552086520875208852089520905209152092520935209452095520965209752098520995210052101521025210352104521055210652107521085210952110521115211252113521145211552116521175211852119521205212152122521235212452125521265212752128521295213052131521325213352134521355213652137521385213952140521415214252143521445214552146521475214852149521505215152152521535215452155521565215752158521595216052161521625216352164521655216652167521685216952170521715217252173521745217552176521775217852179521805218152182521835218452185521865218752188521895219052191521925219352194521955219652197521985219952200522015220252203522045220552206522075220852209522105221152212522135221452215522165221752218522195222052221522225222352224522255222652227522285222952230522315223252233522345223552236522375223852239522405224152242522435224452245522465224752248522495225052251522525225352254522555225652257522585225952260522615226252263522645226552266522675226852269522705227152272522735227452275522765227752278522795228052281522825228352284522855228652287522885228952290522915229252293522945229552296522975229852299523005230152302523035230452305523065230752308523095231052311523125231352314523155231652317523185231952320523215232252323523245232552326523275232852329523305233152332523335233452335523365233752338523395234052341523425234352344523455234652347523485234952350523515235252353523545235552356523575235852359523605236152362523635236452365523665236752368523695237052371523725237352374523755237652377523785237952380523815238252383523845238552386523875238852389523905239152392523935239452395523965239752398523995240052401524025240352404524055240652407524085240952410524115241252413524145241552416524175241852419524205242152422524235242452425524265242752428524295243052431524325243352434524355243652437524385243952440524415244252443524445244552446524475244852449524505245152452524535245452455524565245752458524595246052461524625246352464524655246652467524685246952470524715247252473524745247552476524775247852479524805248152482524835248452485524865248752488524895249052491524925249352494524955249652497524985249952500525015250252503525045250552506525075250852509525105251152512525135251452515525165251752518525195252052521525225252352524525255252652527525285252952530525315253252533525345253552536525375253852539525405254152542525435254452545525465254752548525495255052551525525255352554525555255652557525585255952560525615256252563525645256552566525675256852569525705257152572525735257452575525765257752578525795258052581525825258352584525855258652587525885258952590525915259252593525945259552596525975259852599526005260152602526035260452605526065260752608526095261052611526125261352614526155261652617526185261952620526215262252623526245262552626526275262852629526305263152632526335263452635526365263752638526395264052641526425264352644526455264652647526485264952650526515265252653526545265552656526575265852659526605266152662526635266452665526665266752668526695267052671526725267352674526755267652677526785267952680526815268252683526845268552686526875268852689526905269152692526935269452695526965269752698526995270052701527025270352704527055270652707527085270952710527115271252713527145271552716527175271852719527205272152722527235272452725527265272752728527295273052731527325273352734527355273652737527385273952740527415274252743527445274552746527475274852749527505275152752527535275452755527565275752758527595276052761527625276352764527655276652767527685276952770527715277252773527745277552776527775277852779527805278152782527835278452785527865278752788527895279052791527925279352794527955279652797527985279952800528015280252803528045280552806528075280852809528105281152812528135281452815528165281752818528195282052821528225282352824528255282652827528285282952830528315283252833528345283552836528375283852839528405284152842528435284452845528465284752848528495285052851528525285352854528555285652857528585285952860528615286252863528645286552866528675286852869528705287152872528735287452875528765287752878528795288052881528825288352884528855288652887528885288952890528915289252893528945289552896528975289852899529005290152902529035290452905529065290752908529095291052911529125291352914529155291652917529185291952920529215292252923529245292552926529275292852929529305293152932529335293452935529365293752938529395294052941529425294352944529455294652947529485294952950529515295252953529545295552956529575295852959529605296152962529635296452965529665296752968529695297052971529725297352974529755297652977529785297952980529815298252983529845298552986529875298852989529905299152992529935299452995529965299752998529995300053001530025300353004530055300653007530085300953010530115301253013530145301553016530175301853019530205302153022530235302453025530265302753028530295303053031530325303353034530355303653037530385303953040530415304253043530445304553046530475304853049530505305153052530535305453055530565305753058530595306053061530625306353064530655306653067530685306953070530715307253073530745307553076530775307853079530805308153082530835308453085530865308753088530895309053091530925309353094530955309653097530985309953100531015310253103531045310553106531075310853109531105311153112531135311453115531165311753118531195312053121531225312353124531255312653127531285312953130531315313253133531345313553136531375313853139531405314153142531435314453145531465314753148531495315053151531525315353154531555315653157531585315953160531615316253163531645316553166531675316853169531705317153172531735317453175531765317753178531795318053181531825318353184531855318653187531885318953190531915319253193531945319553196531975319853199532005320153202532035320453205532065320753208532095321053211532125321353214532155321653217532185321953220532215322253223532245322553226532275322853229532305323153232532335323453235532365323753238532395324053241532425324353244532455324653247532485324953250532515325253253532545325553256532575325853259532605326153262532635326453265532665326753268532695327053271532725327353274532755327653277532785327953280532815328253283532845328553286532875328853289532905329153292532935329453295532965329753298532995330053301533025330353304533055330653307533085330953310533115331253313533145331553316533175331853319533205332153322533235332453325533265332753328533295333053331533325333353334533355333653337533385333953340533415334253343533445334553346533475334853349533505335153352533535335453355533565335753358533595336053361533625336353364533655336653367533685336953370533715337253373533745337553376533775337853379533805338153382533835338453385533865338753388533895339053391533925339353394533955339653397533985339953400534015340253403534045340553406534075340853409534105341153412534135341453415534165341753418534195342053421534225342353424534255342653427534285342953430534315343253433534345343553436534375343853439534405344153442534435344453445534465344753448534495345053451534525345353454534555345653457534585345953460534615346253463534645346553466534675346853469534705347153472534735347453475534765347753478534795348053481534825348353484534855348653487534885348953490534915349253493534945349553496534975349853499535005350153502535035350453505535065350753508535095351053511535125351353514535155351653517535185351953520535215352253523535245352553526535275352853529535305353153532535335353453535535365353753538535395354053541535425354353544535455354653547535485354953550535515355253553535545355553556535575355853559535605356153562535635356453565535665356753568535695357053571535725357353574535755357653577535785357953580535815358253583535845358553586535875358853589535905359153592535935359453595535965359753598535995360053601536025360353604536055360653607536085360953610536115361253613536145361553616536175361853619536205362153622536235362453625536265362753628536295363053631536325363353634536355363653637536385363953640536415364253643536445364553646536475364853649536505365153652536535365453655536565365753658536595366053661536625366353664536655366653667536685366953670536715367253673536745367553676536775367853679536805368153682536835368453685536865368753688536895369053691536925369353694536955369653697536985369953700537015370253703537045370553706537075370853709537105371153712537135371453715537165371753718537195372053721537225372353724537255372653727537285372953730537315373253733537345373553736537375373853739537405374153742537435374453745537465374753748537495375053751537525375353754537555375653757537585375953760537615376253763537645376553766537675376853769537705377153772537735377453775537765377753778537795378053781537825378353784537855378653787537885378953790537915379253793537945379553796537975379853799538005380153802538035380453805538065380753808538095381053811538125381353814538155381653817538185381953820538215382253823538245382553826538275382853829538305383153832538335383453835538365383753838538395384053841538425384353844538455384653847538485384953850538515385253853538545385553856538575385853859538605386153862538635386453865538665386753868538695387053871538725387353874538755387653877538785387953880538815388253883538845388553886538875388853889538905389153892538935389453895538965389753898538995390053901539025390353904539055390653907539085390953910539115391253913539145391553916539175391853919539205392153922539235392453925539265392753928539295393053931539325393353934539355393653937539385393953940539415394253943539445394553946539475394853949539505395153952539535395453955539565395753958539595396053961539625396353964539655396653967539685396953970539715397253973539745397553976539775397853979539805398153982539835398453985539865398753988539895399053991539925399353994539955399653997539985399954000540015400254003540045400554006540075400854009540105401154012540135401454015540165401754018540195402054021540225402354024540255402654027540285402954030540315403254033540345403554036540375403854039540405404154042540435404454045540465404754048540495405054051540525405354054540555405654057540585405954060540615406254063540645406554066540675406854069540705407154072540735407454075540765407754078540795408054081540825408354084540855408654087540885408954090540915409254093540945409554096540975409854099541005410154102541035410454105541065410754108541095411054111541125411354114541155411654117541185411954120541215412254123541245412554126541275412854129541305413154132541335413454135541365413754138541395414054141541425414354144541455414654147541485414954150541515415254153541545415554156541575415854159541605416154162541635416454165541665416754168541695417054171541725417354174541755417654177541785417954180541815418254183541845418554186541875418854189541905419154192541935419454195541965419754198541995420054201542025420354204542055420654207542085420954210542115421254213542145421554216542175421854219542205422154222542235422454225542265422754228542295423054231542325423354234542355423654237542385423954240542415424254243542445424554246542475424854249542505425154252542535425454255542565425754258542595426054261542625426354264542655426654267542685426954270542715427254273542745427554276542775427854279542805428154282542835428454285542865428754288542895429054291542925429354294542955429654297542985429954300543015430254303543045430554306543075430854309543105431154312543135431454315543165431754318543195432054321543225432354324543255432654327543285432954330543315433254333543345433554336543375433854339543405434154342543435434454345543465434754348543495435054351543525435354354543555435654357543585435954360543615436254363543645436554366543675436854369543705437154372543735437454375543765437754378543795438054381543825438354384543855438654387543885438954390543915439254393543945439554396543975439854399544005440154402544035440454405544065440754408544095441054411544125441354414544155441654417544185441954420544215442254423544245442554426544275442854429544305443154432544335443454435544365443754438544395444054441544425444354444544455444654447544485444954450544515445254453544545445554456544575445854459544605446154462544635446454465544665446754468544695447054471544725447354474544755447654477544785447954480544815448254483544845448554486544875448854489544905449154492544935449454495544965449754498544995450054501545025450354504545055450654507545085450954510545115451254513545145451554516545175451854519545205452154522545235452454525545265452754528545295453054531545325453354534545355453654537545385453954540545415454254543545445454554546545475454854549545505455154552545535455454555545565455754558545595456054561545625456354564545655456654567545685456954570545715457254573545745457554576545775457854579545805458154582545835458454585545865458754588545895459054591545925459354594545955459654597545985459954600546015460254603546045460554606546075460854609546105461154612546135461454615546165461754618546195462054621546225462354624546255462654627546285462954630546315463254633546345463554636546375463854639546405464154642546435464454645546465464754648546495465054651546525465354654546555465654657546585465954660546615466254663546645466554666546675466854669546705467154672546735467454675546765467754678546795468054681546825468354684546855468654687546885468954690546915469254693546945469554696546975469854699547005470154702547035470454705547065470754708547095471054711547125471354714547155471654717547185471954720547215472254723547245472554726547275472854729547305473154732547335473454735547365473754738547395474054741547425474354744547455474654747547485474954750547515475254753547545475554756547575475854759547605476154762547635476454765547665476754768547695477054771547725477354774547755477654777547785477954780547815478254783547845478554786547875478854789547905479154792547935479454795547965479754798547995480054801548025480354804548055480654807548085480954810548115481254813548145481554816548175481854819548205482154822548235482454825548265482754828548295483054831548325483354834548355483654837548385483954840548415484254843548445484554846548475484854849548505485154852548535485454855548565485754858548595486054861548625486354864548655486654867548685486954870548715487254873548745487554876548775487854879548805488154882548835488454885548865488754888548895489054891548925489354894548955489654897548985489954900549015490254903549045490554906549075490854909549105491154912549135491454915549165491754918549195492054921549225492354924549255492654927549285492954930549315493254933549345493554936549375493854939549405494154942549435494454945549465494754948549495495054951549525495354954549555495654957549585495954960549615496254963549645496554966549675496854969549705497154972549735497454975549765497754978549795498054981549825498354984549855498654987549885498954990549915499254993549945499554996549975499854999550005500155002550035500455005550065500755008550095501055011550125501355014550155501655017550185501955020550215502255023550245502555026550275502855029550305503155032550335503455035550365503755038550395504055041550425504355044550455504655047550485504955050550515505255053550545505555056550575505855059550605506155062550635506455065550665506755068550695507055071550725507355074550755507655077550785507955080550815508255083550845508555086550875508855089550905509155092550935509455095550965509755098550995510055101551025510355104551055510655107551085510955110551115511255113551145511555116551175511855119551205512155122551235512455125551265512755128551295513055131551325513355134551355513655137551385513955140551415514255143551445514555146551475514855149551505515155152551535515455155551565515755158551595516055161551625516355164551655516655167551685516955170551715517255173551745517555176551775517855179551805518155182551835518455185551865518755188551895519055191551925519355194551955519655197551985519955200552015520255203552045520555206552075520855209552105521155212552135521455215552165521755218552195522055221552225522355224552255522655227552285522955230552315523255233552345523555236552375523855239552405524155242552435524455245552465524755248552495525055251552525525355254552555525655257552585525955260552615526255263552645526555266552675526855269552705527155272552735527455275552765527755278552795528055281552825528355284552855528655287552885528955290552915529255293552945529555296552975529855299553005530155302553035530455305553065530755308553095531055311553125531355314553155531655317553185531955320553215532255323553245532555326553275532855329553305533155332553335533455335553365533755338553395534055341553425534355344553455534655347553485534955350553515535255353553545535555356553575535855359553605536155362553635536455365553665536755368553695537055371553725537355374553755537655377553785537955380553815538255383553845538555386553875538855389553905539155392553935539455395553965539755398553995540055401554025540355404554055540655407554085540955410554115541255413554145541555416554175541855419554205542155422554235542455425554265542755428554295543055431554325543355434554355543655437554385543955440554415544255443554445544555446554475544855449554505545155452554535545455455554565545755458554595546055461554625546355464554655546655467554685546955470554715547255473554745547555476554775547855479554805548155482554835548455485554865548755488554895549055491554925549355494554955549655497554985549955500555015550255503555045550555506555075550855509555105551155512555135551455515555165551755518555195552055521555225552355524555255552655527555285552955530555315553255533555345553555536555375553855539555405554155542555435554455545555465554755548555495555055551555525555355554555555555655557555585555955560555615556255563555645556555566555675556855569555705557155572555735557455575555765557755578555795558055581555825558355584555855558655587555885558955590555915559255593555945559555596555975559855599556005560155602556035560455605556065560755608556095561055611556125561355614556155561655617556185561955620556215562255623556245562555626556275562855629556305563155632556335563455635556365563755638556395564055641556425564355644556455564655647556485564955650556515565255653556545565555656556575565855659556605566155662556635566455665556665566755668556695567055671556725567355674556755567655677556785567955680556815568255683556845568555686556875568855689556905569155692556935569455695556965569755698556995570055701557025570355704557055570655707557085570955710557115571255713557145571555716557175571855719557205572155722557235572455725557265572755728557295573055731557325573355734557355573655737557385573955740557415574255743557445574555746557475574855749557505575155752557535575455755557565575755758557595576055761557625576355764557655576655767557685576955770557715577255773557745577555776557775577855779557805578155782557835578455785557865578755788557895579055791557925579355794557955579655797557985579955800558015580255803558045580555806558075580855809558105581155812558135581455815558165581755818558195582055821558225582355824558255582655827558285582955830558315583255833558345583555836558375583855839558405584155842558435584455845558465584755848558495585055851558525585355854558555585655857558585585955860558615586255863558645586555866558675586855869558705587155872558735587455875558765587755878558795588055881558825588355884558855588655887558885588955890558915589255893558945589555896558975589855899559005590155902559035590455905559065590755908559095591055911559125591355914559155591655917559185591955920559215592255923559245592555926559275592855929559305593155932559335593455935559365593755938559395594055941559425594355944559455594655947559485594955950559515595255953559545595555956559575595855959559605596155962559635596455965559665596755968559695597055971559725597355974559755597655977559785597955980559815598255983559845598555986559875598855989559905599155992559935599455995559965599755998559995600056001560025600356004560055600656007560085600956010560115601256013560145601556016560175601856019560205602156022560235602456025560265602756028560295603056031560325603356034560355603656037560385603956040560415604256043560445604556046560475604856049560505605156052560535605456055560565605756058560595606056061560625606356064560655606656067560685606956070560715607256073560745607556076560775607856079560805608156082560835608456085560865608756088560895609056091560925609356094560955609656097560985609956100561015610256103561045610556106561075610856109561105611156112561135611456115561165611756118561195612056121561225612356124561255612656127561285612956130561315613256133561345613556136561375613856139561405614156142561435614456145561465614756148561495615056151561525615356154561555615656157561585615956160561615616256163561645616556166561675616856169561705617156172561735617456175561765617756178561795618056181561825618356184561855618656187561885618956190561915619256193561945619556196561975619856199562005620156202562035620456205562065620756208562095621056211562125621356214562155621656217562185621956220562215622256223562245622556226562275622856229562305623156232562335623456235562365623756238562395624056241562425624356244562455624656247562485624956250562515625256253562545625556256562575625856259562605626156262562635626456265562665626756268562695627056271562725627356274562755627656277562785627956280562815628256283562845628556286562875628856289562905629156292562935629456295562965629756298562995630056301563025630356304563055630656307563085630956310563115631256313563145631556316563175631856319563205632156322563235632456325563265632756328563295633056331563325633356334563355633656337563385633956340563415634256343563445634556346563475634856349563505635156352563535635456355563565635756358563595636056361563625636356364563655636656367563685636956370563715637256373563745637556376563775637856379563805638156382563835638456385563865638756388563895639056391563925639356394563955639656397563985639956400564015640256403564045640556406564075640856409564105641156412564135641456415564165641756418564195642056421564225642356424564255642656427564285642956430564315643256433564345643556436564375643856439564405644156442564435644456445564465644756448564495645056451564525645356454564555645656457564585645956460564615646256463564645646556466564675646856469564705647156472564735647456475564765647756478564795648056481564825648356484564855648656487564885648956490564915649256493564945649556496564975649856499565005650156502565035650456505565065650756508565095651056511565125651356514565155651656517565185651956520565215652256523565245652556526565275652856529565305653156532565335653456535565365653756538565395654056541565425654356544565455654656547565485654956550565515655256553565545655556556565575655856559565605656156562565635656456565565665656756568565695657056571565725657356574565755657656577565785657956580565815658256583565845658556586565875658856589565905659156592565935659456595565965659756598565995660056601566025660356604566055660656607566085660956610566115661256613566145661556616566175661856619566205662156622566235662456625566265662756628566295663056631566325663356634566355663656637566385663956640566415664256643566445664556646566475664856649566505665156652566535665456655566565665756658566595666056661566625666356664566655666656667566685666956670566715667256673566745667556676566775667856679566805668156682566835668456685566865668756688566895669056691566925669356694566955669656697566985669956700567015670256703567045670556706567075670856709567105671156712567135671456715567165671756718567195672056721567225672356724567255672656727567285672956730567315673256733567345673556736567375673856739567405674156742567435674456745567465674756748567495675056751567525675356754567555675656757567585675956760567615676256763567645676556766567675676856769567705677156772567735677456775567765677756778567795678056781567825678356784567855678656787567885678956790567915679256793567945679556796567975679856799568005680156802568035680456805568065680756808568095681056811568125681356814568155681656817568185681956820568215682256823568245682556826568275682856829568305683156832568335683456835568365683756838568395684056841568425684356844568455684656847568485684956850568515685256853568545685556856568575685856859568605686156862568635686456865568665686756868568695687056871568725687356874568755687656877568785687956880568815688256883568845688556886568875688856889568905689156892568935689456895568965689756898568995690056901569025690356904569055690656907569085690956910569115691256913569145691556916569175691856919569205692156922569235692456925569265692756928569295693056931569325693356934569355693656937569385693956940569415694256943569445694556946569475694856949569505695156952569535695456955569565695756958569595696056961569625696356964569655696656967569685696956970569715697256973569745697556976569775697856979569805698156982569835698456985569865698756988569895699056991569925699356994569955699656997569985699957000570015700257003570045700557006570075700857009570105701157012570135701457015570165701757018570195702057021570225702357024570255702657027570285702957030570315703257033570345703557036570375703857039570405704157042570435704457045570465704757048570495705057051570525705357054570555705657057570585705957060570615706257063570645706557066570675706857069570705707157072570735707457075570765707757078570795708057081570825708357084570855708657087570885708957090570915709257093570945709557096570975709857099571005710157102571035710457105571065710757108571095711057111571125711357114571155711657117571185711957120571215712257123571245712557126571275712857129571305713157132571335713457135571365713757138571395714057141571425714357144571455714657147571485714957150571515715257153571545715557156571575715857159571605716157162571635716457165571665716757168571695717057171571725717357174571755717657177571785717957180571815718257183571845718557186571875718857189571905719157192571935719457195571965719757198571995720057201572025720357204572055720657207572085720957210572115721257213572145721557216572175721857219572205722157222572235722457225572265722757228572295723057231572325723357234572355723657237572385723957240572415724257243572445724557246572475724857249572505725157252572535725457255572565725757258572595726057261572625726357264572655726657267572685726957270572715727257273572745727557276572775727857279572805728157282572835728457285572865728757288572895729057291572925729357294572955729657297572985729957300573015730257303573045730557306573075730857309573105731157312573135731457315573165731757318573195732057321573225732357324573255732657327573285732957330573315733257333573345733557336573375733857339573405734157342573435734457345573465734757348573495735057351573525735357354573555735657357573585735957360573615736257363573645736557366573675736857369573705737157372573735737457375573765737757378573795738057381573825738357384573855738657387573885738957390573915739257393573945739557396573975739857399574005740157402574035740457405574065740757408574095741057411574125741357414574155741657417574185741957420574215742257423574245742557426574275742857429574305743157432574335743457435574365743757438574395744057441574425744357444574455744657447574485744957450574515745257453574545745557456574575745857459574605746157462574635746457465574665746757468574695747057471574725747357474574755747657477574785747957480574815748257483574845748557486574875748857489574905749157492574935749457495574965749757498574995750057501575025750357504575055750657507575085750957510575115751257513575145751557516575175751857519575205752157522575235752457525575265752757528575295753057531575325753357534575355753657537575385753957540575415754257543575445754557546575475754857549575505755157552575535755457555575565755757558575595756057561575625756357564575655756657567575685756957570575715757257573575745757557576575775757857579575805758157582575835758457585575865758757588575895759057591575925759357594575955759657597575985759957600576015760257603576045760557606576075760857609576105761157612576135761457615576165761757618576195762057621576225762357624576255762657627576285762957630576315763257633576345763557636576375763857639576405764157642576435764457645576465764757648576495765057651576525765357654576555765657657576585765957660576615766257663576645766557666576675766857669576705767157672576735767457675576765767757678576795768057681576825768357684576855768657687576885768957690576915769257693576945769557696576975769857699577005770157702577035770457705577065770757708577095771057711577125771357714577155771657717577185771957720577215772257723577245772557726577275772857729577305773157732577335773457735577365773757738577395774057741577425774357744577455774657747577485774957750577515775257753577545775557756577575775857759577605776157762577635776457765577665776757768577695777057771577725777357774577755777657777577785777957780577815778257783577845778557786577875778857789577905779157792577935779457795577965779757798577995780057801578025780357804578055780657807578085780957810578115781257813578145781557816578175781857819578205782157822578235782457825578265782757828578295783057831578325783357834578355783657837578385783957840578415784257843578445784557846578475784857849578505785157852578535785457855578565785757858578595786057861578625786357864578655786657867578685786957870578715787257873578745787557876578775787857879578805788157882578835788457885578865788757888578895789057891578925789357894578955789657897578985789957900579015790257903579045790557906579075790857909579105791157912579135791457915579165791757918579195792057921579225792357924579255792657927579285792957930579315793257933579345793557936579375793857939579405794157942579435794457945579465794757948579495795057951579525795357954579555795657957579585795957960579615796257963579645796557966579675796857969579705797157972579735797457975579765797757978579795798057981579825798357984579855798657987579885798957990579915799257993579945799557996579975799857999580005800158002580035800458005580065800758008580095801058011580125801358014580155801658017580185801958020580215802258023580245802558026580275802858029580305803158032580335803458035580365803758038580395804058041580425804358044580455804658047580485804958050580515805258053580545805558056580575805858059580605806158062580635806458065580665806758068580695807058071580725807358074580755807658077580785807958080580815808258083580845808558086580875808858089580905809158092580935809458095580965809758098580995810058101581025810358104581055810658107581085810958110581115811258113581145811558116581175811858119581205812158122581235812458125581265812758128581295813058131581325813358134581355813658137581385813958140581415814258143581445814558146581475814858149581505815158152581535815458155581565815758158581595816058161581625816358164581655816658167581685816958170581715817258173581745817558176581775817858179581805818158182581835818458185581865818758188581895819058191581925819358194581955819658197581985819958200582015820258203582045820558206582075820858209582105821158212582135821458215582165821758218582195822058221582225822358224582255822658227582285822958230582315823258233582345823558236582375823858239582405824158242582435824458245582465824758248582495825058251582525825358254582555825658257582585825958260582615826258263582645826558266582675826858269582705827158272582735827458275582765827758278582795828058281582825828358284582855828658287582885828958290582915829258293582945829558296582975829858299583005830158302583035830458305583065830758308583095831058311583125831358314583155831658317583185831958320583215832258323583245832558326583275832858329583305833158332583335833458335583365833758338583395834058341583425834358344583455834658347583485834958350583515835258353583545835558356583575835858359583605836158362583635836458365583665836758368583695837058371583725837358374583755837658377583785837958380583815838258383583845838558386583875838858389583905839158392583935839458395583965839758398583995840058401584025840358404584055840658407584085840958410584115841258413584145841558416584175841858419584205842158422584235842458425584265842758428584295843058431584325843358434584355843658437584385843958440584415844258443584445844558446584475844858449584505845158452584535845458455584565845758458584595846058461584625846358464584655846658467584685846958470584715847258473584745847558476584775847858479584805848158482584835848458485584865848758488584895849058491584925849358494584955849658497584985849958500585015850258503585045850558506585075850858509585105851158512585135851458515585165851758518585195852058521585225852358524585255852658527585285852958530585315853258533585345853558536585375853858539585405854158542585435854458545585465854758548585495855058551585525855358554585555855658557585585855958560585615856258563585645856558566585675856858569585705857158572585735857458575585765857758578585795858058581585825858358584585855858658587585885858958590585915859258593585945859558596585975859858599586005860158602586035860458605586065860758608586095861058611586125861358614586155861658617586185861958620586215862258623586245862558626586275862858629586305863158632586335863458635586365863758638586395864058641586425864358644586455864658647586485864958650586515865258653586545865558656586575865858659586605866158662586635866458665586665866758668586695867058671586725867358674586755867658677586785867958680586815868258683586845868558686586875868858689586905869158692586935869458695586965869758698586995870058701587025870358704587055870658707587085870958710587115871258713587145871558716587175871858719587205872158722587235872458725587265872758728587295873058731587325873358734587355873658737587385873958740587415874258743587445874558746587475874858749587505875158752587535875458755587565875758758587595876058761587625876358764587655876658767587685876958770587715877258773587745877558776587775877858779587805878158782587835878458785587865878758788587895879058791587925879358794587955879658797587985879958800588015880258803588045880558806588075880858809588105881158812588135881458815588165881758818588195882058821588225882358824588255882658827588285882958830588315883258833588345883558836588375883858839588405884158842588435884458845588465884758848588495885058851588525885358854588555885658857588585885958860588615886258863588645886558866588675886858869588705887158872588735887458875588765887758878588795888058881588825888358884588855888658887588885888958890588915889258893588945889558896588975889858899589005890158902589035890458905589065890758908589095891058911589125891358914589155891658917589185891958920589215892258923589245892558926589275892858929589305893158932589335893458935589365893758938589395894058941589425894358944589455894658947589485894958950589515895258953589545895558956589575895858959589605896158962589635896458965589665896758968589695897058971589725897358974589755897658977589785897958980589815898258983589845898558986589875898858989589905899158992589935899458995589965899758998589995900059001590025900359004590055900659007590085900959010590115901259013590145901559016590175901859019590205902159022590235902459025590265902759028590295903059031590325903359034590355903659037590385903959040590415904259043590445904559046590475904859049590505905159052590535905459055590565905759058590595906059061590625906359064590655906659067590685906959070590715907259073590745907559076590775907859079590805908159082590835908459085590865908759088590895909059091590925909359094590955909659097590985909959100591015910259103591045910559106591075910859109591105911159112591135911459115591165911759118591195912059121591225912359124591255912659127591285912959130591315913259133591345913559136591375913859139591405914159142591435914459145591465914759148591495915059151591525915359154591555915659157591585915959160591615916259163591645916559166591675916859169591705917159172591735917459175591765917759178591795918059181591825918359184591855918659187591885918959190591915919259193591945919559196591975919859199592005920159202592035920459205592065920759208592095921059211592125921359214592155921659217592185921959220592215922259223592245922559226592275922859229592305923159232592335923459235592365923759238592395924059241592425924359244592455924659247592485924959250592515925259253592545925559256592575925859259592605926159262592635926459265592665926759268592695927059271592725927359274592755927659277592785927959280592815928259283592845928559286592875928859289592905929159292592935929459295592965929759298592995930059301593025930359304593055930659307593085930959310593115931259313593145931559316593175931859319593205932159322593235932459325593265932759328593295933059331593325933359334593355933659337593385933959340593415934259343593445934559346593475934859349593505935159352593535935459355593565935759358593595936059361593625936359364593655936659367593685936959370593715937259373593745937559376593775937859379593805938159382593835938459385593865938759388593895939059391593925939359394593955939659397593985939959400594015940259403594045940559406594075940859409594105941159412594135941459415594165941759418594195942059421594225942359424594255942659427594285942959430594315943259433594345943559436594375943859439594405944159442594435944459445594465944759448594495945059451594525945359454594555945659457594585945959460594615946259463594645946559466594675946859469594705947159472594735947459475594765947759478594795948059481594825948359484594855948659487594885948959490594915949259493594945949559496594975949859499595005950159502595035950459505595065950759508595095951059511595125951359514595155951659517595185951959520595215952259523595245952559526595275952859529595305953159532595335953459535595365953759538595395954059541595425954359544595455954659547595485954959550595515955259553595545955559556595575955859559595605956159562595635956459565595665956759568595695957059571595725957359574595755957659577595785957959580595815958259583595845958559586595875958859589595905959159592595935959459595595965959759598595995960059601596025960359604596055960659607596085960959610596115961259613596145961559616596175961859619596205962159622596235962459625596265962759628596295963059631596325963359634596355963659637596385963959640596415964259643596445964559646596475964859649596505965159652596535965459655596565965759658596595966059661596625966359664596655966659667596685966959670596715967259673596745967559676596775967859679596805968159682596835968459685596865968759688596895969059691596925969359694596955969659697596985969959700597015970259703597045970559706597075970859709597105971159712597135971459715597165971759718597195972059721597225972359724597255972659727597285972959730597315973259733597345973559736597375973859739597405974159742597435974459745597465974759748597495975059751597525975359754597555975659757597585975959760597615976259763597645976559766597675976859769597705977159772597735977459775597765977759778597795978059781597825978359784597855978659787597885978959790597915979259793597945979559796597975979859799598005980159802598035980459805598065980759808598095981059811598125981359814598155981659817598185981959820598215982259823598245982559826598275982859829598305983159832598335983459835598365983759838598395984059841598425984359844598455984659847598485984959850598515985259853598545985559856598575985859859598605986159862598635986459865598665986759868598695987059871598725987359874598755987659877598785987959880598815988259883598845988559886598875988859889598905989159892598935989459895598965989759898598995990059901599025990359904599055990659907599085990959910599115991259913599145991559916599175991859919599205992159922599235992459925599265992759928599295993059931599325993359934599355993659937599385993959940599415994259943599445994559946599475994859949599505995159952599535995459955599565995759958599595996059961599625996359964599655996659967599685996959970599715997259973599745997559976599775997859979599805998159982599835998459985599865998759988599895999059991599925999359994599955999659997599985999960000600016000260003600046000560006600076000860009600106001160012600136001460015600166001760018600196002060021600226002360024600256002660027600286002960030600316003260033600346003560036600376003860039600406004160042600436004460045600466004760048600496005060051600526005360054600556005660057600586005960060600616006260063600646006560066600676006860069600706007160072600736007460075600766007760078600796008060081600826008360084600856008660087600886008960090600916009260093600946009560096600976009860099601006010160102601036010460105601066010760108601096011060111601126011360114601156011660117601186011960120601216012260123601246012560126601276012860129601306013160132601336013460135601366013760138601396014060141601426014360144601456014660147601486014960150601516015260153601546015560156601576015860159601606016160162601636016460165601666016760168601696017060171601726017360174601756017660177601786017960180601816018260183601846018560186601876018860189601906019160192601936019460195601966019760198601996020060201602026020360204602056020660207602086020960210602116021260213602146021560216602176021860219602206022160222602236022460225602266022760228602296023060231602326023360234602356023660237602386023960240602416024260243602446024560246602476024860249602506025160252602536025460255602566025760258602596026060261602626026360264602656026660267602686026960270602716027260273602746027560276602776027860279602806028160282602836028460285602866028760288602896029060291602926029360294602956029660297602986029960300603016030260303603046030560306603076030860309603106031160312603136031460315603166031760318603196032060321603226032360324603256032660327603286032960330603316033260333603346033560336603376033860339603406034160342603436034460345603466034760348603496035060351603526035360354603556035660357603586035960360603616036260363603646036560366603676036860369603706037160372603736037460375603766037760378603796038060381603826038360384603856038660387603886038960390603916039260393603946039560396603976039860399604006040160402604036040460405604066040760408604096041060411604126041360414604156041660417604186041960420604216042260423604246042560426604276042860429604306043160432604336043460435604366043760438604396044060441604426044360444604456044660447604486044960450604516045260453604546045560456604576045860459604606046160462604636046460465604666046760468604696047060471604726047360474604756047660477604786047960480604816048260483604846048560486604876048860489604906049160492604936049460495604966049760498604996050060501605026050360504605056050660507605086050960510605116051260513605146051560516605176051860519605206052160522605236052460525605266052760528605296053060531605326053360534605356053660537605386053960540605416054260543605446054560546605476054860549605506055160552605536055460555605566055760558605596056060561605626056360564605656056660567605686056960570605716057260573605746057560576605776057860579605806058160582605836058460585605866058760588605896059060591605926059360594605956059660597605986059960600606016060260603606046060560606606076060860609606106061160612606136061460615606166061760618606196062060621606226062360624606256062660627606286062960630606316063260633606346063560636606376063860639606406064160642606436064460645606466064760648606496065060651606526065360654606556065660657606586065960660606616066260663606646066560666606676066860669606706067160672606736067460675606766067760678606796068060681606826068360684606856068660687606886068960690606916069260693606946069560696606976069860699607006070160702607036070460705607066070760708607096071060711607126071360714607156071660717607186071960720607216072260723607246072560726607276072860729607306073160732607336073460735607366073760738607396074060741607426074360744607456074660747607486074960750607516075260753607546075560756607576075860759607606076160762607636076460765607666076760768607696077060771607726077360774607756077660777607786077960780607816078260783607846078560786607876078860789607906079160792607936079460795607966079760798607996080060801608026080360804608056080660807608086080960810608116081260813608146081560816608176081860819608206082160822608236082460825608266082760828608296083060831608326083360834608356083660837608386083960840608416084260843608446084560846608476084860849608506085160852608536085460855608566085760858608596086060861608626086360864608656086660867608686086960870608716087260873608746087560876608776087860879608806088160882608836088460885608866088760888608896089060891608926089360894608956089660897608986089960900609016090260903609046090560906609076090860909609106091160912609136091460915609166091760918609196092060921609226092360924609256092660927609286092960930609316093260933609346093560936609376093860939609406094160942609436094460945609466094760948609496095060951609526095360954609556095660957609586095960960609616096260963609646096560966609676096860969609706097160972609736097460975609766097760978609796098060981609826098360984609856098660987609886098960990609916099260993609946099560996609976099860999610006100161002610036100461005610066100761008610096101061011610126101361014610156101661017610186101961020610216102261023610246102561026610276102861029610306103161032610336103461035610366103761038610396104061041610426104361044610456104661047610486104961050610516105261053610546105561056610576105861059610606106161062610636106461065610666106761068610696107061071610726107361074610756107661077610786107961080610816108261083610846108561086610876108861089610906109161092610936109461095610966109761098610996110061101611026110361104611056110661107611086110961110611116111261113611146111561116611176111861119611206112161122611236112461125611266112761128611296113061131611326113361134611356113661137611386113961140611416114261143611446114561146611476114861149611506115161152611536115461155611566115761158611596116061161611626116361164611656116661167611686116961170611716117261173611746117561176611776117861179611806118161182611836118461185611866118761188611896119061191611926119361194611956119661197611986119961200612016120261203612046120561206612076120861209612106121161212612136121461215612166121761218612196122061221612226122361224612256122661227612286122961230612316123261233612346123561236612376123861239612406124161242612436124461245612466124761248612496125061251612526125361254612556125661257612586125961260612616126261263612646126561266612676126861269612706127161272612736127461275612766127761278612796128061281612826128361284612856128661287612886128961290612916129261293612946129561296612976129861299613006130161302613036130461305613066130761308613096131061311613126131361314613156131661317613186131961320613216132261323613246132561326613276132861329613306133161332613336133461335613366133761338613396134061341613426134361344613456134661347613486134961350613516135261353613546135561356613576135861359613606136161362613636136461365613666136761368613696137061371613726137361374613756137661377613786137961380613816138261383613846138561386613876138861389613906139161392613936139461395613966139761398613996140061401614026140361404614056140661407614086140961410614116141261413614146141561416614176141861419614206142161422614236142461425614266142761428614296143061431614326143361434614356143661437614386143961440614416144261443614446144561446614476144861449614506145161452614536145461455614566145761458614596146061461614626146361464614656146661467614686146961470614716147261473614746147561476614776147861479614806148161482614836148461485614866148761488614896149061491614926149361494614956149661497614986149961500615016150261503615046150561506615076150861509615106151161512615136151461515615166151761518615196152061521615226152361524615256152661527615286152961530615316153261533615346153561536615376153861539615406154161542615436154461545615466154761548615496155061551615526155361554615556155661557615586155961560615616156261563615646156561566615676156861569615706157161572615736157461575615766157761578615796158061581615826158361584615856158661587615886158961590615916159261593615946159561596615976159861599616006160161602616036160461605616066160761608616096161061611616126161361614616156161661617616186161961620616216162261623616246162561626616276162861629616306163161632616336163461635616366163761638616396164061641616426164361644616456164661647616486164961650616516165261653616546165561656616576165861659616606166161662616636166461665616666166761668616696167061671616726167361674616756167661677616786167961680616816168261683616846168561686616876168861689616906169161692616936169461695616966169761698616996170061701617026170361704617056170661707617086170961710617116171261713617146171561716617176171861719617206172161722617236172461725617266172761728617296173061731617326173361734617356173661737617386173961740617416174261743617446174561746617476174861749617506175161752617536175461755617566175761758617596176061761617626176361764617656176661767617686176961770617716177261773617746177561776617776177861779617806178161782617836178461785617866178761788617896179061791617926179361794617956179661797617986179961800618016180261803618046180561806618076180861809618106181161812618136181461815618166181761818618196182061821618226182361824618256182661827618286182961830618316183261833618346183561836618376183861839618406184161842618436184461845618466184761848618496185061851618526185361854618556185661857618586185961860618616186261863618646186561866618676186861869618706187161872618736187461875618766187761878618796188061881618826188361884618856188661887618886188961890618916189261893618946189561896618976189861899619006190161902619036190461905619066190761908619096191061911619126191361914619156191661917619186191961920619216192261923619246192561926619276192861929619306193161932619336193461935619366193761938619396194061941619426194361944619456194661947619486194961950619516195261953619546195561956619576195861959619606196161962619636196461965619666196761968619696197061971619726197361974619756197661977619786197961980619816198261983619846198561986619876198861989619906199161992619936199461995619966199761998619996200062001620026200362004620056200662007620086200962010620116201262013620146201562016620176201862019620206202162022620236202462025620266202762028620296203062031620326203362034620356203662037620386203962040620416204262043620446204562046620476204862049620506205162052620536205462055620566205762058620596206062061620626206362064620656206662067620686206962070620716207262073620746207562076620776207862079620806208162082620836208462085620866208762088620896209062091620926209362094620956209662097620986209962100621016210262103621046210562106621076210862109621106211162112621136211462115621166211762118621196212062121621226212362124621256212662127621286212962130621316213262133621346213562136621376213862139621406214162142621436214462145621466214762148621496215062151621526215362154621556215662157621586215962160621616216262163621646216562166621676216862169621706217162172621736217462175621766217762178621796218062181621826218362184621856218662187621886218962190621916219262193621946219562196621976219862199622006220162202622036220462205622066220762208622096221062211622126221362214622156221662217622186221962220622216222262223622246222562226622276222862229622306223162232622336223462235622366223762238622396224062241622426224362244622456224662247622486224962250622516225262253622546225562256622576225862259622606226162262622636226462265622666226762268622696227062271622726227362274622756227662277622786227962280622816228262283622846228562286622876228862289622906229162292622936229462295622966229762298622996230062301623026230362304623056230662307623086230962310623116231262313623146231562316623176231862319623206232162322623236232462325623266232762328623296233062331623326233362334623356233662337623386233962340623416234262343623446234562346623476234862349623506235162352623536235462355623566235762358623596236062361623626236362364623656236662367623686236962370623716237262373623746237562376623776237862379623806238162382623836238462385623866238762388623896239062391623926239362394623956239662397623986239962400624016240262403624046240562406624076240862409624106241162412624136241462415624166241762418624196242062421624226242362424624256242662427624286242962430624316243262433624346243562436624376243862439624406244162442624436244462445624466244762448624496245062451624526245362454624556245662457624586245962460624616246262463624646246562466624676246862469624706247162472624736247462475624766247762478624796248062481624826248362484624856248662487624886248962490624916249262493624946249562496624976249862499625006250162502625036250462505625066250762508625096251062511625126251362514625156251662517625186251962520625216252262523625246252562526625276252862529625306253162532625336253462535625366253762538625396254062541625426254362544625456254662547625486254962550625516255262553625546255562556625576255862559625606256162562625636256462565625666256762568625696257062571625726257362574625756257662577625786257962580625816258262583625846258562586625876258862589625906259162592625936259462595625966259762598625996260062601626026260362604626056260662607626086260962610626116261262613626146261562616626176261862619626206262162622626236262462625626266262762628626296263062631626326263362634626356263662637626386263962640626416264262643626446264562646626476264862649626506265162652626536265462655626566265762658626596266062661626626266362664626656266662667626686266962670626716267262673626746267562676626776267862679626806268162682626836268462685626866268762688626896269062691626926269362694626956269662697626986269962700627016270262703627046270562706627076270862709627106271162712627136271462715627166271762718627196272062721627226272362724627256272662727627286272962730627316273262733627346273562736627376273862739627406274162742627436274462745627466274762748627496275062751627526275362754627556275662757627586275962760627616276262763627646276562766627676276862769627706277162772627736277462775627766277762778627796278062781627826278362784627856278662787627886278962790627916279262793627946279562796627976279862799628006280162802628036280462805628066280762808628096281062811628126281362814628156281662817628186281962820628216282262823628246282562826628276282862829628306283162832628336283462835628366283762838628396284062841628426284362844628456284662847628486284962850628516285262853628546285562856628576285862859628606286162862628636286462865628666286762868628696287062871628726287362874628756287662877628786287962880628816288262883628846288562886628876288862889628906289162892628936289462895628966289762898628996290062901629026290362904629056290662907629086290962910629116291262913629146291562916629176291862919629206292162922629236292462925629266292762928629296293062931629326293362934629356293662937629386293962940629416294262943629446294562946629476294862949629506295162952629536295462955629566295762958629596296062961629626296362964629656296662967629686296962970629716297262973629746297562976629776297862979629806298162982629836298462985629866298762988629896299062991629926299362994629956299662997629986299963000630016300263003630046300563006630076300863009630106301163012630136301463015630166301763018630196302063021630226302363024630256302663027630286302963030630316303263033630346303563036630376303863039630406304163042630436304463045630466304763048630496305063051630526305363054630556305663057630586305963060630616306263063630646306563066630676306863069630706307163072630736307463075630766307763078630796308063081630826308363084630856308663087630886308963090630916309263093630946309563096630976309863099631006310163102631036310463105631066310763108631096311063111631126311363114631156311663117631186311963120631216312263123631246312563126631276312863129631306313163132631336313463135631366313763138631396314063141631426314363144631456314663147631486314963150631516315263153631546315563156631576315863159631606316163162631636316463165631666316763168631696317063171631726317363174631756317663177631786317963180631816318263183631846318563186631876318863189631906319163192631936319463195631966319763198631996320063201632026320363204632056320663207632086320963210632116321263213632146321563216632176321863219632206322163222632236322463225632266322763228632296323063231632326323363234632356323663237632386323963240632416324263243632446324563246632476324863249632506325163252632536325463255632566325763258632596326063261632626326363264632656326663267632686326963270632716327263273632746327563276632776327863279632806328163282632836328463285632866328763288632896329063291632926329363294632956329663297632986329963300633016330263303633046330563306633076330863309633106331163312633136331463315633166331763318633196332063321633226332363324633256332663327633286332963330633316333263333633346333563336633376333863339633406334163342633436334463345633466334763348633496335063351633526335363354633556335663357633586335963360633616336263363633646336563366633676336863369633706337163372633736337463375633766337763378633796338063381633826338363384633856338663387633886338963390633916339263393633946339563396633976339863399634006340163402634036340463405634066340763408634096341063411634126341363414634156341663417634186341963420634216342263423634246342563426634276342863429634306343163432634336343463435634366343763438634396344063441634426344363444634456344663447634486344963450634516345263453634546345563456634576345863459634606346163462634636346463465634666346763468634696347063471634726347363474634756347663477634786347963480634816348263483634846348563486634876348863489634906349163492634936349463495634966349763498634996350063501635026350363504635056350663507635086350963510635116351263513635146351563516635176351863519635206352163522635236352463525635266352763528635296353063531635326353363534635356353663537635386353963540635416354263543635446354563546635476354863549635506355163552635536355463555635566355763558635596356063561635626356363564635656356663567635686356963570635716357263573635746357563576635776357863579635806358163582635836358463585635866358763588635896359063591635926359363594635956359663597635986359963600636016360263603636046360563606636076360863609636106361163612636136361463615636166361763618636196362063621636226362363624636256362663627636286362963630636316363263633636346363563636636376363863639636406364163642636436364463645636466364763648636496365063651636526365363654636556365663657636586365963660636616366263663636646366563666636676366863669636706367163672636736367463675636766367763678636796368063681636826368363684636856368663687636886368963690636916369263693636946369563696636976369863699637006370163702637036370463705637066370763708637096371063711637126371363714637156371663717637186371963720637216372263723637246372563726637276372863729637306373163732637336373463735637366373763738637396374063741637426374363744637456374663747637486374963750637516375263753637546375563756637576375863759637606376163762637636376463765637666376763768637696377063771637726377363774637756377663777637786377963780637816378263783637846378563786637876378863789637906379163792637936379463795637966379763798637996380063801638026380363804638056380663807638086380963810638116381263813638146381563816638176381863819638206382163822638236382463825638266382763828638296383063831638326383363834638356383663837638386383963840638416384263843638446384563846638476384863849638506385163852638536385463855638566385763858638596386063861638626386363864638656386663867638686386963870638716387263873638746387563876638776387863879638806388163882638836388463885638866388763888638896389063891638926389363894638956389663897638986389963900639016390263903639046390563906639076390863909639106391163912639136391463915639166391763918639196392063921639226392363924639256392663927639286392963930639316393263933639346393563936639376393863939639406394163942639436394463945639466394763948639496395063951639526395363954639556395663957639586395963960639616396263963639646396563966639676396863969639706397163972639736397463975639766397763978639796398063981639826398363984639856398663987639886398963990639916399263993639946399563996639976399863999640006400164002640036400464005640066400764008640096401064011640126401364014640156401664017640186401964020640216402264023640246402564026640276402864029640306403164032640336403464035640366403764038640396404064041640426404364044640456404664047640486404964050640516405264053640546405564056640576405864059640606406164062640636406464065640666406764068640696407064071640726407364074640756407664077640786407964080640816408264083640846408564086640876408864089640906409164092640936409464095640966409764098640996410064101641026410364104641056410664107641086410964110641116411264113641146411564116641176411864119641206412164122641236412464125641266412764128641296413064131641326413364134641356413664137641386413964140641416414264143641446414564146641476414864149641506415164152641536415464155641566415764158641596416064161641626416364164641656416664167641686416964170641716417264173641746417564176641776417864179641806418164182641836418464185641866418764188641896419064191641926419364194641956419664197641986419964200642016420264203642046420564206642076420864209642106421164212642136421464215642166421764218642196422064221642226422364224642256422664227642286422964230642316423264233642346423564236642376423864239642406424164242642436424464245642466424764248642496425064251642526425364254642556425664257642586425964260642616426264263642646426564266642676426864269642706427164272642736427464275642766427764278642796428064281642826428364284642856428664287642886428964290642916429264293642946429564296642976429864299643006430164302643036430464305643066430764308643096431064311643126431364314643156431664317643186431964320643216432264323643246432564326643276432864329643306433164332643336433464335643366433764338643396434064341643426434364344643456434664347643486434964350643516435264353643546435564356643576435864359643606436164362643636436464365643666436764368643696437064371643726437364374643756437664377643786437964380643816438264383643846438564386643876438864389643906439164392643936439464395643966439764398643996440064401644026440364404644056440664407644086440964410644116441264413644146441564416644176441864419644206442164422644236442464425644266442764428644296443064431644326443364434644356443664437644386443964440644416444264443644446444564446644476444864449644506445164452644536445464455644566445764458644596446064461644626446364464644656446664467644686446964470644716447264473644746447564476644776447864479644806448164482644836448464485644866448764488644896449064491644926449364494644956449664497644986449964500645016450264503645046450564506645076450864509645106451164512645136451464515645166451764518645196452064521645226452364524645256452664527645286452964530645316453264533645346453564536645376453864539645406454164542645436454464545645466454764548645496455064551645526455364554645556455664557645586455964560645616456264563645646456564566645676456864569645706457164572645736457464575645766457764578645796458064581645826458364584645856458664587645886458964590645916459264593645946459564596645976459864599646006460164602646036460464605646066460764608646096461064611646126461364614646156461664617646186461964620646216462264623646246462564626646276462864629646306463164632646336463464635646366463764638646396464064641646426464364644646456464664647646486464964650646516465264653646546465564656646576465864659646606466164662646636466464665646666466764668646696467064671646726467364674646756467664677646786467964680646816468264683646846468564686646876468864689646906469164692646936469464695646966469764698646996470064701647026470364704647056470664707647086470964710647116471264713647146471564716647176471864719647206472164722647236472464725647266472764728647296473064731647326473364734647356473664737647386473964740647416474264743647446474564746647476474864749647506475164752647536475464755647566475764758647596476064761647626476364764647656476664767647686476964770647716477264773647746477564776647776477864779647806478164782647836478464785647866478764788647896479064791647926479364794647956479664797647986479964800648016480264803648046480564806648076480864809648106481164812648136481464815648166481764818648196482064821648226482364824648256482664827648286482964830648316483264833648346483564836648376483864839648406484164842648436484464845648466484764848648496485064851648526485364854648556485664857648586485964860648616486264863648646486564866648676486864869648706487164872648736487464875648766487764878648796488064881648826488364884648856488664887648886488964890648916489264893648946489564896648976489864899649006490164902649036490464905649066490764908649096491064911649126491364914649156491664917649186491964920649216492264923649246492564926649276492864929649306493164932649336493464935649366493764938649396494064941649426494364944649456494664947649486494964950649516495264953649546495564956649576495864959649606496164962649636496464965649666496764968649696497064971649726497364974649756497664977649786497964980649816498264983649846498564986649876498864989649906499164992649936499464995649966499764998649996500065001650026500365004650056500665007650086500965010650116501265013650146501565016650176501865019650206502165022650236502465025650266502765028650296503065031650326503365034650356503665037650386503965040650416504265043650446504565046650476504865049650506505165052650536505465055650566505765058650596506065061650626506365064650656506665067650686506965070650716507265073650746507565076650776507865079650806508165082650836508465085650866508765088650896509065091650926509365094650956509665097650986509965100651016510265103651046510565106651076510865109651106511165112651136511465115651166511765118651196512065121651226512365124651256512665127651286512965130651316513265133651346513565136651376513865139651406514165142651436514465145651466514765148651496515065151651526515365154651556515665157651586515965160651616516265163651646516565166651676516865169651706517165172651736517465175651766517765178651796518065181651826518365184651856518665187651886518965190651916519265193651946519565196651976519865199652006520165202652036520465205652066520765208652096521065211652126521365214652156521665217652186521965220652216522265223652246522565226652276522865229652306523165232652336523465235652366523765238652396524065241652426524365244652456524665247652486524965250652516525265253652546525565256652576525865259652606526165262652636526465265652666526765268652696527065271652726527365274652756527665277652786527965280652816528265283652846528565286652876528865289652906529165292652936529465295652966529765298652996530065301653026530365304653056530665307653086530965310653116531265313653146531565316653176531865319653206532165322653236532465325653266532765328653296533065331653326533365334653356533665337653386533965340653416534265343653446534565346653476534865349653506535165352653536535465355653566535765358653596536065361653626536365364653656536665367653686536965370653716537265373653746537565376653776537865379653806538165382653836538465385653866538765388653896539065391653926539365394653956539665397653986539965400654016540265403654046540565406654076540865409654106541165412654136541465415654166541765418654196542065421654226542365424654256542665427654286542965430654316543265433654346543565436654376543865439654406544165442654436544465445654466544765448654496545065451654526545365454654556545665457654586545965460654616546265463654646546565466654676546865469654706547165472654736547465475654766547765478654796548065481654826548365484654856548665487654886548965490654916549265493654946549565496654976549865499655006550165502655036550465505655066550765508655096551065511655126551365514655156551665517655186551965520655216552265523655246552565526655276552865529655306553165532655336553465535655366553765538655396554065541655426554365544655456554665547655486554965550655516555265553655546555565556655576555865559655606556165562655636556465565655666556765568655696557065571655726557365574655756557665577655786557965580655816558265583655846558565586655876558865589655906559165592655936559465595655966559765598655996560065601656026560365604656056560665607656086560965610656116561265613656146561565616656176561865619656206562165622656236562465625656266562765628656296563065631656326563365634656356563665637656386563965640656416564265643656446564565646656476564865649656506565165652656536565465655656566565765658656596566065661656626566365664656656566665667656686566965670656716567265673656746567565676656776567865679656806568165682656836568465685656866568765688656896569065691656926569365694656956569665697656986569965700657016570265703657046570565706657076570865709657106571165712657136571465715657166571765718657196572065721657226572365724657256572665727657286572965730657316573265733657346573565736657376573865739657406574165742657436574465745657466574765748657496575065751657526575365754657556575665757657586575965760657616576265763657646576565766657676576865769657706577165772657736577465775657766577765778657796578065781657826578365784657856578665787657886578965790657916579265793657946579565796657976579865799658006580165802658036580465805658066580765808658096581065811658126581365814658156581665817658186581965820658216582265823658246582565826658276582865829658306583165832658336583465835658366583765838658396584065841658426584365844658456584665847658486584965850658516585265853658546585565856658576585865859658606586165862658636586465865658666586765868658696587065871658726587365874658756587665877658786587965880658816588265883658846588565886658876588865889658906589165892658936589465895658966589765898658996590065901659026590365904659056590665907659086590965910659116591265913659146591565916659176591865919659206592165922659236592465925659266592765928659296593065931659326593365934659356593665937659386593965940659416594265943659446594565946659476594865949659506595165952659536595465955659566595765958659596596065961659626596365964659656596665967659686596965970659716597265973659746597565976659776597865979659806598165982659836598465985659866598765988659896599065991659926599365994659956599665997659986599966000660016600266003660046600566006660076600866009660106601166012660136601466015660166601766018660196602066021660226602366024660256602666027660286602966030660316603266033660346603566036660376603866039660406604166042660436604466045660466604766048660496605066051660526605366054660556605666057660586605966060660616606266063660646606566066660676606866069660706607166072660736607466075660766607766078660796608066081660826608366084660856608666087660886608966090660916609266093660946609566096660976609866099661006610166102661036610466105661066610766108661096611066111661126611366114661156611666117661186611966120661216612266123661246612566126661276612866129661306613166132661336613466135661366613766138661396614066141661426614366144661456614666147661486614966150661516615266153661546615566156661576615866159661606616166162661636616466165661666616766168661696617066171661726617366174661756617666177661786617966180661816618266183661846618566186661876618866189661906619166192661936619466195661966619766198661996620066201662026620366204662056620666207662086620966210662116621266213662146621566216662176621866219662206622166222662236622466225662266622766228662296623066231662326623366234662356623666237662386623966240662416624266243662446624566246662476624866249662506625166252662536625466255662566625766258662596626066261662626626366264662656626666267662686626966270662716627266273662746627566276662776627866279662806628166282662836628466285662866628766288662896629066291662926629366294662956629666297662986629966300663016630266303663046630566306663076630866309663106631166312663136631466315663166631766318663196632066321663226632366324663256632666327663286632966330663316633266333663346633566336663376633866339663406634166342663436634466345663466634766348663496635066351663526635366354663556635666357663586635966360663616636266363663646636566366663676636866369663706637166372663736637466375663766637766378663796638066381663826638366384663856638666387663886638966390663916639266393663946639566396663976639866399664006640166402664036640466405664066640766408664096641066411664126641366414664156641666417664186641966420664216642266423664246642566426664276642866429664306643166432664336643466435664366643766438664396644066441664426644366444664456644666447664486644966450664516645266453664546645566456664576645866459664606646166462664636646466465664666646766468664696647066471664726647366474664756647666477664786647966480664816648266483664846648566486664876648866489664906649166492664936649466495664966649766498664996650066501665026650366504665056650666507665086650966510665116651266513665146651566516665176651866519665206652166522665236652466525665266652766528665296653066531665326653366534665356653666537665386653966540665416654266543665446654566546665476654866549665506655166552665536655466555665566655766558665596656066561665626656366564665656656666567665686656966570665716657266573665746657566576665776657866579665806658166582665836658466585665866658766588665896659066591665926659366594665956659666597665986659966600666016660266603666046660566606666076660866609666106661166612666136661466615666166661766618666196662066621666226662366624666256662666627666286662966630666316663266633666346663566636666376663866639666406664166642666436664466645666466664766648666496665066651666526665366654666556665666657666586665966660666616666266663666646666566666666676666866669666706667166672666736667466675666766667766678666796668066681666826668366684666856668666687666886668966690666916669266693666946669566696666976669866699667006670166702667036670466705667066670766708667096671066711667126671366714667156671666717667186671966720667216672266723667246672566726667276672866729667306673166732667336673466735667366673766738667396674066741667426674366744667456674666747667486674966750667516675266753667546675566756667576675866759667606676166762667636676466765667666676766768667696677066771667726677366774667756677666777667786677966780667816678266783667846678566786667876678866789667906679166792667936679466795667966679766798667996680066801668026680366804668056680666807668086680966810668116681266813668146681566816668176681866819668206682166822668236682466825668266682766828668296683066831668326683366834668356683666837668386683966840668416684266843668446684566846668476684866849668506685166852668536685466855668566685766858668596686066861668626686366864668656686666867668686686966870668716687266873668746687566876668776687866879668806688166882668836688466885668866688766888668896689066891668926689366894668956689666897668986689966900669016690266903669046690566906669076690866909669106691166912669136691466915669166691766918669196692066921669226692366924669256692666927669286692966930669316693266933669346693566936669376693866939669406694166942669436694466945669466694766948669496695066951669526695366954669556695666957669586695966960669616696266963669646696566966669676696866969669706697166972669736697466975669766697766978669796698066981669826698366984669856698666987669886698966990669916699266993669946699566996669976699866999670006700167002670036700467005670066700767008670096701067011670126701367014670156701667017670186701967020670216702267023670246702567026670276702867029670306703167032670336703467035670366703767038670396704067041670426704367044670456704667047670486704967050670516705267053670546705567056670576705867059670606706167062670636706467065670666706767068670696707067071670726707367074670756707667077670786707967080670816708267083670846708567086670876708867089670906709167092670936709467095670966709767098670996710067101671026710367104671056710667107671086710967110671116711267113671146711567116671176711867119671206712167122671236712467125671266712767128671296713067131671326713367134671356713667137671386713967140671416714267143671446714567146671476714867149671506715167152671536715467155671566715767158671596716067161671626716367164671656716667167671686716967170671716717267173671746717567176671776717867179671806718167182671836718467185671866718767188671896719067191671926719367194671956719667197671986719967200672016720267203672046720567206672076720867209672106721167212672136721467215672166721767218672196722067221672226722367224672256722667227672286722967230672316723267233672346723567236672376723867239672406724167242672436724467245672466724767248672496725067251672526725367254672556725667257672586725967260672616726267263672646726567266672676726867269672706727167272672736727467275672766727767278672796728067281672826728367284672856728667287672886728967290672916729267293672946729567296672976729867299673006730167302673036730467305673066730767308673096731067311673126731367314673156731667317673186731967320673216732267323673246732567326673276732867329673306733167332673336733467335673366733767338673396734067341673426734367344673456734667347673486734967350673516735267353673546735567356673576735867359673606736167362673636736467365673666736767368673696737067371673726737367374673756737667377673786737967380673816738267383673846738567386673876738867389673906739167392673936739467395673966739767398673996740067401674026740367404674056740667407674086740967410674116741267413674146741567416674176741867419674206742167422674236742467425674266742767428674296743067431674326743367434674356743667437674386743967440674416744267443674446744567446674476744867449674506745167452674536745467455674566745767458674596746067461674626746367464674656746667467674686746967470674716747267473674746747567476674776747867479674806748167482674836748467485674866748767488674896749067491674926749367494674956749667497674986749967500675016750267503675046750567506675076750867509675106751167512675136751467515675166751767518675196752067521675226752367524675256752667527675286752967530675316753267533675346753567536675376753867539675406754167542675436754467545675466754767548675496755067551675526755367554675556755667557675586755967560675616756267563675646756567566675676756867569675706757167572675736757467575675766757767578675796758067581675826758367584675856758667587675886758967590675916759267593675946759567596675976759867599676006760167602676036760467605676066760767608676096761067611676126761367614676156761667617676186761967620676216762267623676246762567626676276762867629676306763167632676336763467635676366763767638676396764067641676426764367644676456764667647676486764967650676516765267653676546765567656676576765867659676606766167662676636766467665676666766767668676696767067671676726767367674676756767667677676786767967680676816768267683676846768567686676876768867689676906769167692676936769467695676966769767698676996770067701677026770367704677056770667707677086770967710677116771267713677146771567716677176771867719677206772167722677236772467725677266772767728677296773067731677326773367734677356773667737677386773967740677416774267743677446774567746677476774867749677506775167752677536775467755677566775767758677596776067761677626776367764677656776667767677686776967770677716777267773677746777567776677776777867779677806778167782677836778467785677866778767788677896779067791677926779367794677956779667797677986779967800678016780267803678046780567806678076780867809678106781167812678136781467815678166781767818678196782067821678226782367824678256782667827678286782967830678316783267833678346783567836678376783867839678406784167842678436784467845678466784767848678496785067851678526785367854678556785667857678586785967860678616786267863678646786567866678676786867869678706787167872678736787467875678766787767878678796788067881678826788367884678856788667887678886788967890678916789267893678946789567896678976789867899679006790167902679036790467905679066790767908679096791067911679126791367914679156791667917679186791967920679216792267923679246792567926679276792867929679306793167932679336793467935679366793767938679396794067941679426794367944679456794667947679486794967950679516795267953679546795567956679576795867959679606796167962679636796467965679666796767968679696797067971679726797367974679756797667977679786797967980679816798267983679846798567986679876798867989679906799167992679936799467995679966799767998679996800068001680026800368004680056800668007680086800968010680116801268013680146801568016680176801868019680206802168022680236802468025680266802768028680296803068031680326803368034680356803668037680386803968040680416804268043680446804568046680476804868049680506805168052680536805468055680566805768058680596806068061680626806368064680656806668067680686806968070680716807268073680746807568076680776807868079680806808168082680836808468085680866808768088680896809068091680926809368094680956809668097680986809968100681016810268103681046810568106681076810868109681106811168112681136811468115681166811768118681196812068121681226812368124681256812668127681286812968130681316813268133681346813568136681376813868139681406814168142681436814468145681466814768148681496815068151681526815368154681556815668157681586815968160681616816268163681646816568166681676816868169681706817168172681736817468175681766817768178681796818068181681826818368184681856818668187681886818968190681916819268193681946819568196681976819868199682006820168202682036820468205682066820768208682096821068211682126821368214682156821668217682186821968220682216822268223682246822568226682276822868229682306823168232682336823468235682366823768238682396824068241682426824368244682456824668247682486824968250682516825268253682546825568256682576825868259682606826168262682636826468265682666826768268682696827068271682726827368274682756827668277682786827968280682816828268283682846828568286682876828868289682906829168292682936829468295682966829768298682996830068301683026830368304683056830668307683086830968310683116831268313683146831568316683176831868319683206832168322683236832468325683266832768328683296833068331683326833368334683356833668337683386833968340683416834268343683446834568346683476834868349683506835168352683536835468355683566835768358683596836068361683626836368364683656836668367683686836968370683716837268373683746837568376683776837868379683806838168382683836838468385683866838768388683896839068391683926839368394683956839668397683986839968400684016840268403684046840568406684076840868409684106841168412684136841468415684166841768418684196842068421684226842368424684256842668427684286842968430684316843268433684346843568436684376843868439684406844168442684436844468445684466844768448684496845068451684526845368454684556845668457684586845968460684616846268463684646846568466684676846868469684706847168472684736847468475684766847768478684796848068481684826848368484684856848668487684886848968490684916849268493684946849568496684976849868499685006850168502685036850468505685066850768508685096851068511685126851368514685156851668517685186851968520685216852268523685246852568526685276852868529685306853168532685336853468535685366853768538685396854068541685426854368544685456854668547685486854968550685516855268553685546855568556685576855868559685606856168562685636856468565685666856768568685696857068571685726857368574685756857668577685786857968580685816858268583685846858568586685876858868589685906859168592685936859468595685966859768598685996860068601686026860368604686056860668607686086860968610686116861268613686146861568616686176861868619686206862168622686236862468625686266862768628686296863068631686326863368634686356863668637686386863968640686416864268643686446864568646686476864868649686506865168652686536865468655686566865768658686596866068661686626866368664686656866668667686686866968670686716867268673686746867568676686776867868679686806868168682686836868468685686866868768688686896869068691686926869368694686956869668697686986869968700687016870268703687046870568706687076870868709687106871168712687136871468715687166871768718687196872068721687226872368724687256872668727687286872968730687316873268733687346873568736687376873868739687406874168742687436874468745687466874768748687496875068751687526875368754687556875668757687586875968760687616876268763687646876568766687676876868769687706877168772687736877468775687766877768778687796878068781687826878368784687856878668787687886878968790687916879268793687946879568796687976879868799688006880168802688036880468805688066880768808688096881068811688126881368814688156881668817688186881968820688216882268823688246882568826688276882868829688306883168832688336883468835688366883768838688396884068841688426884368844688456884668847688486884968850688516885268853688546885568856688576885868859688606886168862688636886468865688666886768868688696887068871688726887368874688756887668877688786887968880688816888268883688846888568886688876888868889688906889168892688936889468895688966889768898688996890068901689026890368904689056890668907689086890968910689116891268913689146891568916689176891868919689206892168922689236892468925689266892768928689296893068931689326893368934689356893668937689386893968940689416894268943689446894568946689476894868949689506895168952689536895468955689566895768958689596896068961689626896368964689656896668967689686896968970689716897268973689746897568976689776897868979689806898168982689836898468985689866898768988689896899068991689926899368994689956899668997689986899969000690016900269003690046900569006690076900869009690106901169012690136901469015690166901769018690196902069021690226902369024690256902669027690286902969030690316903269033690346903569036690376903869039690406904169042690436904469045690466904769048690496905069051690526905369054690556905669057690586905969060690616906269063690646906569066690676906869069690706907169072690736907469075690766907769078690796908069081690826908369084690856908669087690886908969090690916909269093690946909569096690976909869099691006910169102691036910469105691066910769108691096911069111691126911369114691156911669117691186911969120691216912269123691246912569126691276912869129691306913169132691336913469135691366913769138691396914069141691426914369144691456914669147691486914969150691516915269153691546915569156691576915869159691606916169162691636916469165691666916769168691696917069171691726917369174691756917669177691786917969180691816918269183691846918569186691876918869189691906919169192691936919469195691966919769198691996920069201692026920369204692056920669207692086920969210692116921269213692146921569216692176921869219692206922169222692236922469225692266922769228692296923069231692326923369234692356923669237692386923969240692416924269243692446924569246692476924869249692506925169252692536925469255692566925769258692596926069261692626926369264692656926669267692686926969270692716927269273692746927569276692776927869279692806928169282692836928469285692866928769288692896929069291692926929369294692956929669297692986929969300693016930269303693046930569306693076930869309693106931169312693136931469315693166931769318693196932069321693226932369324693256932669327693286932969330693316933269333693346933569336693376933869339693406934169342693436934469345693466934769348693496935069351693526935369354693556935669357693586935969360693616936269363693646936569366693676936869369693706937169372693736937469375693766937769378693796938069381693826938369384693856938669387693886938969390693916939269393693946939569396693976939869399694006940169402694036940469405694066940769408694096941069411694126941369414694156941669417694186941969420694216942269423694246942569426694276942869429694306943169432694336943469435694366943769438694396944069441694426944369444694456944669447694486944969450694516945269453694546945569456694576945869459694606946169462694636946469465694666946769468694696947069471694726947369474694756947669477694786947969480694816948269483694846948569486694876948869489694906949169492694936949469495694966949769498694996950069501695026950369504695056950669507695086950969510695116951269513695146951569516695176951869519695206952169522695236952469525695266952769528695296953069531695326953369534695356953669537695386953969540695416954269543695446954569546695476954869549695506955169552695536955469555695566955769558695596956069561695626956369564695656956669567695686956969570695716957269573695746957569576695776957869579695806958169582695836958469585695866958769588695896959069591695926959369594695956959669597695986959969600696016960269603696046960569606696076960869609696106961169612696136961469615696166961769618696196962069621696226962369624696256962669627696286962969630696316963269633696346963569636696376963869639696406964169642696436964469645696466964769648696496965069651696526965369654696556965669657696586965969660696616966269663696646966569666696676966869669696706967169672696736967469675696766967769678696796968069681696826968369684696856968669687696886968969690696916969269693696946969569696696976969869699697006970169702697036970469705697066970769708697096971069711697126971369714697156971669717697186971969720697216972269723697246972569726697276972869729697306973169732697336973469735697366973769738697396974069741697426974369744697456974669747697486974969750697516975269753697546975569756697576975869759697606976169762697636976469765697666976769768697696977069771697726977369774697756977669777697786977969780697816978269783697846978569786697876978869789697906979169792697936979469795697966979769798697996980069801698026980369804698056980669807698086980969810698116981269813698146981569816698176981869819698206982169822698236982469825698266982769828698296983069831698326983369834698356983669837698386983969840698416984269843698446984569846698476984869849698506985169852698536985469855698566985769858698596986069861698626986369864698656986669867698686986969870698716987269873698746987569876698776987869879698806988169882698836988469885698866988769888698896989069891698926989369894698956989669897698986989969900699016990269903699046990569906699076990869909699106991169912699136991469915699166991769918699196992069921699226992369924699256992669927699286992969930699316993269933699346993569936699376993869939699406994169942699436994469945699466994769948699496995069951699526995369954699556995669957699586995969960699616996269963699646996569966699676996869969699706997169972699736997469975699766997769978699796998069981699826998369984699856998669987699886998969990699916999269993699946999569996699976999869999700007000170002700037000470005700067000770008700097001070011700127001370014700157001670017700187001970020700217002270023700247002570026700277002870029700307003170032700337003470035700367003770038700397004070041700427004370044700457004670047700487004970050700517005270053700547005570056700577005870059700607006170062700637006470065700667006770068700697007070071700727007370074700757007670077700787007970080700817008270083700847008570086700877008870089700907009170092700937009470095700967009770098700997010070101701027010370104701057010670107701087010970110701117011270113701147011570116701177011870119701207012170122701237012470125701267012770128701297013070131701327013370134701357013670137701387013970140701417014270143701447014570146701477014870149701507015170152701537015470155701567015770158701597016070161701627016370164701657016670167701687016970170701717017270173701747017570176701777017870179701807018170182701837018470185701867018770188701897019070191701927019370194701957019670197701987019970200702017020270203702047020570206702077020870209702107021170212702137021470215702167021770218702197022070221702227022370224702257022670227702287022970230702317023270233702347023570236702377023870239702407024170242702437024470245702467024770248702497025070251702527025370254702557025670257702587025970260702617026270263702647026570266702677026870269702707027170272702737027470275702767027770278702797028070281702827028370284702857028670287702887028970290702917029270293702947029570296702977029870299703007030170302703037030470305703067030770308703097031070311703127031370314703157031670317703187031970320703217032270323703247032570326703277032870329703307033170332703337033470335703367033770338703397034070341703427034370344703457034670347703487034970350703517035270353703547035570356703577035870359703607036170362703637036470365703667036770368703697037070371703727037370374703757037670377703787037970380703817038270383703847038570386703877038870389703907039170392703937039470395703967039770398703997040070401704027040370404704057040670407704087040970410704117041270413704147041570416704177041870419704207042170422704237042470425704267042770428704297043070431704327043370434704357043670437704387043970440704417044270443704447044570446704477044870449704507045170452704537045470455704567045770458704597046070461704627046370464704657046670467704687046970470704717047270473704747047570476704777047870479704807048170482704837048470485704867048770488704897049070491704927049370494704957049670497704987049970500705017050270503705047050570506705077050870509705107051170512705137051470515705167051770518705197052070521705227052370524705257052670527705287052970530705317053270533705347053570536705377053870539705407054170542705437054470545705467054770548705497055070551705527055370554705557055670557705587055970560705617056270563705647056570566705677056870569705707057170572705737057470575705767057770578705797058070581705827058370584705857058670587705887058970590705917059270593705947059570596705977059870599706007060170602706037060470605706067060770608706097061070611706127061370614706157061670617706187061970620706217062270623706247062570626706277062870629706307063170632706337063470635706367063770638706397064070641706427064370644706457064670647706487064970650706517065270653706547065570656706577065870659706607066170662706637066470665706667066770668706697067070671706727067370674706757067670677706787067970680706817068270683706847068570686706877068870689706907069170692706937069470695706967069770698706997070070701707027070370704707057070670707707087070970710707117071270713707147071570716707177071870719707207072170722707237072470725707267072770728707297073070731707327073370734707357073670737707387073970740707417074270743707447074570746707477074870749707507075170752707537075470755707567075770758707597076070761707627076370764707657076670767707687076970770707717077270773707747077570776707777077870779707807078170782707837078470785707867078770788707897079070791707927079370794707957079670797707987079970800708017080270803708047080570806708077080870809708107081170812708137081470815708167081770818708197082070821708227082370824708257082670827708287082970830708317083270833708347083570836708377083870839708407084170842708437084470845708467084770848708497085070851708527085370854708557085670857708587085970860708617086270863708647086570866708677086870869708707087170872708737087470875708767087770878708797088070881708827088370884708857088670887708887088970890708917089270893708947089570896708977089870899709007090170902709037090470905709067090770908709097091070911709127091370914709157091670917709187091970920709217092270923709247092570926709277092870929709307093170932709337093470935709367093770938709397094070941709427094370944709457094670947709487094970950709517095270953709547095570956709577095870959709607096170962709637096470965709667096770968709697097070971709727097370974709757097670977709787097970980709817098270983709847098570986709877098870989709907099170992709937099470995709967099770998709997100071001710027100371004710057100671007710087100971010710117101271013710147101571016710177101871019710207102171022710237102471025710267102771028710297103071031710327103371034710357103671037710387103971040710417104271043710447104571046710477104871049710507105171052710537105471055710567105771058710597106071061710627106371064710657106671067710687106971070710717107271073710747107571076710777107871079710807108171082710837108471085710867108771088710897109071091710927109371094710957109671097710987109971100711017110271103711047110571106711077110871109711107111171112711137111471115711167111771118711197112071121711227112371124711257112671127711287112971130711317113271133711347113571136711377113871139711407114171142711437114471145711467114771148711497115071151711527115371154711557115671157711587115971160711617116271163711647116571166711677116871169711707117171172711737117471175711767117771178711797118071181711827118371184711857118671187711887118971190711917119271193711947119571196711977119871199712007120171202712037120471205712067120771208712097121071211712127121371214712157121671217712187121971220712217122271223712247122571226712277122871229712307123171232712337123471235712367123771238712397124071241712427124371244712457124671247712487124971250712517125271253712547125571256712577125871259712607126171262712637126471265712667126771268712697127071271712727127371274712757127671277712787127971280712817128271283712847128571286712877128871289712907129171292712937129471295712967129771298712997130071301713027130371304713057130671307713087130971310713117131271313713147131571316713177131871319713207132171322713237132471325713267132771328713297133071331713327133371334713357133671337713387133971340713417134271343713447134571346713477134871349713507135171352713537135471355713567135771358713597136071361713627136371364713657136671367713687136971370713717137271373713747137571376713777137871379713807138171382713837138471385713867138771388713897139071391713927139371394713957139671397713987139971400714017140271403714047140571406714077140871409714107141171412714137141471415714167141771418714197142071421714227142371424714257142671427714287142971430714317143271433714347143571436714377143871439714407144171442714437144471445714467144771448714497145071451714527145371454714557145671457714587145971460714617146271463714647146571466714677146871469714707147171472714737147471475714767147771478714797148071481714827148371484714857148671487714887148971490714917149271493714947149571496714977149871499715007150171502715037150471505715067150771508715097151071511715127151371514715157151671517715187151971520715217152271523715247152571526715277152871529715307153171532715337153471535715367153771538715397154071541715427154371544715457154671547715487154971550715517155271553715547155571556715577155871559715607156171562715637156471565715667156771568715697157071571715727157371574715757157671577715787157971580715817158271583715847158571586715877158871589715907159171592715937159471595715967159771598715997160071601716027160371604716057160671607716087160971610716117161271613716147161571616716177161871619716207162171622716237162471625716267162771628716297163071631716327163371634716357163671637716387163971640716417164271643716447164571646716477164871649716507165171652716537165471655716567165771658716597166071661716627166371664716657166671667716687166971670716717167271673716747167571676716777167871679716807168171682716837168471685716867168771688716897169071691716927169371694716957169671697716987169971700717017170271703717047170571706717077170871709717107171171712717137171471715717167171771718717197172071721717227172371724717257172671727717287172971730717317173271733717347173571736717377173871739717407174171742717437174471745717467174771748717497175071751717527175371754717557175671757717587175971760717617176271763717647176571766717677176871769717707177171772717737177471775717767177771778717797178071781717827178371784717857178671787717887178971790717917179271793717947179571796717977179871799718007180171802718037180471805718067180771808718097181071811718127181371814718157181671817718187181971820718217182271823718247182571826718277182871829718307183171832718337183471835718367183771838718397184071841718427184371844718457184671847718487184971850718517185271853718547185571856718577185871859718607186171862718637186471865718667186771868718697187071871718727187371874718757187671877718787187971880718817188271883718847188571886718877188871889718907189171892718937189471895718967189771898718997190071901719027190371904719057190671907719087190971910719117191271913719147191571916719177191871919719207192171922719237192471925719267192771928719297193071931719327193371934719357193671937719387193971940719417194271943719447194571946719477194871949719507195171952719537195471955719567195771958719597196071961719627196371964719657196671967719687196971970719717197271973719747197571976719777197871979719807198171982719837198471985719867198771988719897199071991719927199371994719957199671997719987199972000720017200272003720047200572006720077200872009720107201172012720137201472015720167201772018720197202072021720227202372024720257202672027720287202972030720317203272033720347203572036720377203872039720407204172042720437204472045720467204772048720497205072051720527205372054720557205672057720587205972060720617206272063720647206572066720677206872069720707207172072720737207472075720767207772078720797208072081720827208372084720857208672087720887208972090720917209272093720947209572096720977209872099721007210172102721037210472105721067210772108721097211072111721127211372114721157211672117721187211972120721217212272123721247212572126721277212872129721307213172132721337213472135721367213772138721397214072141721427214372144721457214672147721487214972150721517215272153721547215572156721577215872159721607216172162721637216472165721667216772168721697217072171721727217372174721757217672177721787217972180721817218272183721847218572186721877218872189721907219172192721937219472195721967219772198721997220072201722027220372204722057220672207722087220972210722117221272213722147221572216722177221872219722207222172222722237222472225722267222772228722297223072231722327223372234722357223672237722387223972240722417224272243722447224572246722477224872249722507225172252722537225472255722567225772258722597226072261722627226372264722657226672267722687226972270722717227272273722747227572276722777227872279722807228172282722837228472285722867228772288722897229072291722927229372294722957229672297722987229972300723017230272303723047230572306723077230872309723107231172312723137231472315723167231772318723197232072321723227232372324723257232672327723287232972330723317233272333723347233572336723377233872339723407234172342723437234472345723467234772348723497235072351723527235372354723557235672357723587235972360723617236272363723647236572366723677236872369723707237172372723737237472375723767237772378723797238072381723827238372384723857238672387723887238972390723917239272393723947239572396723977239872399724007240172402724037240472405724067240772408724097241072411724127241372414724157241672417724187241972420724217242272423724247242572426724277242872429724307243172432724337243472435724367243772438724397244072441724427244372444724457244672447724487244972450724517245272453724547245572456724577245872459724607246172462724637246472465724667246772468724697247072471724727247372474724757247672477724787247972480724817248272483724847248572486724877248872489724907249172492724937249472495724967249772498724997250072501725027250372504725057250672507725087250972510725117251272513725147251572516725177251872519725207252172522725237252472525725267252772528725297253072531725327253372534725357253672537725387253972540725417254272543725447254572546725477254872549725507255172552725537255472555725567255772558725597256072561725627256372564725657256672567725687256972570725717257272573725747257572576725777257872579725807258172582725837258472585725867258772588725897259072591725927259372594725957259672597725987259972600726017260272603726047260572606726077260872609726107261172612726137261472615726167261772618726197262072621726227262372624726257262672627726287262972630726317263272633726347263572636726377263872639726407264172642726437264472645726467264772648726497265072651726527265372654726557265672657726587265972660726617266272663726647266572666726677266872669726707267172672726737267472675726767267772678726797268072681726827268372684726857268672687726887268972690726917269272693726947269572696726977269872699727007270172702727037270472705727067270772708727097271072711727127271372714727157271672717727187271972720727217272272723727247272572726727277272872729727307273172732727337273472735727367273772738727397274072741727427274372744727457274672747727487274972750727517275272753727547275572756727577275872759727607276172762727637276472765727667276772768727697277072771727727277372774727757277672777727787277972780727817278272783727847278572786727877278872789727907279172792727937279472795727967279772798727997280072801728027280372804728057280672807728087280972810728117281272813728147281572816728177281872819728207282172822728237282472825728267282772828728297283072831728327283372834728357283672837728387283972840728417284272843728447284572846728477284872849728507285172852728537285472855728567285772858728597286072861728627286372864728657286672867728687286972870728717287272873728747287572876728777287872879728807288172882728837288472885728867288772888728897289072891728927289372894728957289672897728987289972900729017290272903729047290572906729077290872909729107291172912729137291472915729167291772918729197292072921729227292372924729257292672927729287292972930729317293272933729347293572936729377293872939729407294172942729437294472945729467294772948729497295072951729527295372954729557295672957729587295972960729617296272963729647296572966729677296872969729707297172972729737297472975729767297772978729797298072981729827298372984729857298672987729887298972990729917299272993729947299572996729977299872999730007300173002730037300473005730067300773008730097301073011730127301373014730157301673017730187301973020730217302273023730247302573026730277302873029730307303173032730337303473035730367303773038730397304073041730427304373044730457304673047730487304973050730517305273053730547305573056730577305873059730607306173062730637306473065730667306773068730697307073071730727307373074730757307673077730787307973080730817308273083730847308573086730877308873089730907309173092730937309473095730967309773098730997310073101731027310373104731057310673107731087310973110731117311273113731147311573116731177311873119731207312173122731237312473125731267312773128731297313073131731327313373134731357313673137731387313973140731417314273143731447314573146731477314873149731507315173152731537315473155731567315773158731597316073161731627316373164731657316673167731687316973170731717317273173731747317573176731777317873179731807318173182731837318473185731867318773188731897319073191731927319373194731957319673197731987319973200732017320273203732047320573206732077320873209732107321173212732137321473215732167321773218732197322073221732227322373224732257322673227732287322973230732317323273233732347323573236732377323873239732407324173242732437324473245732467324773248732497325073251732527325373254732557325673257732587325973260732617326273263732647326573266732677326873269732707327173272732737327473275732767327773278732797328073281732827328373284732857328673287732887328973290732917329273293732947329573296732977329873299733007330173302733037330473305733067330773308733097331073311733127331373314733157331673317733187331973320733217332273323733247332573326733277332873329733307333173332733337333473335733367333773338733397334073341733427334373344733457334673347733487334973350733517335273353733547335573356733577335873359733607336173362733637336473365733667336773368733697337073371733727337373374733757337673377733787337973380733817338273383733847338573386733877338873389733907339173392733937339473395733967339773398733997340073401734027340373404734057340673407734087340973410734117341273413734147341573416734177341873419734207342173422734237342473425734267342773428734297343073431734327343373434734357343673437734387343973440734417344273443734447344573446734477344873449734507345173452734537345473455734567345773458734597346073461734627346373464734657346673467734687346973470734717347273473734747347573476734777347873479734807348173482734837348473485734867348773488734897349073491734927349373494734957349673497734987349973500735017350273503735047350573506735077350873509735107351173512735137351473515735167351773518735197352073521735227352373524735257352673527735287352973530735317353273533735347353573536735377353873539735407354173542735437354473545735467354773548735497355073551735527355373554735557355673557735587355973560735617356273563735647356573566735677356873569735707357173572735737357473575735767357773578735797358073581735827358373584735857358673587735887358973590735917359273593735947359573596735977359873599736007360173602736037360473605736067360773608736097361073611736127361373614736157361673617736187361973620736217362273623736247362573626736277362873629736307363173632736337363473635736367363773638736397364073641736427364373644736457364673647736487364973650736517365273653736547365573656736577365873659736607366173662736637366473665736667366773668736697367073671736727367373674736757367673677736787367973680736817368273683736847368573686736877368873689736907369173692736937369473695736967369773698736997370073701737027370373704737057370673707737087370973710737117371273713737147371573716737177371873719737207372173722737237372473725737267372773728737297373073731737327373373734737357373673737737387373973740737417374273743737447374573746737477374873749737507375173752737537375473755737567375773758737597376073761737627376373764737657376673767737687376973770737717377273773737747377573776737777377873779737807378173782737837378473785737867378773788737897379073791737927379373794737957379673797737987379973800738017380273803738047380573806738077380873809738107381173812738137381473815738167381773818738197382073821738227382373824738257382673827738287382973830738317383273833738347383573836738377383873839738407384173842738437384473845738467384773848738497385073851738527385373854738557385673857738587385973860738617386273863738647386573866738677386873869738707387173872738737387473875738767387773878738797388073881738827388373884738857388673887738887388973890738917389273893738947389573896738977389873899739007390173902739037390473905739067390773908739097391073911739127391373914739157391673917739187391973920739217392273923739247392573926739277392873929739307393173932739337393473935739367393773938739397394073941739427394373944739457394673947739487394973950739517395273953739547395573956739577395873959739607396173962739637396473965739667396773968739697397073971739727397373974739757397673977739787397973980739817398273983739847398573986739877398873989739907399173992739937399473995739967399773998739997400074001740027400374004740057400674007740087400974010740117401274013740147401574016740177401874019740207402174022740237402474025740267402774028740297403074031740327403374034740357403674037740387403974040740417404274043740447404574046740477404874049740507405174052740537405474055740567405774058740597406074061740627406374064740657406674067740687406974070740717407274073740747407574076740777407874079740807408174082740837408474085740867408774088740897409074091740927409374094740957409674097740987409974100741017410274103741047410574106741077410874109741107411174112741137411474115741167411774118741197412074121741227412374124741257412674127741287412974130741317413274133741347413574136741377413874139741407414174142741437414474145741467414774148741497415074151741527415374154741557415674157741587415974160741617416274163741647416574166741677416874169741707417174172741737417474175741767417774178741797418074181741827418374184741857418674187741887418974190741917419274193741947419574196741977419874199742007420174202742037420474205742067420774208742097421074211742127421374214742157421674217742187421974220742217422274223742247422574226742277422874229742307423174232742337423474235742367423774238742397424074241742427424374244742457424674247742487424974250742517425274253742547425574256742577425874259742607426174262742637426474265742667426774268742697427074271742727427374274742757427674277742787427974280742817428274283742847428574286742877428874289742907429174292742937429474295742967429774298742997430074301743027430374304743057430674307743087430974310743117431274313743147431574316743177431874319743207432174322743237432474325743267432774328743297433074331743327433374334743357433674337743387433974340743417434274343743447434574346743477434874349743507435174352743537435474355743567435774358743597436074361743627436374364743657436674367743687436974370743717437274373743747437574376743777437874379743807438174382743837438474385743867438774388743897439074391743927439374394743957439674397743987439974400744017440274403744047440574406744077440874409744107441174412744137441474415744167441774418744197442074421744227442374424744257442674427744287442974430744317443274433744347443574436744377443874439744407444174442744437444474445744467444774448744497445074451744527445374454744557445674457744587445974460744617446274463744647446574466744677446874469744707447174472744737447474475744767447774478744797448074481744827448374484744857448674487744887448974490744917449274493744947449574496744977449874499745007450174502745037450474505745067450774508745097451074511745127451374514745157451674517745187451974520745217452274523745247452574526745277452874529745307453174532745337453474535745367453774538745397454074541745427454374544745457454674547745487454974550745517455274553745547455574556745577455874559745607456174562745637456474565745667456774568745697457074571745727457374574745757457674577745787457974580745817458274583745847458574586745877458874589745907459174592745937459474595745967459774598745997460074601746027460374604746057460674607746087460974610746117461274613746147461574616746177461874619746207462174622746237462474625746267462774628746297463074631746327463374634746357463674637746387463974640746417464274643746447464574646746477464874649746507465174652746537465474655746567465774658746597466074661746627466374664746657466674667746687466974670746717467274673746747467574676746777467874679746807468174682746837468474685746867468774688746897469074691746927469374694746957469674697746987469974700747017470274703747047470574706747077470874709747107471174712747137471474715747167471774718747197472074721747227472374724747257472674727747287472974730747317473274733747347473574736747377473874739747407474174742747437474474745747467474774748747497475074751747527475374754747557475674757747587475974760747617476274763747647476574766747677476874769747707477174772747737477474775747767477774778747797478074781747827478374784747857478674787747887478974790747917479274793747947479574796747977479874799748007480174802748037480474805748067480774808748097481074811748127481374814748157481674817748187481974820748217482274823748247482574826748277482874829748307483174832748337483474835748367483774838748397484074841748427484374844748457484674847748487484974850748517485274853748547485574856748577485874859748607486174862748637486474865748667486774868748697487074871748727487374874748757487674877748787487974880748817488274883748847488574886748877488874889748907489174892748937489474895748967489774898748997490074901749027490374904749057490674907749087490974910749117491274913749147491574916749177491874919749207492174922749237492474925749267492774928749297493074931749327493374934749357493674937749387493974940749417494274943749447494574946749477494874949749507495174952749537495474955749567495774958749597496074961749627496374964749657496674967749687496974970749717497274973749747497574976749777497874979749807498174982749837498474985749867498774988749897499074991749927499374994749957499674997749987499975000750017500275003750047500575006750077500875009750107501175012750137501475015750167501775018750197502075021750227502375024750257502675027750287502975030750317503275033750347503575036750377503875039750407504175042750437504475045750467504775048750497505075051750527505375054750557505675057750587505975060750617506275063750647506575066750677506875069750707507175072750737507475075750767507775078750797508075081750827508375084750857508675087750887508975090750917509275093750947509575096750977509875099751007510175102751037510475105751067510775108751097511075111751127511375114751157511675117751187511975120751217512275123751247512575126751277512875129751307513175132751337513475135751367513775138751397514075141751427514375144751457514675147751487514975150751517515275153751547515575156751577515875159751607516175162751637516475165751667516775168751697517075171751727517375174751757517675177751787517975180751817518275183751847518575186751877518875189751907519175192751937519475195751967519775198751997520075201752027520375204752057520675207752087520975210752117521275213752147521575216752177521875219752207522175222752237522475225752267522775228752297523075231752327523375234752357523675237752387523975240752417524275243752447524575246752477524875249752507525175252752537525475255752567525775258752597526075261752627526375264752657526675267752687526975270752717527275273752747527575276752777527875279752807528175282752837528475285752867528775288752897529075291752927529375294752957529675297752987529975300753017530275303753047530575306753077530875309753107531175312753137531475315753167531775318753197532075321753227532375324753257532675327753287532975330753317533275333753347533575336753377533875339753407534175342753437534475345753467534775348753497535075351753527535375354753557535675357753587535975360753617536275363753647536575366753677536875369753707537175372753737537475375753767537775378753797538075381753827538375384753857538675387753887538975390753917539275393753947539575396753977539875399754007540175402754037540475405754067540775408754097541075411754127541375414754157541675417754187541975420754217542275423754247542575426754277542875429754307543175432754337543475435754367543775438754397544075441754427544375444754457544675447754487544975450754517545275453754547545575456754577545875459754607546175462754637546475465754667546775468754697547075471754727547375474754757547675477754787547975480754817548275483754847548575486754877548875489754907549175492754937549475495754967549775498754997550075501755027550375504755057550675507755087550975510755117551275513755147551575516755177551875519755207552175522755237552475525755267552775528755297553075531755327553375534755357553675537755387553975540755417554275543755447554575546755477554875549755507555175552755537555475555755567555775558755597556075561755627556375564755657556675567755687556975570755717557275573755747557575576755777557875579755807558175582755837558475585755867558775588755897559075591755927559375594755957559675597755987559975600756017560275603756047560575606756077560875609756107561175612756137561475615756167561775618756197562075621756227562375624756257562675627756287562975630756317563275633756347563575636756377563875639756407564175642756437564475645756467564775648756497565075651756527565375654756557565675657756587565975660756617566275663756647566575666756677566875669756707567175672756737567475675756767567775678756797568075681756827568375684756857568675687756887568975690756917569275693756947569575696756977569875699757007570175702757037570475705757067570775708757097571075711757127571375714757157571675717757187571975720757217572275723757247572575726757277572875729757307573175732757337573475735757367573775738757397574075741757427574375744757457574675747757487574975750757517575275753757547575575756757577575875759757607576175762757637576475765757667576775768757697577075771757727577375774757757577675777757787577975780757817578275783757847578575786757877578875789757907579175792757937579475795757967579775798757997580075801758027580375804758057580675807758087580975810758117581275813758147581575816758177581875819758207582175822758237582475825758267582775828758297583075831758327583375834758357583675837758387583975840758417584275843758447584575846758477584875849758507585175852758537585475855758567585775858758597586075861758627586375864758657586675867758687586975870758717587275873758747587575876758777587875879758807588175882758837588475885758867588775888758897589075891758927589375894758957589675897758987589975900759017590275903759047590575906759077590875909759107591175912759137591475915759167591775918759197592075921759227592375924759257592675927759287592975930759317593275933759347593575936759377593875939759407594175942759437594475945759467594775948759497595075951759527595375954759557595675957759587595975960759617596275963759647596575966759677596875969759707597175972759737597475975759767597775978759797598075981759827598375984759857598675987759887598975990759917599275993759947599575996759977599875999760007600176002760037600476005760067600776008760097601076011760127601376014760157601676017760187601976020760217602276023760247602576026760277602876029760307603176032760337603476035760367603776038760397604076041760427604376044760457604676047760487604976050760517605276053760547605576056760577605876059760607606176062760637606476065760667606776068760697607076071760727607376074760757607676077760787607976080760817608276083760847608576086760877608876089760907609176092760937609476095760967609776098760997610076101761027610376104761057610676107761087610976110761117611276113761147611576116761177611876119761207612176122761237612476125761267612776128761297613076131761327613376134761357613676137761387613976140761417614276143761447614576146761477614876149761507615176152761537615476155761567615776158761597616076161761627616376164761657616676167761687616976170761717617276173761747617576176761777617876179761807618176182761837618476185761867618776188761897619076191761927619376194761957619676197761987619976200762017620276203762047620576206762077620876209762107621176212762137621476215762167621776218762197622076221762227622376224762257622676227762287622976230762317623276233762347623576236762377623876239762407624176242762437624476245762467624776248762497625076251762527625376254762557625676257762587625976260762617626276263762647626576266762677626876269762707627176272762737627476275762767627776278762797628076281762827628376284762857628676287762887628976290762917629276293762947629576296762977629876299763007630176302763037630476305763067630776308763097631076311763127631376314763157631676317763187631976320763217632276323763247632576326763277632876329763307633176332763337633476335763367633776338763397634076341763427634376344763457634676347763487634976350763517635276353763547635576356763577635876359763607636176362763637636476365763667636776368763697637076371763727637376374763757637676377763787637976380763817638276383763847638576386763877638876389763907639176392763937639476395763967639776398763997640076401764027640376404764057640676407764087640976410764117641276413764147641576416764177641876419764207642176422764237642476425764267642776428764297643076431764327643376434764357643676437764387643976440764417644276443764447644576446764477644876449764507645176452764537645476455764567645776458764597646076461764627646376464764657646676467764687646976470764717647276473764747647576476764777647876479764807648176482764837648476485764867648776488764897649076491764927649376494764957649676497764987649976500765017650276503765047650576506765077650876509765107651176512765137651476515765167651776518765197652076521765227652376524765257652676527765287652976530765317653276533765347653576536765377653876539765407654176542765437654476545765467654776548765497655076551765527655376554765557655676557765587655976560765617656276563765647656576566765677656876569765707657176572765737657476575765767657776578765797658076581765827658376584765857658676587765887658976590765917659276593765947659576596765977659876599766007660176602766037660476605766067660776608766097661076611766127661376614766157661676617766187661976620766217662276623766247662576626766277662876629766307663176632766337663476635766367663776638766397664076641766427664376644766457664676647766487664976650766517665276653766547665576656766577665876659766607666176662766637666476665766667666776668766697667076671766727667376674766757667676677766787667976680766817668276683766847668576686766877668876689766907669176692766937669476695766967669776698766997670076701767027670376704767057670676707767087670976710767117671276713767147671576716767177671876719767207672176722767237672476725767267672776728767297673076731767327673376734767357673676737767387673976740767417674276743767447674576746767477674876749767507675176752767537675476755767567675776758767597676076761767627676376764767657676676767767687676976770767717677276773767747677576776767777677876779767807678176782767837678476785767867678776788767897679076791767927679376794767957679676797767987679976800768017680276803768047680576806768077680876809768107681176812768137681476815768167681776818768197682076821768227682376824768257682676827768287682976830768317683276833768347683576836768377683876839768407684176842768437684476845768467684776848768497685076851768527685376854768557685676857768587685976860768617686276863768647686576866768677686876869768707687176872768737687476875768767687776878768797688076881768827688376884768857688676887768887688976890768917689276893768947689576896768977689876899769007690176902769037690476905769067690776908769097691076911769127691376914769157691676917769187691976920769217692276923769247692576926769277692876929769307693176932769337693476935769367693776938769397694076941769427694376944769457694676947769487694976950769517695276953769547695576956769577695876959769607696176962769637696476965769667696776968769697697076971769727697376974769757697676977769787697976980769817698276983769847698576986769877698876989769907699176992769937699476995769967699776998769997700077001770027700377004770057700677007770087700977010770117701277013770147701577016770177701877019770207702177022770237702477025770267702777028770297703077031770327703377034770357703677037770387703977040770417704277043770447704577046770477704877049770507705177052770537705477055770567705777058770597706077061770627706377064770657706677067770687706977070770717707277073770747707577076770777707877079770807708177082770837708477085770867708777088770897709077091770927709377094770957709677097770987709977100771017710277103771047710577106771077710877109771107711177112771137711477115771167711777118771197712077121771227712377124771257712677127771287712977130771317713277133771347713577136771377713877139771407714177142771437714477145771467714777148771497715077151771527715377154771557715677157771587715977160771617716277163771647716577166771677716877169771707717177172771737717477175771767717777178771797718077181771827718377184771857718677187771887718977190771917719277193771947719577196771977719877199772007720177202772037720477205772067720777208772097721077211772127721377214772157721677217772187721977220772217722277223772247722577226772277722877229772307723177232772337723477235772367723777238772397724077241772427724377244772457724677247772487724977250772517725277253772547725577256772577725877259772607726177262772637726477265772667726777268772697727077271772727727377274772757727677277772787727977280772817728277283772847728577286772877728877289772907729177292772937729477295772967729777298772997730077301773027730377304773057730677307773087730977310773117731277313773147731577316773177731877319773207732177322773237732477325773267732777328773297733077331773327733377334773357733677337773387733977340773417734277343773447734577346773477734877349773507735177352773537735477355773567735777358773597736077361773627736377364773657736677367773687736977370773717737277373773747737577376773777737877379773807738177382773837738477385773867738777388773897739077391773927739377394773957739677397773987739977400774017740277403774047740577406774077740877409774107741177412774137741477415774167741777418774197742077421774227742377424774257742677427774287742977430774317743277433774347743577436774377743877439774407744177442774437744477445774467744777448774497745077451774527745377454774557745677457774587745977460774617746277463774647746577466774677746877469774707747177472774737747477475774767747777478774797748077481774827748377484774857748677487774887748977490774917749277493774947749577496774977749877499775007750177502775037750477505775067750777508775097751077511775127751377514775157751677517775187751977520775217752277523775247752577526775277752877529775307753177532775337753477535775367753777538775397754077541775427754377544775457754677547775487754977550775517755277553775547755577556775577755877559775607756177562775637756477565775667756777568775697757077571775727757377574775757757677577775787757977580775817758277583775847758577586775877758877589775907759177592775937759477595775967759777598775997760077601776027760377604776057760677607776087760977610776117761277613776147761577616776177761877619776207762177622776237762477625776267762777628776297763077631776327763377634776357763677637776387763977640776417764277643776447764577646776477764877649776507765177652776537765477655776567765777658776597766077661776627766377664776657766677667776687766977670776717767277673776747767577676776777767877679776807768177682776837768477685776867768777688776897769077691776927769377694776957769677697776987769977700777017770277703777047770577706777077770877709777107771177712777137771477715777167771777718777197772077721777227772377724777257772677727777287772977730777317773277733777347773577736777377773877739777407774177742777437774477745777467774777748777497775077751777527775377754777557775677757777587775977760777617776277763777647776577766777677776877769777707777177772777737777477775777767777777778777797778077781777827778377784777857778677787777887778977790777917779277793777947779577796777977779877799778007780177802778037780477805778067780777808778097781077811778127781377814778157781677817778187781977820778217782277823778247782577826778277782877829778307783177832778337783477835778367783777838778397784077841778427784377844778457784677847778487784977850778517785277853778547785577856778577785877859778607786177862778637786477865778667786777868778697787077871778727787377874778757787677877778787787977880778817788277883778847788577886778877788877889778907789177892778937789477895778967789777898778997790077901779027790377904779057790677907779087790977910779117791277913779147791577916779177791877919779207792177922779237792477925779267792777928779297793077931779327793377934779357793677937779387793977940779417794277943779447794577946779477794877949779507795177952779537795477955779567795777958779597796077961779627796377964779657796677967779687796977970779717797277973779747797577976779777797877979779807798177982779837798477985779867798777988779897799077991779927799377994779957799677997779987799978000780017800278003780047800578006780077800878009780107801178012780137801478015780167801778018780197802078021780227802378024780257802678027780287802978030780317803278033780347803578036780377803878039780407804178042780437804478045780467804778048780497805078051780527805378054780557805678057780587805978060780617806278063780647806578066780677806878069780707807178072780737807478075780767807778078780797808078081780827808378084780857808678087780887808978090780917809278093780947809578096780977809878099781007810178102781037810478105781067810778108781097811078111781127811378114781157811678117781187811978120781217812278123781247812578126781277812878129781307813178132781337813478135781367813778138781397814078141781427814378144781457814678147781487814978150781517815278153781547815578156781577815878159781607816178162781637816478165781667816778168781697817078171781727817378174781757817678177781787817978180781817818278183781847818578186781877818878189781907819178192781937819478195781967819778198781997820078201782027820378204782057820678207782087820978210782117821278213782147821578216782177821878219782207822178222782237822478225782267822778228782297823078231782327823378234782357823678237782387823978240782417824278243782447824578246782477824878249782507825178252782537825478255782567825778258782597826078261782627826378264782657826678267782687826978270782717827278273782747827578276782777827878279782807828178282782837828478285782867828778288782897829078291782927829378294782957829678297782987829978300783017830278303783047830578306783077830878309783107831178312783137831478315783167831778318783197832078321783227832378324783257832678327783287832978330783317833278333783347833578336783377833878339783407834178342783437834478345783467834778348783497835078351783527835378354783557835678357783587835978360783617836278363783647836578366783677836878369783707837178372783737837478375783767837778378783797838078381783827838378384783857838678387783887838978390783917839278393783947839578396783977839878399784007840178402784037840478405784067840778408784097841078411784127841378414784157841678417784187841978420784217842278423784247842578426784277842878429784307843178432784337843478435784367843778438784397844078441784427844378444784457844678447784487844978450784517845278453784547845578456784577845878459784607846178462784637846478465784667846778468784697847078471784727847378474784757847678477784787847978480784817848278483784847848578486784877848878489784907849178492784937849478495784967849778498784997850078501785027850378504785057850678507785087850978510785117851278513785147851578516785177851878519785207852178522785237852478525785267852778528785297853078531785327853378534785357853678537785387853978540785417854278543785447854578546785477854878549785507855178552785537855478555785567855778558785597856078561785627856378564785657856678567785687856978570785717857278573785747857578576785777857878579785807858178582785837858478585785867858778588785897859078591785927859378594785957859678597785987859978600786017860278603786047860578606786077860878609786107861178612786137861478615786167861778618786197862078621786227862378624786257862678627786287862978630786317863278633786347863578636786377863878639786407864178642786437864478645786467864778648786497865078651786527865378654786557865678657786587865978660786617866278663786647866578666786677866878669786707867178672786737867478675786767867778678786797868078681786827868378684786857868678687786887868978690786917869278693786947869578696786977869878699787007870178702787037870478705787067870778708787097871078711787127871378714787157871678717787187871978720787217872278723787247872578726787277872878729787307873178732787337873478735787367873778738787397874078741787427874378744787457874678747787487874978750787517875278753787547875578756787577875878759787607876178762787637876478765787667876778768787697877078771787727877378774787757877678777787787877978780787817878278783787847878578786787877878878789787907879178792787937879478795787967879778798787997880078801788027880378804788057880678807788087880978810788117881278813788147881578816788177881878819788207882178822788237882478825788267882778828788297883078831788327883378834788357883678837788387883978840788417884278843788447884578846788477884878849788507885178852788537885478855788567885778858788597886078861788627886378864788657886678867788687886978870788717887278873788747887578876788777887878879788807888178882788837888478885788867888778888788897889078891788927889378894788957889678897788987889978900789017890278903789047890578906789077890878909789107891178912789137891478915789167891778918789197892078921789227892378924789257892678927789287892978930789317893278933789347893578936789377893878939789407894178942789437894478945789467894778948789497895078951789527895378954789557895678957789587895978960789617896278963789647896578966789677896878969789707897178972789737897478975789767897778978789797898078981789827898378984789857898678987789887898978990789917899278993789947899578996789977899878999790007900179002790037900479005790067900779008790097901079011790127901379014790157901679017790187901979020790217902279023790247902579026790277902879029790307903179032790337903479035790367903779038790397904079041790427904379044790457904679047790487904979050790517905279053790547905579056790577905879059790607906179062790637906479065790667906779068790697907079071790727907379074790757907679077790787907979080790817908279083790847908579086790877908879089790907909179092790937909479095790967909779098790997910079101791027910379104791057910679107791087910979110791117911279113791147911579116791177911879119791207912179122791237912479125791267912779128791297913079131791327913379134791357913679137791387913979140791417914279143791447914579146791477914879149791507915179152791537915479155791567915779158791597916079161791627916379164791657916679167791687916979170791717917279173791747917579176791777917879179791807918179182791837918479185791867918779188791897919079191791927919379194791957919679197791987919979200792017920279203792047920579206792077920879209792107921179212792137921479215792167921779218792197922079221792227922379224792257922679227792287922979230792317923279233792347923579236792377923879239792407924179242792437924479245792467924779248792497925079251792527925379254792557925679257792587925979260792617926279263792647926579266792677926879269792707927179272792737927479275792767927779278792797928079281792827928379284792857928679287792887928979290792917929279293792947929579296792977929879299793007930179302793037930479305793067930779308793097931079311793127931379314793157931679317793187931979320793217932279323793247932579326793277932879329793307933179332793337933479335793367933779338793397934079341793427934379344793457934679347793487934979350793517935279353793547935579356793577935879359793607936179362793637936479365793667936779368793697937079371793727937379374793757937679377793787937979380793817938279383793847938579386793877938879389793907939179392793937939479395793967939779398793997940079401794027940379404794057940679407794087940979410794117941279413794147941579416794177941879419794207942179422794237942479425794267942779428794297943079431794327943379434794357943679437794387943979440794417944279443794447944579446794477944879449794507945179452794537945479455794567945779458794597946079461794627946379464794657946679467794687946979470794717947279473794747947579476794777947879479794807948179482794837948479485794867948779488794897949079491794927949379494794957949679497794987949979500795017950279503795047950579506795077950879509795107951179512795137951479515795167951779518795197952079521795227952379524795257952679527795287952979530795317953279533795347953579536795377953879539795407954179542795437954479545795467954779548795497955079551795527955379554795557955679557795587955979560795617956279563795647956579566795677956879569795707957179572795737957479575795767957779578795797958079581795827958379584795857958679587795887958979590795917959279593795947959579596795977959879599796007960179602796037960479605796067960779608796097961079611796127961379614796157961679617796187961979620796217962279623796247962579626796277962879629796307963179632796337963479635796367963779638796397964079641796427964379644796457964679647796487964979650796517965279653796547965579656796577965879659796607966179662796637966479665796667966779668796697967079671796727967379674796757967679677796787967979680796817968279683796847968579686796877968879689796907969179692796937969479695796967969779698796997970079701797027970379704797057970679707797087970979710797117971279713797147971579716797177971879719797207972179722797237972479725797267972779728797297973079731797327973379734797357973679737797387973979740797417974279743797447974579746797477974879749797507975179752797537975479755797567975779758797597976079761797627976379764797657976679767797687976979770797717977279773797747977579776797777977879779797807978179782797837978479785797867978779788797897979079791797927979379794797957979679797797987979979800798017980279803798047980579806798077980879809798107981179812798137981479815798167981779818798197982079821798227982379824798257982679827798287982979830798317983279833798347983579836798377983879839798407984179842798437984479845798467984779848798497985079851798527985379854798557985679857798587985979860798617986279863798647986579866798677986879869798707987179872798737987479875798767987779878798797988079881798827988379884798857988679887798887988979890798917989279893798947989579896798977989879899799007990179902799037990479905799067990779908799097991079911799127991379914799157991679917799187991979920799217992279923799247992579926799277992879929799307993179932799337993479935799367993779938799397994079941799427994379944799457994679947799487994979950799517995279953799547995579956799577995879959799607996179962799637996479965799667996779968799697997079971799727997379974799757997679977799787997979980799817998279983799847998579986799877998879989799907999179992799937999479995799967999779998799998000080001800028000380004800058000680007800088000980010800118001280013800148001580016800178001880019800208002180022800238002480025800268002780028800298003080031800328003380034800358003680037800388003980040800418004280043800448004580046800478004880049800508005180052800538005480055800568005780058800598006080061800628006380064800658006680067800688006980070800718007280073800748007580076800778007880079800808008180082800838008480085800868008780088800898009080091800928009380094800958009680097800988009980100801018010280103801048010580106801078010880109801108011180112801138011480115801168011780118801198012080121801228012380124801258012680127801288012980130801318013280133801348013580136801378013880139801408014180142801438014480145801468014780148801498015080151801528015380154801558015680157801588015980160801618016280163801648016580166801678016880169801708017180172801738017480175801768017780178801798018080181801828018380184801858018680187801888018980190801918019280193801948019580196801978019880199802008020180202802038020480205802068020780208802098021080211802128021380214802158021680217802188021980220802218022280223802248022580226802278022880229802308023180232802338023480235802368023780238802398024080241802428024380244802458024680247802488024980250802518025280253802548025580256802578025880259802608026180262802638026480265802668026780268802698027080271802728027380274802758027680277802788027980280802818028280283802848028580286802878028880289802908029180292802938029480295802968029780298802998030080301803028030380304803058030680307803088030980310803118031280313803148031580316803178031880319803208032180322803238032480325803268032780328803298033080331803328033380334803358033680337803388033980340803418034280343803448034580346803478034880349803508035180352803538035480355803568035780358803598036080361803628036380364803658036680367803688036980370803718037280373803748037580376803778037880379803808038180382803838038480385803868038780388803898039080391803928039380394803958039680397803988039980400804018040280403804048040580406804078040880409804108041180412804138041480415804168041780418804198042080421804228042380424804258042680427804288042980430804318043280433804348043580436804378043880439804408044180442804438044480445804468044780448804498045080451804528045380454804558045680457804588045980460804618046280463804648046580466804678046880469804708047180472804738047480475804768047780478804798048080481804828048380484804858048680487804888048980490804918049280493804948049580496804978049880499805008050180502805038050480505805068050780508805098051080511805128051380514805158051680517805188051980520805218052280523805248052580526805278052880529805308053180532805338053480535805368053780538805398054080541805428054380544805458054680547805488054980550805518055280553805548055580556805578055880559805608056180562805638056480565805668056780568805698057080571805728057380574805758057680577805788057980580805818058280583805848058580586805878058880589805908059180592805938059480595805968059780598805998060080601806028060380604806058060680607806088060980610806118061280613806148061580616806178061880619806208062180622806238062480625806268062780628806298063080631806328063380634806358063680637806388063980640806418064280643806448064580646806478064880649806508065180652806538065480655806568065780658806598066080661806628066380664806658066680667806688066980670806718067280673806748067580676806778067880679806808068180682806838068480685806868068780688806898069080691806928069380694806958069680697806988069980700807018070280703807048070580706807078070880709807108071180712807138071480715807168071780718807198072080721807228072380724807258072680727807288072980730807318073280733807348073580736807378073880739807408074180742807438074480745807468074780748807498075080751807528075380754807558075680757807588075980760807618076280763807648076580766807678076880769807708077180772807738077480775807768077780778807798078080781807828078380784807858078680787807888078980790807918079280793807948079580796807978079880799808008080180802808038080480805808068080780808808098081080811808128081380814808158081680817808188081980820808218082280823808248082580826808278082880829808308083180832808338083480835808368083780838808398084080841808428084380844808458084680847808488084980850808518085280853808548085580856808578085880859808608086180862808638086480865808668086780868808698087080871808728087380874808758087680877808788087980880808818088280883808848088580886808878088880889808908089180892808938089480895808968089780898808998090080901809028090380904809058090680907809088090980910809118091280913809148091580916809178091880919809208092180922809238092480925809268092780928809298093080931809328093380934809358093680937809388093980940809418094280943809448094580946809478094880949809508095180952809538095480955809568095780958809598096080961809628096380964809658096680967809688096980970809718097280973809748097580976809778097880979809808098180982809838098480985809868098780988809898099080991809928099380994809958099680997809988099981000810018100281003810048100581006810078100881009810108101181012810138101481015810168101781018810198102081021810228102381024810258102681027810288102981030810318103281033810348103581036810378103881039810408104181042810438104481045810468104781048810498105081051810528105381054810558105681057810588105981060810618106281063810648106581066810678106881069810708107181072810738107481075810768107781078810798108081081810828108381084810858108681087810888108981090810918109281093810948109581096810978109881099811008110181102811038110481105811068110781108811098111081111811128111381114811158111681117811188111981120811218112281123811248112581126811278112881129811308113181132811338113481135811368113781138811398114081141811428114381144811458114681147811488114981150811518115281153811548115581156811578115881159811608116181162811638116481165811668116781168811698117081171811728117381174811758117681177811788117981180811818118281183811848118581186811878118881189811908119181192811938119481195811968119781198811998120081201812028120381204812058120681207812088120981210812118121281213812148121581216812178121881219812208122181222812238122481225812268122781228812298123081231812328123381234812358123681237812388123981240812418124281243812448124581246812478124881249812508125181252812538125481255812568125781258812598126081261812628126381264812658126681267812688126981270812718127281273812748127581276812778127881279812808128181282812838128481285812868128781288812898129081291812928129381294812958129681297812988129981300813018130281303813048130581306813078130881309813108131181312813138131481315813168131781318813198132081321813228132381324813258132681327813288132981330813318133281333813348133581336813378133881339813408134181342813438134481345813468134781348813498135081351813528135381354813558135681357813588135981360813618136281363813648136581366813678136881369813708137181372813738137481375813768137781378813798138081381813828138381384813858138681387813888138981390813918139281393813948139581396813978139881399814008140181402814038140481405814068140781408814098141081411814128141381414814158141681417814188141981420814218142281423814248142581426814278142881429814308143181432814338143481435814368143781438814398144081441814428144381444814458144681447814488144981450814518145281453814548145581456814578145881459814608146181462814638146481465814668146781468814698147081471814728147381474814758147681477814788147981480814818148281483814848148581486814878148881489814908149181492814938149481495814968149781498814998150081501815028150381504815058150681507815088150981510815118151281513815148151581516815178151881519815208152181522815238152481525815268152781528815298153081531815328153381534815358153681537815388153981540815418154281543815448154581546815478154881549815508155181552815538155481555815568155781558815598156081561815628156381564815658156681567815688156981570815718157281573815748157581576815778157881579815808158181582815838158481585815868158781588815898159081591815928159381594815958159681597815988159981600816018160281603816048160581606816078160881609816108161181612816138161481615816168161781618816198162081621816228162381624816258162681627816288162981630816318163281633816348163581636816378163881639816408164181642816438164481645816468164781648816498165081651816528165381654816558165681657816588165981660816618166281663816648166581666816678166881669816708167181672816738167481675816768167781678816798168081681816828168381684816858168681687816888168981690816918169281693816948169581696816978169881699817008170181702817038170481705817068170781708817098171081711817128171381714817158171681717817188171981720817218172281723817248172581726817278172881729817308173181732817338173481735817368173781738817398174081741817428174381744817458174681747817488174981750817518175281753817548175581756817578175881759817608176181762817638176481765817668176781768817698177081771817728177381774817758177681777817788177981780817818178281783817848178581786817878178881789817908179181792817938179481795817968179781798817998180081801818028180381804818058180681807818088180981810818118181281813818148181581816818178181881819818208182181822818238182481825818268182781828818298183081831818328183381834818358183681837818388183981840818418184281843818448184581846818478184881849818508185181852818538185481855818568185781858818598186081861818628186381864818658186681867818688186981870818718187281873818748187581876818778187881879818808188181882818838188481885818868188781888818898189081891818928189381894818958189681897818988189981900819018190281903819048190581906819078190881909819108191181912819138191481915819168191781918819198192081921819228192381924819258192681927819288192981930819318193281933819348193581936819378193881939819408194181942819438194481945819468194781948819498195081951819528195381954819558195681957819588195981960819618196281963819648196581966819678196881969819708197181972819738197481975819768197781978819798198081981819828198381984819858198681987819888198981990819918199281993819948199581996819978199881999820008200182002820038200482005820068200782008820098201082011820128201382014820158201682017820188201982020820218202282023820248202582026820278202882029820308203182032820338203482035820368203782038820398204082041820428204382044820458204682047820488204982050820518205282053820548205582056820578205882059820608206182062820638206482065820668206782068820698207082071820728207382074820758207682077820788207982080820818208282083820848208582086820878208882089820908209182092820938209482095820968209782098820998210082101821028210382104821058210682107821088210982110821118211282113821148211582116821178211882119821208212182122821238212482125821268212782128821298213082131821328213382134821358213682137821388213982140821418214282143821448214582146821478214882149821508215182152821538215482155821568215782158821598216082161821628216382164821658216682167821688216982170821718217282173821748217582176821778217882179821808218182182821838218482185821868218782188821898219082191821928219382194821958219682197821988219982200822018220282203822048220582206822078220882209822108221182212822138221482215822168221782218822198222082221822228222382224822258222682227822288222982230822318223282233822348223582236822378223882239822408224182242822438224482245822468224782248822498225082251822528225382254822558225682257822588225982260822618226282263822648226582266822678226882269822708227182272822738227482275822768227782278822798228082281822828228382284822858228682287822888228982290822918229282293822948229582296822978229882299823008230182302823038230482305823068230782308823098231082311823128231382314823158231682317823188231982320823218232282323823248232582326823278232882329823308233182332823338233482335823368233782338823398234082341823428234382344823458234682347823488234982350823518235282353823548235582356823578235882359823608236182362823638236482365823668236782368823698237082371823728237382374823758237682377823788237982380823818238282383823848238582386823878238882389823908239182392823938239482395823968239782398823998240082401824028240382404824058240682407824088240982410824118241282413824148241582416824178241882419824208242182422824238242482425824268242782428824298243082431824328243382434824358243682437824388243982440824418244282443824448244582446824478244882449824508245182452824538245482455824568245782458824598246082461824628246382464824658246682467824688246982470824718247282473824748247582476824778247882479824808248182482824838248482485824868248782488824898249082491824928249382494824958249682497824988249982500825018250282503825048250582506825078250882509825108251182512825138251482515825168251782518825198252082521825228252382524825258252682527825288252982530825318253282533825348253582536825378253882539825408254182542825438254482545825468254782548825498255082551825528255382554825558255682557825588255982560825618256282563825648256582566825678256882569825708257182572825738257482575825768257782578825798258082581825828258382584825858258682587825888258982590825918259282593825948259582596825978259882599826008260182602826038260482605826068260782608826098261082611826128261382614826158261682617826188261982620826218262282623826248262582626826278262882629826308263182632826338263482635826368263782638826398264082641826428264382644826458264682647826488264982650826518265282653826548265582656826578265882659826608266182662826638266482665826668266782668826698267082671826728267382674826758267682677826788267982680826818268282683826848268582686826878268882689826908269182692826938269482695826968269782698826998270082701827028270382704827058270682707827088270982710827118271282713827148271582716827178271882719827208272182722827238272482725827268272782728827298273082731827328273382734827358273682737827388273982740827418274282743827448274582746827478274882749827508275182752827538275482755827568275782758827598276082761827628276382764827658276682767827688276982770827718277282773827748277582776827778277882779827808278182782827838278482785827868278782788827898279082791827928279382794827958279682797827988279982800828018280282803828048280582806828078280882809828108281182812828138281482815828168281782818828198282082821828228282382824828258282682827828288282982830828318283282833828348283582836828378283882839828408284182842828438284482845828468284782848828498285082851828528285382854828558285682857828588285982860828618286282863828648286582866828678286882869828708287182872828738287482875828768287782878828798288082881828828288382884828858288682887828888288982890828918289282893828948289582896828978289882899829008290182902829038290482905829068290782908829098291082911829128291382914829158291682917829188291982920829218292282923829248292582926829278292882929829308293182932829338293482935829368293782938829398294082941829428294382944829458294682947829488294982950829518295282953829548295582956829578295882959829608296182962829638296482965829668296782968829698297082971829728297382974829758297682977829788297982980829818298282983829848298582986829878298882989829908299182992829938299482995829968299782998829998300083001830028300383004830058300683007830088300983010830118301283013830148301583016830178301883019830208302183022830238302483025830268302783028830298303083031830328303383034830358303683037830388303983040830418304283043830448304583046830478304883049830508305183052830538305483055830568305783058830598306083061830628306383064830658306683067830688306983070830718307283073830748307583076830778307883079830808308183082830838308483085830868308783088830898309083091830928309383094830958309683097830988309983100831018310283103831048310583106831078310883109831108311183112831138311483115831168311783118831198312083121831228312383124831258312683127831288312983130831318313283133831348313583136831378313883139831408314183142831438314483145831468314783148831498315083151831528315383154831558315683157831588315983160831618316283163831648316583166831678316883169831708317183172831738317483175831768317783178831798318083181831828318383184831858318683187831888318983190831918319283193831948319583196831978319883199832008320183202832038320483205832068320783208832098321083211832128321383214832158321683217832188321983220832218322283223832248322583226832278322883229832308323183232832338323483235832368323783238832398324083241832428324383244832458324683247832488324983250832518325283253832548325583256832578325883259832608326183262832638326483265832668326783268832698327083271832728327383274832758327683277832788327983280832818328283283832848328583286832878328883289832908329183292832938329483295832968329783298832998330083301833028330383304833058330683307833088330983310833118331283313833148331583316833178331883319833208332183322833238332483325833268332783328833298333083331833328333383334833358333683337833388333983340833418334283343833448334583346833478334883349833508335183352833538335483355833568335783358833598336083361833628336383364833658336683367833688336983370833718337283373833748337583376833778337883379833808338183382833838338483385833868338783388833898339083391833928339383394833958339683397833988339983400834018340283403834048340583406834078340883409834108341183412834138341483415834168341783418834198342083421834228342383424834258342683427834288342983430834318343283433834348343583436834378343883439834408344183442834438344483445834468344783448834498345083451834528345383454834558345683457834588345983460834618346283463834648346583466834678346883469834708347183472834738347483475834768347783478834798348083481834828348383484834858348683487834888348983490834918349283493834948349583496834978349883499835008350183502835038350483505835068350783508835098351083511835128351383514835158351683517835188351983520835218352283523835248352583526835278352883529835308353183532835338353483535835368353783538835398354083541835428354383544835458354683547835488354983550835518355283553835548355583556835578355883559835608356183562835638356483565835668356783568835698357083571835728357383574835758357683577835788357983580835818358283583835848358583586835878358883589835908359183592835938359483595835968359783598835998360083601836028360383604836058360683607836088360983610836118361283613836148361583616836178361883619836208362183622836238362483625836268362783628836298363083631836328363383634836358363683637836388363983640836418364283643836448364583646836478364883649836508365183652836538365483655836568365783658836598366083661836628366383664836658366683667836688366983670836718367283673836748367583676836778367883679836808368183682836838368483685836868368783688836898369083691836928369383694836958369683697836988369983700837018370283703837048370583706837078370883709837108371183712837138371483715837168371783718837198372083721837228372383724837258372683727837288372983730837318373283733837348373583736837378373883739837408374183742837438374483745837468374783748837498375083751837528375383754837558375683757837588375983760837618376283763837648376583766837678376883769837708377183772837738377483775837768377783778837798378083781837828378383784837858378683787837888378983790837918379283793837948379583796837978379883799838008380183802838038380483805838068380783808838098381083811838128381383814838158381683817838188381983820838218382283823838248382583826838278382883829838308383183832838338383483835838368383783838838398384083841838428384383844838458384683847838488384983850838518385283853838548385583856838578385883859838608386183862838638386483865838668386783868838698387083871838728387383874838758387683877838788387983880838818388283883838848388583886838878388883889838908389183892838938389483895838968389783898838998390083901839028390383904839058390683907839088390983910839118391283913839148391583916839178391883919839208392183922839238392483925839268392783928839298393083931839328393383934839358393683937839388393983940839418394283943839448394583946839478394883949839508395183952839538395483955839568395783958839598396083961839628396383964839658396683967839688396983970839718397283973839748397583976839778397883979839808398183982839838398483985839868398783988839898399083991839928399383994839958399683997839988399984000840018400284003840048400584006840078400884009840108401184012840138401484015840168401784018840198402084021840228402384024840258402684027840288402984030840318403284033840348403584036840378403884039840408404184042840438404484045840468404784048840498405084051840528405384054840558405684057840588405984060840618406284063840648406584066840678406884069840708407184072840738407484075840768407784078840798408084081840828408384084840858408684087840888408984090840918409284093840948409584096840978409884099841008410184102841038410484105841068410784108841098411084111841128411384114841158411684117841188411984120841218412284123841248412584126841278412884129841308413184132841338413484135841368413784138841398414084141841428414384144841458414684147841488414984150841518415284153841548415584156841578415884159841608416184162841638416484165841668416784168841698417084171841728417384174841758417684177841788417984180841818418284183841848418584186841878418884189841908419184192841938419484195841968419784198841998420084201842028420384204842058420684207842088420984210842118421284213842148421584216842178421884219842208422184222842238422484225842268422784228842298423084231842328423384234842358423684237842388423984240842418424284243842448424584246842478424884249842508425184252842538425484255842568425784258842598426084261842628426384264842658426684267842688426984270842718427284273842748427584276842778427884279842808428184282842838428484285842868428784288842898429084291842928429384294842958429684297842988429984300843018430284303843048430584306843078430884309843108431184312843138431484315843168431784318843198432084321843228432384324843258432684327843288432984330843318433284333843348433584336843378433884339843408434184342843438434484345843468434784348843498435084351843528435384354843558435684357843588435984360843618436284363843648436584366843678436884369843708437184372843738437484375843768437784378843798438084381843828438384384843858438684387843888438984390843918439284393843948439584396843978439884399844008440184402844038440484405844068440784408844098441084411844128441384414844158441684417844188441984420844218442284423844248442584426844278442884429844308443184432844338443484435844368443784438844398444084441844428444384444844458444684447844488444984450844518445284453844548445584456844578445884459844608446184462844638446484465844668446784468844698447084471844728447384474844758447684477844788447984480844818448284483844848448584486844878448884489844908449184492844938449484495844968449784498844998450084501845028450384504845058450684507845088450984510845118451284513845148451584516845178451884519845208452184522845238452484525845268452784528845298453084531845328453384534845358453684537845388453984540845418454284543845448454584546845478454884549845508455184552845538455484555845568455784558845598456084561845628456384564845658456684567845688456984570845718457284573845748457584576845778457884579845808458184582845838458484585845868458784588845898459084591845928459384594845958459684597845988459984600846018460284603846048460584606846078460884609846108461184612846138461484615846168461784618846198462084621846228462384624846258462684627846288462984630846318463284633846348463584636846378463884639846408464184642846438464484645846468464784648846498465084651846528465384654846558465684657846588465984660846618466284663846648466584666846678466884669846708467184672846738467484675846768467784678846798468084681846828468384684846858468684687846888468984690846918469284693846948469584696846978469884699847008470184702847038470484705847068470784708847098471084711847128471384714847158471684717847188471984720847218472284723847248472584726847278472884729847308473184732847338473484735847368473784738847398474084741847428474384744847458474684747847488474984750847518475284753847548475584756847578475884759847608476184762847638476484765847668476784768847698477084771847728477384774847758477684777847788477984780847818478284783847848478584786847878478884789847908479184792847938479484795847968479784798847998480084801848028480384804848058480684807848088480984810848118481284813848148481584816848178481884819848208482184822848238482484825848268482784828848298483084831848328483384834848358483684837848388483984840848418484284843848448484584846848478484884849848508485184852848538485484855848568485784858848598486084861848628486384864848658486684867848688486984870848718487284873848748487584876848778487884879848808488184882848838488484885848868488784888848898489084891848928489384894848958489684897848988489984900849018490284903849048490584906849078490884909849108491184912849138491484915849168491784918849198492084921849228492384924849258492684927849288492984930849318493284933849348493584936849378493884939849408494184942849438494484945849468494784948849498495084951849528495384954849558495684957849588495984960849618496284963849648496584966849678496884969849708497184972849738497484975849768497784978849798498084981849828498384984849858498684987849888498984990849918499284993849948499584996849978499884999850008500185002850038500485005850068500785008850098501085011850128501385014850158501685017850188501985020850218502285023850248502585026850278502885029850308503185032850338503485035850368503785038850398504085041850428504385044850458504685047850488504985050850518505285053850548505585056850578505885059850608506185062850638506485065850668506785068850698507085071850728507385074850758507685077850788507985080850818508285083850848508585086850878508885089850908509185092850938509485095850968509785098850998510085101851028510385104851058510685107851088510985110851118511285113851148511585116851178511885119851208512185122851238512485125851268512785128851298513085131851328513385134851358513685137851388513985140851418514285143851448514585146851478514885149851508515185152851538515485155851568515785158851598516085161851628516385164851658516685167851688516985170851718517285173851748517585176851778517885179851808518185182851838518485185851868518785188851898519085191851928519385194851958519685197851988519985200852018520285203852048520585206852078520885209852108521185212852138521485215852168521785218852198522085221852228522385224852258522685227852288522985230852318523285233852348523585236852378523885239852408524185242852438524485245852468524785248852498525085251852528525385254852558525685257852588525985260852618526285263852648526585266852678526885269852708527185272852738527485275852768527785278852798528085281852828528385284852858528685287852888528985290852918529285293852948529585296852978529885299853008530185302853038530485305853068530785308853098531085311853128531385314853158531685317853188531985320853218532285323853248532585326853278532885329853308533185332853338533485335853368533785338853398534085341853428534385344853458534685347853488534985350853518535285353853548535585356853578535885359853608536185362853638536485365853668536785368853698537085371853728537385374853758537685377853788537985380853818538285383853848538585386853878538885389853908539185392853938539485395853968539785398853998540085401854028540385404854058540685407854088540985410854118541285413854148541585416854178541885419854208542185422854238542485425854268542785428854298543085431854328543385434854358543685437854388543985440854418544285443854448544585446854478544885449854508545185452854538545485455854568545785458854598546085461854628546385464854658546685467854688546985470854718547285473854748547585476854778547885479854808548185482854838548485485854868548785488854898549085491854928549385494854958549685497854988549985500855018550285503855048550585506855078550885509855108551185512855138551485515855168551785518855198552085521855228552385524855258552685527855288552985530855318553285533855348553585536855378553885539855408554185542855438554485545855468554785548855498555085551855528555385554855558555685557855588555985560855618556285563855648556585566855678556885569855708557185572855738557485575855768557785578855798558085581855828558385584855858558685587855888558985590855918559285593855948559585596855978559885599856008560185602856038560485605856068560785608856098561085611856128561385614856158561685617856188561985620856218562285623856248562585626856278562885629856308563185632856338563485635856368563785638856398564085641856428564385644856458564685647856488564985650856518565285653856548565585656856578565885659856608566185662856638566485665856668566785668856698567085671856728567385674856758567685677856788567985680856818568285683856848568585686856878568885689856908569185692856938569485695856968569785698856998570085701857028570385704857058570685707857088570985710857118571285713857148571585716857178571885719857208572185722857238572485725857268572785728857298573085731857328573385734857358573685737857388573985740857418574285743857448574585746857478574885749857508575185752857538575485755857568575785758857598576085761857628576385764857658576685767857688576985770857718577285773857748577585776857778577885779857808578185782857838578485785857868578785788857898579085791857928579385794857958579685797857988579985800858018580285803858048580585806858078580885809858108581185812858138581485815858168581785818858198582085821858228582385824858258582685827858288582985830858318583285833858348583585836858378583885839858408584185842858438584485845858468584785848858498585085851858528585385854858558585685857858588585985860858618586285863858648586585866858678586885869858708587185872858738587485875858768587785878858798588085881858828588385884858858588685887858888588985890858918589285893858948589585896858978589885899859008590185902859038590485905859068590785908859098591085911859128591385914859158591685917859188591985920859218592285923859248592585926859278592885929859308593185932859338593485935859368593785938859398594085941859428594385944859458594685947859488594985950859518595285953859548595585956859578595885959859608596185962859638596485965859668596785968859698597085971859728597385974859758597685977859788597985980859818598285983859848598585986859878598885989859908599185992859938599485995859968599785998859998600086001860028600386004860058600686007860088600986010860118601286013860148601586016860178601886019860208602186022860238602486025860268602786028860298603086031860328603386034860358603686037860388603986040860418604286043860448604586046860478604886049860508605186052860538605486055860568605786058860598606086061860628606386064860658606686067860688606986070860718607286073860748607586076860778607886079860808608186082860838608486085860868608786088860898609086091860928609386094860958609686097860988609986100861018610286103861048610586106861078610886109861108611186112861138611486115861168611786118861198612086121861228612386124861258612686127861288612986130861318613286133861348613586136861378613886139861408614186142861438614486145861468614786148861498615086151861528615386154861558615686157861588615986160861618616286163861648616586166861678616886169861708617186172861738617486175861768617786178861798618086181861828618386184861858618686187861888618986190861918619286193861948619586196861978619886199862008620186202862038620486205862068620786208862098621086211862128621386214862158621686217862188621986220862218622286223862248622586226862278622886229862308623186232862338623486235862368623786238862398624086241862428624386244862458624686247862488624986250862518625286253862548625586256862578625886259862608626186262862638626486265862668626786268862698627086271862728627386274862758627686277862788627986280862818628286283862848628586286862878628886289862908629186292862938629486295862968629786298862998630086301863028630386304863058630686307863088630986310863118631286313863148631586316863178631886319863208632186322863238632486325863268632786328863298633086331863328633386334863358633686337863388633986340863418634286343863448634586346863478634886349863508635186352863538635486355863568635786358863598636086361863628636386364863658636686367863688636986370863718637286373863748637586376863778637886379863808638186382863838638486385863868638786388863898639086391863928639386394863958639686397863988639986400864018640286403864048640586406864078640886409864108641186412864138641486415864168641786418864198642086421864228642386424864258642686427864288642986430864318643286433864348643586436864378643886439864408644186442864438644486445864468644786448864498645086451864528645386454864558645686457864588645986460864618646286463864648646586466864678646886469864708647186472864738647486475864768647786478864798648086481864828648386484864858648686487864888648986490864918649286493864948649586496864978649886499865008650186502865038650486505865068650786508865098651086511865128651386514865158651686517865188651986520865218652286523865248652586526865278652886529865308653186532865338653486535865368653786538865398654086541865428654386544865458654686547865488654986550865518655286553865548655586556865578655886559865608656186562865638656486565865668656786568865698657086571865728657386574865758657686577865788657986580865818658286583865848658586586865878658886589865908659186592865938659486595865968659786598865998660086601866028660386604866058660686607866088660986610866118661286613866148661586616866178661886619866208662186622866238662486625866268662786628866298663086631866328663386634866358663686637866388663986640866418664286643866448664586646866478664886649866508665186652866538665486655866568665786658866598666086661866628666386664866658666686667866688666986670866718667286673866748667586676866778667886679866808668186682866838668486685866868668786688866898669086691866928669386694866958669686697866988669986700867018670286703867048670586706867078670886709867108671186712867138671486715867168671786718867198672086721867228672386724867258672686727867288672986730867318673286733867348673586736867378673886739867408674186742867438674486745867468674786748867498675086751867528675386754867558675686757867588675986760867618676286763867648676586766867678676886769867708677186772867738677486775867768677786778867798678086781867828678386784867858678686787867888678986790867918679286793867948679586796867978679886799868008680186802868038680486805868068680786808868098681086811868128681386814868158681686817868188681986820868218682286823868248682586826868278682886829868308683186832868338683486835868368683786838868398684086841868428684386844868458684686847868488684986850868518685286853868548685586856868578685886859868608686186862868638686486865868668686786868868698687086871868728687386874868758687686877868788687986880868818688286883868848688586886868878688886889868908689186892868938689486895868968689786898868998690086901869028690386904869058690686907869088690986910869118691286913869148691586916869178691886919869208692186922869238692486925869268692786928869298693086931869328693386934869358693686937869388693986940869418694286943869448694586946869478694886949869508695186952869538695486955869568695786958869598696086961869628696386964869658696686967869688696986970869718697286973869748697586976869778697886979869808698186982869838698486985869868698786988869898699086991869928699386994869958699686997869988699987000870018700287003870048700587006870078700887009870108701187012870138701487015870168701787018870198702087021870228702387024870258702687027870288702987030870318703287033870348703587036870378703887039870408704187042870438704487045870468704787048870498705087051870528705387054870558705687057870588705987060870618706287063870648706587066870678706887069870708707187072870738707487075870768707787078870798708087081870828708387084870858708687087870888708987090870918709287093870948709587096870978709887099871008710187102871038710487105871068710787108871098711087111871128711387114871158711687117871188711987120871218712287123871248712587126871278712887129871308713187132871338713487135871368713787138871398714087141871428714387144871458714687147871488714987150871518715287153871548715587156871578715887159871608716187162871638716487165871668716787168871698717087171871728717387174871758717687177871788717987180871818718287183871848718587186871878718887189871908719187192871938719487195871968719787198871998720087201872028720387204872058720687207872088720987210872118721287213872148721587216872178721887219872208722187222872238722487225872268722787228872298723087231872328723387234872358723687237872388723987240872418724287243872448724587246872478724887249872508725187252872538725487255872568725787258872598726087261872628726387264872658726687267872688726987270872718727287273872748727587276872778727887279872808728187282872838728487285872868728787288872898729087291872928729387294872958729687297872988729987300873018730287303873048730587306873078730887309873108731187312873138731487315873168731787318873198732087321873228732387324873258732687327873288732987330873318733287333873348733587336873378733887339873408734187342873438734487345873468734787348873498735087351873528735387354873558735687357873588735987360873618736287363873648736587366873678736887369873708737187372873738737487375873768737787378873798738087381873828738387384873858738687387873888738987390873918739287393873948739587396873978739887399874008740187402874038740487405874068740787408874098741087411874128741387414874158741687417874188741987420874218742287423874248742587426874278742887429874308743187432874338743487435874368743787438874398744087441874428744387444874458744687447874488744987450874518745287453874548745587456874578745887459874608746187462874638746487465874668746787468874698747087471874728747387474874758747687477874788747987480874818748287483874848748587486874878748887489874908749187492874938749487495874968749787498874998750087501875028750387504875058750687507875088750987510875118751287513875148751587516875178751887519875208752187522875238752487525875268752787528875298753087531875328753387534875358753687537875388753987540875418754287543875448754587546875478754887549875508755187552875538755487555875568755787558875598756087561875628756387564875658756687567875688756987570875718757287573875748757587576875778757887579875808758187582875838758487585875868758787588875898759087591875928759387594875958759687597875988759987600876018760287603876048760587606876078760887609876108761187612876138761487615876168761787618876198762087621876228762387624876258762687627876288762987630876318763287633876348763587636876378763887639876408764187642876438764487645876468764787648876498765087651876528765387654876558765687657876588765987660876618766287663876648766587666876678766887669876708767187672876738767487675876768767787678876798768087681876828768387684876858768687687876888768987690876918769287693876948769587696876978769887699877008770187702877038770487705877068770787708877098771087711877128771387714877158771687717877188771987720877218772287723877248772587726877278772887729877308773187732877338773487735877368773787738877398774087741877428774387744877458774687747877488774987750877518775287753877548775587756877578775887759877608776187762877638776487765877668776787768877698777087771877728777387774877758777687777877788777987780877818778287783877848778587786877878778887789877908779187792877938779487795877968779787798877998780087801878028780387804878058780687807878088780987810878118781287813878148781587816878178781887819878208782187822878238782487825878268782787828878298783087831878328783387834878358783687837878388783987840878418784287843878448784587846878478784887849878508785187852878538785487855878568785787858878598786087861878628786387864878658786687867878688786987870878718787287873878748787587876878778787887879878808788187882878838788487885878868788787888878898789087891878928789387894878958789687897878988789987900879018790287903879048790587906879078790887909879108791187912879138791487915879168791787918879198792087921879228792387924879258792687927879288792987930879318793287933879348793587936879378793887939879408794187942879438794487945879468794787948879498795087951879528795387954879558795687957879588795987960879618796287963879648796587966879678796887969879708797187972879738797487975879768797787978879798798087981879828798387984879858798687987879888798987990879918799287993879948799587996879978799887999880008800188002880038800488005880068800788008880098801088011880128801388014880158801688017880188801988020880218802288023880248802588026880278802888029880308803188032880338803488035880368803788038880398804088041880428804388044880458804688047880488804988050880518805288053880548805588056880578805888059880608806188062880638806488065880668806788068880698807088071880728807388074880758807688077880788807988080880818808288083880848808588086880878808888089880908809188092880938809488095880968809788098880998810088101881028810388104881058810688107881088810988110881118811288113881148811588116881178811888119881208812188122881238812488125881268812788128881298813088131881328813388134881358813688137881388813988140881418814288143881448814588146881478814888149881508815188152881538815488155881568815788158881598816088161881628816388164881658816688167881688816988170881718817288173881748817588176881778817888179881808818188182881838818488185881868818788188881898819088191881928819388194881958819688197881988819988200882018820288203882048820588206882078820888209882108821188212882138821488215882168821788218882198822088221882228822388224882258822688227882288822988230882318823288233882348823588236882378823888239882408824188242882438824488245882468824788248882498825088251882528825388254882558825688257882588825988260882618826288263882648826588266882678826888269882708827188272882738827488275882768827788278882798828088281882828828388284882858828688287882888828988290882918829288293882948829588296882978829888299883008830188302883038830488305883068830788308883098831088311883128831388314883158831688317883188831988320883218832288323883248832588326883278832888329883308833188332883338833488335883368833788338883398834088341883428834388344883458834688347883488834988350883518835288353883548835588356883578835888359883608836188362883638836488365883668836788368883698837088371883728837388374883758837688377883788837988380883818838288383883848838588386883878838888389883908839188392883938839488395883968839788398883998840088401884028840388404884058840688407884088840988410884118841288413884148841588416884178841888419884208842188422884238842488425884268842788428884298843088431884328843388434884358843688437884388843988440884418844288443884448844588446884478844888449884508845188452884538845488455884568845788458884598846088461884628846388464884658846688467884688846988470884718847288473884748847588476884778847888479884808848188482884838848488485884868848788488884898849088491884928849388494884958849688497884988849988500885018850288503885048850588506885078850888509885108851188512885138851488515885168851788518885198852088521885228852388524885258852688527885288852988530885318853288533885348853588536885378853888539885408854188542885438854488545885468854788548885498855088551885528855388554885558855688557885588855988560885618856288563885648856588566885678856888569885708857188572885738857488575885768857788578885798858088581885828858388584885858858688587885888858988590885918859288593885948859588596885978859888599886008860188602886038860488605886068860788608886098861088611886128861388614886158861688617886188861988620886218862288623886248862588626886278862888629886308863188632886338863488635886368863788638886398864088641886428864388644886458864688647886488864988650886518865288653886548865588656886578865888659886608866188662886638866488665886668866788668886698867088671886728867388674886758867688677886788867988680886818868288683886848868588686886878868888689886908869188692886938869488695886968869788698886998870088701887028870388704887058870688707887088870988710887118871288713887148871588716887178871888719887208872188722887238872488725887268872788728887298873088731887328873388734887358873688737887388873988740887418874288743887448874588746887478874888749887508875188752887538875488755887568875788758887598876088761887628876388764887658876688767887688876988770887718877288773887748877588776887778877888779887808878188782887838878488785887868878788788887898879088791887928879388794887958879688797887988879988800888018880288803888048880588806888078880888809888108881188812888138881488815888168881788818888198882088821888228882388824888258882688827888288882988830888318883288833888348883588836888378883888839888408884188842888438884488845888468884788848888498885088851888528885388854888558885688857888588885988860888618886288863888648886588866888678886888869888708887188872888738887488875888768887788878888798888088881888828888388884888858888688887888888888988890888918889288893888948889588896888978889888899889008890188902889038890488905889068890788908889098891088911889128891388914889158891688917889188891988920889218892288923889248892588926889278892888929889308893188932889338893488935889368893788938889398894088941889428894388944889458894688947889488894988950889518895288953889548895588956889578895888959889608896188962889638896488965889668896788968889698897088971889728897388974889758897688977889788897988980889818898288983889848898588986889878898888989889908899188992889938899488995889968899788998889998900089001890028900389004890058900689007890088900989010890118901289013890148901589016890178901889019890208902189022890238902489025890268902789028890298903089031890328903389034890358903689037890388903989040890418904289043890448904589046890478904889049890508905189052890538905489055890568905789058890598906089061890628906389064890658906689067890688906989070890718907289073890748907589076890778907889079890808908189082890838908489085890868908789088890898909089091890928909389094890958909689097890988909989100891018910289103891048910589106891078910889109891108911189112891138911489115891168911789118891198912089121891228912389124891258912689127891288912989130891318913289133891348913589136891378913889139891408914189142891438914489145891468914789148891498915089151891528915389154891558915689157891588915989160891618916289163891648916589166891678916889169891708917189172891738917489175891768917789178891798918089181891828918389184891858918689187891888918989190891918919289193891948919589196891978919889199892008920189202892038920489205892068920789208892098921089211892128921389214892158921689217892188921989220892218922289223892248922589226892278922889229892308923189232892338923489235892368923789238892398924089241892428924389244892458924689247892488924989250892518925289253892548925589256892578925889259892608926189262892638926489265892668926789268892698927089271892728927389274892758927689277892788927989280892818928289283892848928589286892878928889289892908929189292892938929489295892968929789298892998930089301893028930389304893058930689307893088930989310893118931289313893148931589316893178931889319893208932189322893238932489325893268932789328893298933089331893328933389334893358933689337893388933989340893418934289343893448934589346893478934889349893508935189352893538935489355893568935789358893598936089361893628936389364893658936689367893688936989370893718937289373893748937589376893778937889379893808938189382893838938489385893868938789388893898939089391893928939389394893958939689397893988939989400894018940289403894048940589406894078940889409894108941189412894138941489415894168941789418894198942089421894228942389424894258942689427894288942989430894318943289433894348943589436894378943889439894408944189442894438944489445894468944789448894498945089451894528945389454894558945689457894588945989460894618946289463894648946589466894678946889469894708947189472894738947489475894768947789478894798948089481894828948389484894858948689487894888948989490894918949289493894948949589496894978949889499895008950189502895038950489505895068950789508895098951089511895128951389514895158951689517895188951989520895218952289523895248952589526895278952889529895308953189532895338953489535895368953789538895398954089541895428954389544895458954689547895488954989550895518955289553895548955589556895578955889559895608956189562895638956489565895668956789568895698957089571895728957389574895758957689577895788957989580895818958289583895848958589586895878958889589895908959189592895938959489595895968959789598895998960089601896028960389604896058960689607896088960989610896118961289613896148961589616896178961889619896208962189622896238962489625896268962789628896298963089631896328963389634896358963689637896388963989640896418964289643896448964589646896478964889649896508965189652896538965489655896568965789658896598966089661896628966389664896658966689667896688966989670896718967289673896748967589676896778967889679896808968189682896838968489685896868968789688896898969089691896928969389694896958969689697896988969989700897018970289703897048970589706897078970889709897108971189712897138971489715897168971789718897198972089721897228972389724897258972689727897288972989730897318973289733897348973589736897378973889739897408974189742897438974489745897468974789748897498975089751897528975389754897558975689757897588975989760897618976289763897648976589766897678976889769897708977189772897738977489775897768977789778897798978089781897828978389784897858978689787897888978989790897918979289793897948979589796897978979889799898008980189802898038980489805898068980789808898098981089811898128981389814898158981689817898188981989820898218982289823898248982589826898278982889829898308983189832898338983489835898368983789838898398984089841898428984389844898458984689847898488984989850898518985289853898548985589856898578985889859898608986189862898638986489865898668986789868898698987089871898728987389874898758987689877898788987989880898818988289883898848988589886898878988889889898908989189892898938989489895898968989789898898998990089901899028990389904899058990689907899088990989910899118991289913899148991589916899178991889919899208992189922899238992489925899268992789928899298993089931899328993389934899358993689937899388993989940899418994289943899448994589946899478994889949899508995189952899538995489955899568995789958899598996089961899628996389964899658996689967899688996989970899718997289973899748997589976899778997889979899808998189982899838998489985899868998789988899898999089991899928999389994899958999689997899988999990000900019000290003900049000590006900079000890009900109001190012900139001490015900169001790018900199002090021900229002390024900259002690027900289002990030900319003290033900349003590036900379003890039900409004190042900439004490045900469004790048900499005090051900529005390054900559005690057900589005990060900619006290063900649006590066900679006890069900709007190072900739007490075900769007790078900799008090081900829008390084900859008690087900889008990090900919009290093900949009590096900979009890099901009010190102901039010490105901069010790108901099011090111901129011390114901159011690117901189011990120901219012290123901249012590126901279012890129901309013190132901339013490135901369013790138901399014090141901429014390144901459014690147901489014990150901519015290153901549015590156901579015890159901609016190162901639016490165901669016790168901699017090171901729017390174901759017690177901789017990180901819018290183901849018590186901879018890189901909019190192901939019490195901969019790198901999020090201902029020390204902059020690207902089020990210902119021290213902149021590216902179021890219902209022190222902239022490225902269022790228902299023090231902329023390234902359023690237902389023990240902419024290243902449024590246902479024890249902509025190252902539025490255902569025790258902599026090261902629026390264902659026690267902689026990270902719027290273902749027590276902779027890279902809028190282902839028490285902869028790288902899029090291902929029390294902959029690297902989029990300903019030290303903049030590306903079030890309903109031190312903139031490315903169031790318903199032090321903229032390324903259032690327903289032990330903319033290333903349033590336903379033890339903409034190342903439034490345903469034790348903499035090351903529035390354903559035690357903589035990360903619036290363903649036590366903679036890369903709037190372903739037490375903769037790378903799038090381903829038390384903859038690387903889038990390903919039290393903949039590396903979039890399904009040190402904039040490405904069040790408904099041090411904129041390414904159041690417904189041990420904219042290423904249042590426904279042890429904309043190432904339043490435904369043790438904399044090441904429044390444904459044690447904489044990450904519045290453904549045590456904579045890459904609046190462904639046490465904669046790468904699047090471904729047390474904759047690477904789047990480904819048290483904849048590486904879048890489904909049190492904939049490495904969049790498904999050090501905029050390504905059050690507905089050990510905119051290513905149051590516905179051890519905209052190522905239052490525905269052790528905299053090531905329053390534905359053690537905389053990540905419054290543905449054590546905479054890549905509055190552905539055490555905569055790558905599056090561905629056390564905659056690567905689056990570905719057290573905749057590576905779057890579905809058190582905839058490585905869058790588905899059090591905929059390594905959059690597905989059990600906019060290603906049060590606906079060890609906109061190612906139061490615906169061790618906199062090621906229062390624906259062690627906289062990630906319063290633906349063590636906379063890639906409064190642906439064490645906469064790648906499065090651906529065390654906559065690657906589065990660906619066290663906649066590666906679066890669906709067190672906739067490675906769067790678906799068090681906829068390684906859068690687906889068990690906919069290693906949069590696906979069890699907009070190702907039070490705907069070790708907099071090711907129071390714907159071690717907189071990720907219072290723907249072590726907279072890729907309073190732907339073490735907369073790738907399074090741907429074390744907459074690747907489074990750907519075290753907549075590756907579075890759907609076190762907639076490765907669076790768907699077090771907729077390774907759077690777907789077990780907819078290783907849078590786907879078890789907909079190792907939079490795907969079790798907999080090801908029080390804908059080690807908089080990810908119081290813908149081590816908179081890819908209082190822908239082490825908269082790828908299083090831908329083390834908359083690837908389083990840908419084290843908449084590846908479084890849908509085190852908539085490855908569085790858908599086090861908629086390864908659086690867908689086990870908719087290873908749087590876908779087890879908809088190882908839088490885908869088790888908899089090891908929089390894908959089690897908989089990900909019090290903909049090590906909079090890909909109091190912909139091490915909169091790918909199092090921909229092390924909259092690927909289092990930909319093290933909349093590936909379093890939909409094190942909439094490945909469094790948909499095090951909529095390954909559095690957909589095990960909619096290963909649096590966909679096890969909709097190972909739097490975909769097790978909799098090981909829098390984909859098690987909889098990990909919099290993909949099590996909979099890999910009100191002910039100491005910069100791008910099101091011910129101391014910159101691017910189101991020910219102291023910249102591026910279102891029910309103191032910339103491035910369103791038910399104091041910429104391044910459104691047910489104991050910519105291053910549105591056910579105891059910609106191062910639106491065910669106791068910699107091071910729107391074910759107691077910789107991080910819108291083910849108591086910879108891089910909109191092910939109491095910969109791098910999110091101911029110391104911059110691107911089110991110911119111291113911149111591116911179111891119911209112191122911239112491125911269112791128911299113091131911329113391134911359113691137911389113991140911419114291143911449114591146911479114891149911509115191152911539115491155911569115791158911599116091161911629116391164911659116691167911689116991170911719117291173911749117591176911779117891179911809118191182911839118491185911869118791188911899119091191911929119391194911959119691197911989119991200912019120291203912049120591206912079120891209912109121191212912139121491215912169121791218912199122091221912229122391224912259122691227912289122991230912319123291233912349123591236912379123891239912409124191242912439124491245912469124791248912499125091251912529125391254912559125691257912589125991260912619126291263912649126591266912679126891269912709127191272912739127491275912769127791278912799128091281912829128391284912859128691287912889128991290912919129291293912949129591296912979129891299913009130191302913039130491305913069130791308913099131091311913129131391314913159131691317913189131991320913219132291323913249132591326913279132891329913309133191332913339133491335913369133791338913399134091341913429134391344913459134691347913489134991350913519135291353913549135591356913579135891359913609136191362913639136491365913669136791368913699137091371913729137391374913759137691377913789137991380913819138291383913849138591386913879138891389913909139191392913939139491395913969139791398913999140091401914029140391404914059140691407914089140991410914119141291413914149141591416914179141891419914209142191422914239142491425914269142791428914299143091431914329143391434914359143691437914389143991440914419144291443914449144591446914479144891449914509145191452914539145491455914569145791458914599146091461914629146391464914659146691467914689146991470914719147291473914749147591476914779147891479914809148191482914839148491485914869148791488914899149091491914929149391494914959149691497914989149991500915019150291503915049150591506915079150891509915109151191512915139151491515915169151791518915199152091521915229152391524915259152691527915289152991530915319153291533915349153591536915379153891539915409154191542915439154491545915469154791548915499155091551915529155391554915559155691557915589155991560915619156291563915649156591566915679156891569915709157191572915739157491575915769157791578915799158091581915829158391584915859158691587915889158991590915919159291593915949159591596915979159891599916009160191602916039160491605916069160791608916099161091611916129161391614916159161691617916189161991620916219162291623916249162591626916279162891629916309163191632916339163491635916369163791638916399164091641916429164391644916459164691647916489164991650916519165291653916549165591656916579165891659916609166191662916639166491665916669166791668916699167091671916729167391674916759167691677916789167991680916819168291683916849168591686916879168891689916909169191692916939169491695916969169791698916999170091701917029170391704917059170691707917089170991710917119171291713917149171591716917179171891719917209172191722917239172491725917269172791728917299173091731917329173391734917359173691737917389173991740917419174291743917449174591746917479174891749917509175191752917539175491755917569175791758917599176091761917629176391764917659176691767917689176991770917719177291773917749177591776917779177891779917809178191782917839178491785917869178791788917899179091791917929179391794917959179691797917989179991800918019180291803918049180591806918079180891809918109181191812918139181491815918169181791818918199182091821918229182391824918259182691827918289182991830918319183291833918349183591836918379183891839918409184191842918439184491845918469184791848918499185091851918529185391854918559185691857918589185991860918619186291863918649186591866918679186891869918709187191872918739187491875918769187791878918799188091881918829188391884918859188691887918889188991890918919189291893918949189591896918979189891899919009190191902919039190491905919069190791908919099191091911919129191391914919159191691917919189191991920919219192291923919249192591926919279192891929919309193191932919339193491935919369193791938919399194091941919429194391944919459194691947919489194991950919519195291953919549195591956919579195891959919609196191962919639196491965919669196791968919699197091971919729197391974919759197691977919789197991980919819198291983919849198591986919879198891989919909199191992919939199491995919969199791998919999200092001920029200392004920059200692007920089200992010920119201292013920149201592016920179201892019920209202192022920239202492025920269202792028920299203092031920329203392034920359203692037920389203992040920419204292043920449204592046920479204892049920509205192052920539205492055920569205792058920599206092061920629206392064920659206692067920689206992070920719207292073920749207592076920779207892079920809208192082920839208492085920869208792088920899209092091920929209392094920959209692097920989209992100921019210292103921049210592106921079210892109921109211192112921139211492115921169211792118921199212092121921229212392124921259212692127921289212992130921319213292133921349213592136921379213892139921409214192142921439214492145921469214792148921499215092151921529215392154921559215692157921589215992160921619216292163921649216592166921679216892169921709217192172921739217492175921769217792178921799218092181921829218392184921859218692187921889218992190921919219292193921949219592196921979219892199922009220192202922039220492205922069220792208922099221092211922129221392214922159221692217922189221992220922219222292223922249222592226922279222892229922309223192232922339223492235922369223792238922399224092241922429224392244922459224692247922489224992250922519225292253922549225592256922579225892259922609226192262922639226492265922669226792268922699227092271922729227392274922759227692277922789227992280922819228292283922849228592286922879228892289922909229192292922939229492295922969229792298922999230092301923029230392304923059230692307923089230992310923119231292313923149231592316923179231892319923209232192322923239232492325923269232792328923299233092331923329233392334923359233692337923389233992340923419234292343923449234592346923479234892349923509235192352923539235492355923569235792358923599236092361923629236392364923659236692367923689236992370923719237292373923749237592376923779237892379923809238192382923839238492385923869238792388923899239092391923929239392394923959239692397923989239992400924019240292403924049240592406924079240892409924109241192412924139241492415924169241792418924199242092421924229242392424924259242692427924289242992430924319243292433924349243592436924379243892439924409244192442924439244492445924469244792448924499245092451924529245392454924559245692457924589245992460924619246292463924649246592466924679246892469924709247192472924739247492475924769247792478924799248092481924829248392484924859248692487924889248992490924919249292493924949249592496924979249892499925009250192502925039250492505925069250792508925099251092511925129251392514925159251692517925189251992520925219252292523925249252592526925279252892529925309253192532925339253492535925369253792538925399254092541925429254392544925459254692547925489254992550925519255292553925549255592556925579255892559925609256192562925639256492565925669256792568925699257092571925729257392574925759257692577925789257992580925819258292583925849258592586925879258892589925909259192592925939259492595925969259792598925999260092601926029260392604926059260692607926089260992610926119261292613926149261592616926179261892619926209262192622926239262492625926269262792628926299263092631926329263392634926359263692637926389263992640926419264292643926449264592646926479264892649926509265192652926539265492655926569265792658926599266092661926629266392664926659266692667926689266992670926719267292673926749267592676926779267892679926809268192682926839268492685926869268792688926899269092691926929269392694926959269692697926989269992700927019270292703927049270592706927079270892709927109271192712927139271492715927169271792718927199272092721927229272392724927259272692727927289272992730927319273292733927349273592736927379273892739927409274192742927439274492745927469274792748927499275092751927529275392754927559275692757927589275992760927619276292763927649276592766927679276892769927709277192772927739277492775927769277792778927799278092781927829278392784927859278692787927889278992790927919279292793927949279592796927979279892799928009280192802928039280492805928069280792808928099281092811928129281392814928159281692817928189281992820928219282292823928249282592826928279282892829928309283192832928339283492835928369283792838928399284092841928429284392844928459284692847928489284992850928519285292853928549285592856928579285892859928609286192862928639286492865928669286792868928699287092871928729287392874928759287692877928789287992880928819288292883928849288592886928879288892889928909289192892928939289492895928969289792898928999290092901929029290392904929059290692907929089290992910929119291292913929149291592916929179291892919929209292192922929239292492925929269292792928929299293092931929329293392934929359293692937929389293992940929419294292943929449294592946929479294892949929509295192952929539295492955929569295792958929599296092961929629296392964929659296692967929689296992970929719297292973929749297592976929779297892979929809298192982929839298492985929869298792988929899299092991929929299392994929959299692997929989299993000930019300293003930049300593006930079300893009930109301193012930139301493015930169301793018930199302093021930229302393024930259302693027930289302993030930319303293033930349303593036930379303893039930409304193042930439304493045930469304793048930499305093051930529305393054930559305693057930589305993060930619306293063930649306593066930679306893069930709307193072930739307493075930769307793078930799308093081930829308393084930859308693087930889308993090930919309293093930949309593096930979309893099931009310193102931039310493105931069310793108931099311093111931129311393114931159311693117931189311993120931219312293123931249312593126931279312893129931309313193132931339313493135931369313793138931399314093141931429314393144931459314693147931489314993150931519315293153931549315593156931579315893159931609316193162931639316493165931669316793168931699317093171931729317393174931759317693177931789317993180931819318293183931849318593186931879318893189931909319193192931939319493195931969319793198931999320093201932029320393204932059320693207932089320993210932119321293213932149321593216932179321893219932209322193222932239322493225932269322793228932299323093231932329323393234932359323693237932389323993240932419324293243932449324593246932479324893249932509325193252932539325493255932569325793258932599326093261932629326393264932659326693267932689326993270932719327293273932749327593276932779327893279932809328193282932839328493285932869328793288932899329093291932929329393294932959329693297932989329993300933019330293303933049330593306933079330893309933109331193312933139331493315933169331793318933199332093321933229332393324933259332693327933289332993330933319333293333933349333593336933379333893339933409334193342933439334493345933469334793348933499335093351933529335393354933559335693357933589335993360933619336293363933649336593366933679336893369933709337193372933739337493375933769337793378933799338093381933829338393384933859338693387933889338993390933919339293393933949339593396933979339893399934009340193402934039340493405934069340793408934099341093411934129341393414934159341693417934189341993420934219342293423934249342593426934279342893429934309343193432934339343493435934369343793438934399344093441934429344393444934459344693447934489344993450934519345293453934549345593456934579345893459934609346193462934639346493465934669346793468934699347093471934729347393474934759347693477934789347993480934819348293483934849348593486934879348893489934909349193492934939349493495934969349793498934999350093501935029350393504935059350693507935089350993510935119351293513935149351593516935179351893519935209352193522935239352493525935269352793528935299353093531935329353393534935359353693537935389353993540935419354293543935449354593546935479354893549935509355193552935539355493555935569355793558935599356093561935629356393564935659356693567935689356993570935719357293573935749357593576935779357893579935809358193582935839358493585935869358793588935899359093591935929359393594935959359693597935989359993600936019360293603936049360593606936079360893609936109361193612936139361493615936169361793618936199362093621936229362393624936259362693627936289362993630936319363293633936349363593636936379363893639936409364193642936439364493645936469364793648936499365093651936529365393654936559365693657936589365993660936619366293663936649366593666936679366893669936709367193672936739367493675936769367793678936799368093681936829368393684936859368693687936889368993690936919369293693936949369593696936979369893699937009370193702937039370493705937069370793708937099371093711937129371393714937159371693717937189371993720937219372293723937249372593726937279372893729937309373193732937339373493735937369373793738937399374093741937429374393744937459374693747937489374993750937519375293753937549375593756937579375893759937609376193762937639376493765937669376793768937699377093771937729377393774937759377693777937789377993780937819378293783937849378593786937879378893789937909379193792937939379493795937969379793798937999380093801938029380393804938059380693807938089380993810938119381293813938149381593816938179381893819938209382193822938239382493825938269382793828938299383093831938329383393834938359383693837938389383993840938419384293843938449384593846938479384893849938509385193852938539385493855938569385793858938599386093861938629386393864938659386693867938689386993870938719387293873938749387593876938779387893879938809388193882938839388493885938869388793888938899389093891938929389393894938959389693897938989389993900939019390293903939049390593906939079390893909939109391193912939139391493915939169391793918939199392093921939229392393924939259392693927939289392993930939319393293933939349393593936939379393893939939409394193942939439394493945939469394793948939499395093951939529395393954939559395693957939589395993960939619396293963939649396593966939679396893969939709397193972939739397493975939769397793978939799398093981939829398393984939859398693987939889398993990939919399293993939949399593996939979399893999940009400194002940039400494005940069400794008940099401094011940129401394014940159401694017940189401994020940219402294023940249402594026940279402894029940309403194032940339403494035940369403794038940399404094041940429404394044940459404694047940489404994050940519405294053940549405594056940579405894059940609406194062940639406494065940669406794068940699407094071940729407394074940759407694077940789407994080940819408294083940849408594086940879408894089940909409194092940939409494095940969409794098940999410094101941029410394104941059410694107941089410994110941119411294113941149411594116941179411894119941209412194122941239412494125941269412794128941299413094131941329413394134941359413694137941389413994140941419414294143941449414594146941479414894149941509415194152941539415494155941569415794158941599416094161941629416394164941659416694167941689416994170941719417294173941749417594176941779417894179941809418194182941839418494185941869418794188941899419094191941929419394194941959419694197941989419994200942019420294203942049420594206942079420894209942109421194212942139421494215942169421794218942199422094221942229422394224942259422694227942289422994230942319423294233942349423594236942379423894239942409424194242942439424494245942469424794248942499425094251942529425394254942559425694257942589425994260942619426294263942649426594266942679426894269942709427194272942739427494275942769427794278942799428094281942829428394284942859428694287942889428994290942919429294293942949429594296942979429894299943009430194302943039430494305943069430794308943099431094311943129431394314943159431694317943189431994320943219432294323943249432594326943279432894329943309433194332943339433494335943369433794338943399434094341943429434394344943459434694347943489434994350943519435294353943549435594356943579435894359943609436194362943639436494365943669436794368943699437094371943729437394374943759437694377943789437994380943819438294383943849438594386943879438894389943909439194392943939439494395943969439794398943999440094401944029440394404944059440694407944089440994410944119441294413944149441594416944179441894419944209442194422944239442494425944269442794428944299443094431944329443394434944359443694437944389443994440944419444294443944449444594446944479444894449944509445194452944539445494455944569445794458944599446094461944629446394464944659446694467944689446994470944719447294473944749447594476944779447894479944809448194482944839448494485944869448794488944899449094491944929449394494944959449694497944989449994500945019450294503945049450594506945079450894509945109451194512945139451494515945169451794518945199452094521945229452394524945259452694527945289452994530945319453294533945349453594536945379453894539945409454194542945439454494545945469454794548945499455094551945529455394554945559455694557945589455994560945619456294563945649456594566945679456894569945709457194572945739457494575945769457794578945799458094581945829458394584945859458694587945889458994590945919459294593945949459594596945979459894599946009460194602946039460494605946069460794608946099461094611946129461394614946159461694617946189461994620946219462294623946249462594626946279462894629946309463194632946339463494635946369463794638946399464094641946429464394644946459464694647946489464994650946519465294653946549465594656946579465894659946609466194662946639466494665946669466794668946699467094671946729467394674946759467694677946789467994680946819468294683946849468594686946879468894689946909469194692946939469494695946969469794698946999470094701947029470394704947059470694707947089470994710947119471294713947149471594716947179471894719947209472194722947239472494725947269472794728947299473094731947329473394734947359473694737947389473994740947419474294743947449474594746947479474894749947509475194752947539475494755947569475794758947599476094761947629476394764947659476694767947689476994770947719477294773947749477594776947779477894779947809478194782947839478494785947869478794788947899479094791947929479394794947959479694797947989479994800948019480294803948049480594806948079480894809948109481194812948139481494815948169481794818948199482094821948229482394824948259482694827948289482994830948319483294833948349483594836948379483894839948409484194842948439484494845948469484794848948499485094851948529485394854948559485694857948589485994860948619486294863948649486594866948679486894869948709487194872948739487494875948769487794878948799488094881948829488394884948859488694887948889488994890948919489294893948949489594896948979489894899949009490194902949039490494905949069490794908949099491094911949129491394914949159491694917949189491994920949219492294923949249492594926949279492894929949309493194932949339493494935949369493794938949399494094941949429494394944949459494694947949489494994950949519495294953949549495594956949579495894959949609496194962949639496494965949669496794968949699497094971949729497394974949759497694977949789497994980949819498294983949849498594986949879498894989949909499194992949939499494995949969499794998949999500095001950029500395004950059500695007950089500995010950119501295013950149501595016950179501895019950209502195022950239502495025950269502795028950299503095031950329503395034950359503695037950389503995040950419504295043950449504595046950479504895049950509505195052950539505495055950569505795058950599506095061950629506395064950659506695067950689506995070950719507295073950749507595076950779507895079950809508195082950839508495085950869508795088950899509095091950929509395094950959509695097950989509995100951019510295103951049510595106951079510895109951109511195112951139511495115951169511795118951199512095121951229512395124951259512695127951289512995130951319513295133951349513595136951379513895139951409514195142951439514495145951469514795148951499515095151951529515395154951559515695157951589515995160951619516295163951649516595166951679516895169951709517195172951739517495175951769517795178951799518095181951829518395184951859518695187951889518995190951919519295193951949519595196951979519895199952009520195202952039520495205952069520795208952099521095211952129521395214952159521695217952189521995220952219522295223952249522595226952279522895229952309523195232952339523495235952369523795238952399524095241952429524395244952459524695247952489524995250952519525295253952549525595256952579525895259952609526195262952639526495265952669526795268952699527095271952729527395274952759527695277952789527995280952819528295283952849528595286952879528895289952909529195292952939529495295952969529795298952999530095301953029530395304953059530695307953089530995310953119531295313953149531595316953179531895319953209532195322953239532495325953269532795328953299533095331953329533395334953359533695337953389533995340953419534295343953449534595346953479534895349953509535195352953539535495355953569535795358953599536095361953629536395364953659536695367953689536995370953719537295373953749537595376953779537895379953809538195382953839538495385953869538795388953899539095391953929539395394953959539695397953989539995400954019540295403954049540595406954079540895409954109541195412954139541495415954169541795418954199542095421954229542395424954259542695427954289542995430954319543295433954349543595436954379543895439954409544195442954439544495445954469544795448954499545095451954529545395454954559545695457954589545995460954619546295463954649546595466954679546895469954709547195472954739547495475954769547795478954799548095481954829548395484954859548695487954889548995490954919549295493954949549595496954979549895499955009550195502955039550495505955069550795508955099551095511955129551395514955159551695517955189551995520955219552295523955249552595526955279552895529955309553195532955339553495535955369553795538955399554095541955429554395544955459554695547955489554995550955519555295553955549555595556955579555895559955609556195562955639556495565955669556795568955699557095571955729557395574955759557695577955789557995580955819558295583955849558595586955879558895589955909559195592955939559495595955969559795598955999560095601956029560395604956059560695607956089560995610956119561295613956149561595616956179561895619956209562195622956239562495625956269562795628956299563095631956329563395634956359563695637956389563995640956419564295643956449564595646956479564895649956509565195652956539565495655956569565795658956599566095661956629566395664956659566695667956689566995670956719567295673956749567595676956779567895679956809568195682956839568495685956869568795688956899569095691956929569395694956959569695697956989569995700957019570295703957049570595706957079570895709957109571195712957139571495715957169571795718957199572095721957229572395724957259572695727957289572995730957319573295733957349573595736957379573895739957409574195742957439574495745957469574795748957499575095751957529575395754957559575695757957589575995760957619576295763957649576595766957679576895769957709577195772957739577495775957769577795778957799578095781957829578395784957859578695787957889578995790957919579295793957949579595796957979579895799958009580195802958039580495805958069580795808958099581095811958129581395814958159581695817958189581995820958219582295823958249582595826958279582895829958309583195832958339583495835958369583795838958399584095841958429584395844958459584695847958489584995850958519585295853958549585595856958579585895859958609586195862958639586495865958669586795868958699587095871958729587395874958759587695877958789587995880958819588295883958849588595886958879588895889958909589195892958939589495895958969589795898958999590095901959029590395904959059590695907959089590995910959119591295913959149591595916959179591895919959209592195922959239592495925959269592795928959299593095931959329593395934959359593695937959389593995940959419594295943959449594595946959479594895949959509595195952959539595495955959569595795958959599596095961959629596395964959659596695967959689596995970959719597295973959749597595976959779597895979959809598195982959839598495985959869598795988959899599095991959929599395994959959599695997959989599996000960019600296003960049600596006960079600896009960109601196012960139601496015960169601796018960199602096021960229602396024960259602696027960289602996030960319603296033960349603596036960379603896039960409604196042960439604496045960469604796048960499605096051960529605396054960559605696057960589605996060960619606296063960649606596066960679606896069960709607196072960739607496075960769607796078960799608096081960829608396084960859608696087960889608996090960919609296093960949609596096960979609896099961009610196102961039610496105961069610796108961099611096111961129611396114961159611696117961189611996120961219612296123961249612596126961279612896129961309613196132961339613496135961369613796138961399614096141961429614396144961459614696147961489614996150961519615296153961549615596156961579615896159961609616196162961639616496165961669616796168961699617096171961729617396174961759617696177961789617996180961819618296183961849618596186961879618896189961909619196192961939619496195961969619796198961999620096201962029620396204962059620696207962089620996210962119621296213962149621596216962179621896219962209622196222962239622496225962269622796228962299623096231962329623396234962359623696237962389623996240962419624296243962449624596246962479624896249962509625196252962539625496255962569625796258962599626096261962629626396264962659626696267962689626996270962719627296273962749627596276962779627896279962809628196282962839628496285962869628796288962899629096291962929629396294962959629696297962989629996300963019630296303963049630596306963079630896309963109631196312963139631496315963169631796318963199632096321963229632396324963259632696327963289632996330963319633296333963349633596336963379633896339963409634196342963439634496345963469634796348963499635096351963529635396354963559635696357963589635996360963619636296363963649636596366963679636896369963709637196372963739637496375963769637796378963799638096381963829638396384963859638696387963889638996390963919639296393963949639596396963979639896399964009640196402964039640496405964069640796408964099641096411964129641396414964159641696417964189641996420964219642296423964249642596426964279642896429964309643196432964339643496435964369643796438964399644096441964429644396444964459644696447964489644996450964519645296453964549645596456964579645896459964609646196462964639646496465964669646796468964699647096471964729647396474964759647696477964789647996480964819648296483964849648596486964879648896489964909649196492964939649496495964969649796498964999650096501965029650396504965059650696507965089650996510965119651296513965149651596516965179651896519965209652196522965239652496525965269652796528965299653096531965329653396534965359653696537965389653996540965419654296543965449654596546965479654896549965509655196552965539655496555965569655796558965599656096561965629656396564965659656696567965689656996570965719657296573965749657596576965779657896579965809658196582965839658496585965869658796588965899659096591965929659396594965959659696597965989659996600966019660296603966049660596606966079660896609966109661196612966139661496615966169661796618966199662096621966229662396624966259662696627966289662996630966319663296633966349663596636966379663896639966409664196642966439664496645966469664796648966499665096651966529665396654966559665696657966589665996660966619666296663966649666596666966679666896669966709667196672966739667496675966769667796678966799668096681966829668396684966859668696687966889668996690966919669296693966949669596696966979669896699967009670196702967039670496705967069670796708967099671096711967129671396714967159671696717967189671996720967219672296723967249672596726967279672896729967309673196732967339673496735967369673796738967399674096741967429674396744967459674696747967489674996750967519675296753967549675596756967579675896759967609676196762967639676496765967669676796768967699677096771967729677396774967759677696777967789677996780967819678296783967849678596786967879678896789967909679196792967939679496795967969679796798967999680096801968029680396804968059680696807968089680996810968119681296813968149681596816968179681896819968209682196822968239682496825968269682796828968299683096831968329683396834968359683696837968389683996840968419684296843968449684596846968479684896849968509685196852968539685496855968569685796858968599686096861968629686396864968659686696867968689686996870968719687296873968749687596876968779687896879968809688196882968839688496885968869688796888968899689096891968929689396894968959689696897968989689996900969019690296903969049690596906969079690896909969109691196912969139691496915969169691796918969199692096921969229692396924969259692696927969289692996930969319693296933969349693596936969379693896939969409694196942969439694496945969469694796948969499695096951969529695396954969559695696957969589695996960969619696296963969649696596966969679696896969969709697196972969739697496975969769697796978969799698096981969829698396984969859698696987969889698996990969919699296993969949699596996969979699896999970009700197002970039700497005970069700797008970099701097011970129701397014970159701697017970189701997020970219702297023970249702597026970279702897029970309703197032970339703497035970369703797038970399704097041970429704397044970459704697047970489704997050970519705297053970549705597056970579705897059970609706197062970639706497065970669706797068970699707097071970729707397074970759707697077970789707997080970819708297083970849708597086970879708897089970909709197092970939709497095970969709797098970999710097101971029710397104971059710697107971089710997110971119711297113971149711597116971179711897119971209712197122971239712497125971269712797128971299713097131971329713397134971359713697137971389713997140971419714297143971449714597146971479714897149971509715197152971539715497155971569715797158971599716097161971629716397164971659716697167971689716997170971719717297173971749717597176971779717897179971809718197182971839718497185971869718797188971899719097191971929719397194971959719697197971989719997200972019720297203972049720597206972079720897209972109721197212972139721497215972169721797218972199722097221972229722397224972259722697227972289722997230972319723297233972349723597236972379723897239972409724197242972439724497245972469724797248972499725097251972529725397254972559725697257972589725997260972619726297263972649726597266972679726897269972709727197272972739727497275972769727797278972799728097281972829728397284972859728697287972889728997290972919729297293972949729597296972979729897299973009730197302973039730497305973069730797308973099731097311973129731397314973159731697317973189731997320973219732297323973249732597326973279732897329973309733197332973339733497335973369733797338973399734097341973429734397344973459734697347973489734997350973519735297353973549735597356973579735897359973609736197362973639736497365973669736797368973699737097371973729737397374973759737697377973789737997380973819738297383973849738597386973879738897389973909739197392973939739497395973969739797398973999740097401974029740397404974059740697407974089740997410974119741297413974149741597416974179741897419974209742197422974239742497425974269742797428974299743097431974329743397434974359743697437974389743997440974419744297443974449744597446974479744897449974509745197452974539745497455974569745797458974599746097461974629746397464974659746697467974689746997470974719747297473974749747597476974779747897479974809748197482974839748497485974869748797488974899749097491974929749397494974959749697497974989749997500975019750297503975049750597506975079750897509975109751197512975139751497515975169751797518975199752097521975229752397524975259752697527975289752997530975319753297533975349753597536975379753897539975409754197542975439754497545975469754797548975499755097551975529755397554975559755697557975589755997560975619756297563975649756597566975679756897569975709757197572975739757497575975769757797578975799758097581975829758397584975859758697587975889758997590975919759297593975949759597596975979759897599976009760197602976039760497605976069760797608976099761097611976129761397614976159761697617976189761997620976219762297623976249762597626976279762897629976309763197632976339763497635976369763797638976399764097641976429764397644976459764697647976489764997650976519765297653976549765597656976579765897659976609766197662976639766497665976669766797668976699767097671976729767397674976759767697677976789767997680976819768297683976849768597686976879768897689976909769197692976939769497695976969769797698976999770097701977029770397704977059770697707977089770997710977119771297713977149771597716977179771897719977209772197722977239772497725977269772797728977299773097731977329773397734977359773697737977389773997740977419774297743977449774597746977479774897749977509775197752977539775497755977569775797758977599776097761977629776397764977659776697767977689776997770977719777297773977749777597776977779777897779977809778197782977839778497785977869778797788977899779097791977929779397794977959779697797977989779997800978019780297803978049780597806978079780897809978109781197812978139781497815978169781797818978199782097821978229782397824978259782697827978289782997830978319783297833978349783597836978379783897839978409784197842978439784497845978469784797848978499785097851978529785397854978559785697857978589785997860978619786297863978649786597866978679786897869978709787197872978739787497875978769787797878978799788097881978829788397884978859788697887978889788997890978919789297893978949789597896978979789897899979009790197902979039790497905979069790797908979099791097911979129791397914979159791697917979189791997920979219792297923979249792597926979279792897929979309793197932979339793497935979369793797938979399794097941979429794397944979459794697947979489794997950979519795297953979549795597956979579795897959979609796197962979639796497965979669796797968979699797097971979729797397974979759797697977979789797997980979819798297983979849798597986979879798897989979909799197992979939799497995979969799797998979999800098001980029800398004980059800698007980089800998010980119801298013980149801598016980179801898019980209802198022980239802498025980269802798028980299803098031980329803398034980359803698037980389803998040980419804298043980449804598046980479804898049980509805198052980539805498055980569805798058980599806098061980629806398064980659806698067980689806998070980719807298073980749807598076980779807898079980809808198082980839808498085980869808798088980899809098091980929809398094980959809698097980989809998100981019810298103981049810598106981079810898109981109811198112981139811498115981169811798118981199812098121981229812398124981259812698127981289812998130981319813298133981349813598136981379813898139981409814198142981439814498145981469814798148981499815098151981529815398154981559815698157981589815998160981619816298163981649816598166981679816898169981709817198172981739817498175981769817798178981799818098181981829818398184981859818698187981889818998190981919819298193981949819598196981979819898199982009820198202982039820498205982069820798208982099821098211982129821398214982159821698217982189821998220982219822298223982249822598226982279822898229982309823198232982339823498235982369823798238982399824098241982429824398244982459824698247982489824998250982519825298253982549825598256982579825898259982609826198262982639826498265982669826798268982699827098271982729827398274982759827698277982789827998280982819828298283982849828598286982879828898289982909829198292982939829498295982969829798298982999830098301983029830398304983059830698307983089830998310983119831298313983149831598316983179831898319983209832198322983239832498325983269832798328983299833098331983329833398334983359833698337983389833998340983419834298343983449834598346983479834898349983509835198352983539835498355983569835798358983599836098361983629836398364983659836698367983689836998370983719837298373983749837598376983779837898379983809838198382983839838498385983869838798388983899839098391983929839398394983959839698397983989839998400984019840298403984049840598406984079840898409984109841198412984139841498415984169841798418984199842098421984229842398424984259842698427984289842998430984319843298433984349843598436984379843898439984409844198442984439844498445984469844798448984499845098451984529845398454984559845698457984589845998460984619846298463984649846598466984679846898469984709847198472984739847498475984769847798478984799848098481984829848398484984859848698487984889848998490984919849298493984949849598496984979849898499985009850198502985039850498505985069850798508985099851098511985129851398514985159851698517985189851998520985219852298523985249852598526985279852898529985309853198532985339853498535985369853798538985399854098541985429854398544985459854698547985489854998550985519855298553985549855598556985579855898559985609856198562985639856498565985669856798568985699857098571985729857398574985759857698577985789857998580985819858298583985849858598586985879858898589985909859198592985939859498595985969859798598985999860098601986029860398604986059860698607986089860998610986119861298613986149861598616986179861898619986209862198622986239862498625986269862798628986299863098631986329863398634986359863698637986389863998640986419864298643986449864598646986479864898649986509865198652986539865498655986569865798658986599866098661986629866398664986659866698667986689866998670986719867298673986749867598676986779867898679986809868198682986839868498685986869868798688986899869098691986929869398694986959869698697986989869998700987019870298703987049870598706987079870898709987109871198712987139871498715987169871798718987199872098721987229872398724987259872698727987289872998730987319873298733987349873598736987379873898739987409874198742987439874498745987469874798748987499875098751987529875398754987559875698757987589875998760987619876298763987649876598766987679876898769987709877198772987739877498775987769877798778987799878098781987829878398784987859878698787987889878998790987919879298793987949879598796987979879898799988009880198802988039880498805988069880798808988099881098811988129881398814988159881698817988189881998820988219882298823988249882598826988279882898829988309883198832988339883498835988369883798838988399884098841988429884398844988459884698847988489884998850988519885298853988549885598856988579885898859988609886198862988639886498865988669886798868988699887098871988729887398874988759887698877988789887998880988819888298883988849888598886988879888898889988909889198892988939889498895988969889798898988999890098901989029890398904989059890698907989089890998910989119891298913989149891598916989179891898919989209892198922989239892498925989269892798928989299893098931989329893398934989359893698937989389893998940989419894298943989449894598946989479894898949989509895198952989539895498955989569895798958989599896098961989629896398964989659896698967989689896998970989719897298973989749897598976989779897898979989809898198982989839898498985989869898798988989899899098991989929899398994989959899698997989989899999000990019900299003990049900599006990079900899009990109901199012990139901499015990169901799018990199902099021990229902399024990259902699027990289902999030990319903299033990349903599036990379903899039990409904199042990439904499045990469904799048990499905099051990529905399054990559905699057990589905999060990619906299063990649906599066990679906899069990709907199072990739907499075990769907799078990799908099081990829908399084990859908699087990889908999090990919909299093990949909599096990979909899099991009910199102991039910499105991069910799108991099911099111991129911399114991159911699117991189911999120991219912299123991249912599126991279912899129991309913199132991339913499135991369913799138991399914099141991429914399144991459914699147991489914999150991519915299153991549915599156991579915899159991609916199162991639916499165991669916799168991699917099171991729917399174991759917699177991789917999180991819918299183991849918599186991879918899189991909919199192991939919499195991969919799198991999920099201992029920399204992059920699207992089920999210992119921299213992149921599216992179921899219992209922199222992239922499225992269922799228992299923099231992329923399234992359923699237992389923999240992419924299243992449924599246992479924899249992509925199252992539925499255992569925799258992599926099261992629926399264992659926699267992689926999270992719927299273992749927599276992779927899279992809928199282992839928499285992869928799288992899929099291992929929399294992959929699297992989929999300993019930299303993049930599306993079930899309993109931199312993139931499315993169931799318993199932099321993229932399324993259932699327993289932999330993319933299333993349933599336993379933899339993409934199342993439934499345993469934799348993499935099351993529935399354993559935699357993589935999360993619936299363993649936599366993679936899369993709937199372993739937499375993769937799378993799938099381993829938399384993859938699387993889938999390993919939299393993949939599396993979939899399994009940199402994039940499405994069940799408994099941099411994129941399414994159941699417994189941999420994219942299423994249942599426994279942899429994309943199432994339943499435994369943799438994399944099441994429944399444994459944699447994489944999450994519945299453994549945599456994579945899459994609946199462994639946499465994669946799468994699947099471994729947399474994759947699477994789947999480994819948299483994849948599486994879948899489994909949199492994939949499495994969949799498994999950099501995029950399504995059950699507995089950999510995119951299513995149951599516995179951899519995209952199522995239952499525995269952799528995299953099531995329953399534995359953699537995389953999540995419954299543995449954599546995479954899549995509955199552995539955499555995569955799558995599956099561995629956399564995659956699567995689956999570995719957299573995749957599576995779957899579995809958199582995839958499585995869958799588995899959099591995929959399594995959959699597995989959999600996019960299603996049960599606996079960899609996109961199612996139961499615996169961799618996199962099621996229962399624996259962699627996289962999630996319963299633996349963599636996379963899639996409964199642996439964499645996469964799648996499965099651996529965399654996559965699657996589965999660996619966299663996649966599666996679966899669996709967199672996739967499675996769967799678996799968099681996829968399684996859968699687996889968999690996919969299693996949969599696996979969899699997009970199702997039970499705997069970799708997099971099711997129971399714997159971699717997189971999720997219972299723997249972599726997279972899729997309973199732997339973499735997369973799738997399974099741997429974399744997459974699747997489974999750997519975299753997549975599756997579975899759997609976199762997639976499765997669976799768997699977099771997729977399774997759977699777997789977999780997819978299783997849978599786997879978899789997909979199792997939979499795997969979799798997999980099801998029980399804998059980699807998089980999810998119981299813998149981599816998179981899819998209982199822998239982499825998269982799828998299983099831998329983399834998359983699837998389983999840998419984299843998449984599846998479984899849998509985199852998539985499855998569985799858998599986099861998629986399864998659986699867998689986999870998719987299873998749987599876998779987899879998809988199882998839988499885998869988799888998899989099891998929989399894998959989699897998989989999900999019990299903999049990599906999079990899909999109991199912999139991499915999169991799918999199992099921999229992399924999259992699927999289992999930999319993299933999349993599936999379993899939999409994199942999439994499945999469994799948999499995099951999529995399954999559995699957999589995999960999619996299963999649996599966999679996899969999709997199972999739997499975999769997799978999799998099981999829998399984999859998699987999889998999990999919999299993999949999599996999979999899999100000100001100002100003100004100005100006100007100008100009100010100011100012100013100014100015100016100017100018100019100020100021100022100023100024100025100026100027100028100029100030100031100032100033100034100035100036100037100038100039100040100041100042100043100044100045100046100047100048100049100050100051100052100053100054100055100056100057100058100059100060100061100062100063100064100065100066100067100068100069100070100071100072100073100074100075100076100077100078100079100080100081100082100083100084100085100086100087100088100089100090100091100092100093100094100095100096100097100098100099100100100101100102100103100104100105100106100107100108100109100110100111100112100113100114100115100116100117100118100119100120100121100122100123100124100125100126100127100128100129100130100131100132100133100134100135100136100137100138100139100140100141100142100143100144100145100146100147100148100149100150100151100152100153100154100155100156100157100158100159100160100161100162100163100164100165100166100167100168100169100170100171100172100173100174100175100176100177100178100179100180100181100182100183100184100185100186100187100188100189100190100191100192100193100194100195100196100197100198100199100200100201100202100203100204100205100206100207100208100209100210100211100212100213100214100215100216100217100218100219100220100221100222100223100224100225100226100227100228100229100230100231100232100233100234100235100236100237100238100239100240100241100242100243100244100245100246100247100248100249100250100251100252100253100254100255100256100257100258100259100260100261100262100263100264100265100266100267100268100269100270100271100272100273100274100275100276100277100278100279100280100281100282100283100284100285100286100287100288100289100290100291100292100293100294100295100296100297100298100299100300100301100302100303100304100305100306100307100308100309100310100311100312100313100314100315100316100317100318100319100320100321100322100323100324100325100326100327100328100329100330100331100332100333100334100335100336100337100338100339100340100341100342100343100344100345100346100347100348100349100350100351100352100353100354100355100356100357100358100359100360100361100362100363100364100365100366100367100368100369100370100371100372100373100374100375100376100377100378100379100380100381100382100383100384100385100386100387100388100389100390100391100392100393100394100395100396100397100398100399100400100401100402100403100404100405100406100407100408100409100410100411100412100413100414100415100416100417100418100419100420100421100422100423100424100425100426100427100428100429100430100431100432100433100434100435100436100437100438100439100440100441100442100443100444100445100446100447100448100449100450100451100452100453100454100455100456100457100458100459100460100461100462100463100464100465100466100467100468100469100470100471100472100473100474100475100476100477100478100479100480100481100482100483100484100485100486100487100488100489100490100491100492100493100494100495100496100497100498100499100500100501100502100503100504100505100506100507100508100509100510100511100512100513100514100515100516100517100518100519100520100521100522100523100524100525100526100527100528100529100530100531100532100533100534100535100536100537100538100539100540100541100542100543100544100545100546100547100548100549100550100551100552100553100554100555100556100557100558100559100560100561100562100563100564100565100566100567100568100569100570100571100572100573100574100575100576100577100578100579100580100581100582100583100584100585100586100587100588100589100590100591100592100593100594100595100596100597100598100599100600100601100602100603100604100605100606100607100608100609100610100611100612100613100614100615100616100617100618100619100620100621100622100623100624100625100626100627100628100629100630100631100632100633100634100635100636100637100638100639100640100641100642100643100644100645100646100647100648100649100650100651100652100653100654100655100656100657100658100659100660100661100662100663100664100665100666100667100668100669100670100671100672100673100674100675100676100677100678100679100680100681100682100683100684100685100686100687100688100689100690100691100692100693100694100695100696100697100698100699100700100701100702100703100704100705100706100707100708100709100710100711100712100713100714100715100716100717100718100719100720100721100722100723100724100725100726100727100728100729100730100731100732100733100734100735100736100737100738100739100740100741100742100743100744100745100746100747100748100749100750100751100752100753100754100755100756100757100758100759100760100761100762100763100764100765100766100767100768100769100770100771100772100773100774100775100776100777100778100779100780100781100782100783100784100785100786100787100788100789100790100791100792100793100794100795100796100797100798100799100800100801100802100803100804100805100806100807100808100809100810100811100812100813100814100815100816100817100818100819100820100821100822100823100824100825100826100827100828100829100830100831100832100833100834100835100836100837100838100839100840100841100842100843100844100845100846100847100848100849100850100851100852100853100854100855100856100857100858100859100860100861100862100863100864100865100866100867100868100869100870100871100872100873100874100875100876100877100878100879100880100881100882100883100884100885100886100887100888100889100890100891100892100893100894100895100896100897100898100899100900100901100902100903100904100905100906100907100908100909100910100911100912100913100914100915100916100917100918100919100920100921100922100923100924100925100926100927100928100929100930100931100932100933100934100935100936100937100938100939100940100941100942100943100944100945100946100947100948100949100950100951100952100953100954100955100956100957100958100959100960100961100962100963100964100965100966100967100968100969100970100971100972100973100974100975100976100977100978100979100980100981100982100983100984100985100986100987100988100989100990100991100992100993100994100995100996100997100998100999101000101001101002101003101004101005101006101007101008101009101010101011101012101013101014101015101016101017101018101019101020101021101022101023101024101025101026101027101028101029101030101031101032101033101034101035101036101037101038101039101040101041101042101043101044101045101046101047101048101049101050101051101052101053101054101055101056101057101058101059101060101061101062101063101064101065101066101067101068101069101070101071101072101073101074101075101076101077101078101079101080101081101082101083101084101085101086101087101088101089101090101091101092101093101094101095101096101097101098101099101100101101101102101103101104101105101106101107101108101109101110101111101112101113101114101115101116101117101118101119101120101121101122101123101124101125101126101127101128101129101130101131101132101133101134101135101136101137101138101139101140101141101142101143101144101145101146101147101148101149101150101151101152101153101154101155101156101157101158101159101160101161101162101163101164101165101166101167101168101169101170101171101172101173101174101175101176101177101178101179101180101181101182101183101184101185101186101187101188101189101190101191101192101193101194101195101196101197101198101199101200101201101202101203101204101205101206101207101208101209101210101211101212101213101214101215101216101217101218101219101220101221101222101223101224101225101226101227101228101229101230101231101232101233101234101235101236101237101238101239101240101241101242101243101244101245101246101247101248101249101250101251101252101253101254101255101256101257101258101259101260101261101262101263101264101265101266101267101268101269101270101271101272101273101274101275101276101277101278101279101280101281101282101283101284101285101286101287101288101289101290101291101292101293101294101295101296101297101298101299101300101301101302101303101304101305101306101307101308101309101310101311101312101313101314101315101316101317101318101319101320101321101322101323101324101325101326101327101328101329101330101331101332101333101334101335101336101337101338101339101340101341101342101343101344101345101346101347101348101349101350101351101352101353101354101355101356101357101358101359101360101361101362101363101364101365101366101367101368101369101370101371101372101373101374101375101376101377101378101379101380101381101382101383101384101385101386101387101388101389101390101391101392101393101394101395101396101397101398101399101400101401101402101403101404101405101406101407101408101409101410101411101412101413101414101415101416101417101418101419101420101421101422101423101424101425101426101427101428101429101430101431101432101433101434101435101436101437101438101439101440101441101442101443101444101445101446101447101448101449101450101451101452101453101454101455101456101457101458101459101460101461101462101463101464101465101466101467101468101469101470101471101472101473101474101475101476101477101478101479101480101481101482101483101484101485101486101487101488101489101490101491101492101493101494101495101496101497101498101499101500101501101502101503101504101505101506101507101508101509101510101511101512101513101514101515101516101517101518101519101520101521101522101523101524101525101526101527101528101529101530101531101532101533101534101535101536101537101538101539101540101541101542101543101544101545101546101547101548101549101550101551101552101553101554101555101556101557101558101559101560101561101562101563101564101565101566101567101568101569101570101571101572101573101574101575101576101577101578101579101580101581101582101583101584101585101586101587101588101589101590101591101592101593101594101595101596101597101598101599101600101601101602101603101604101605101606101607101608101609101610101611101612101613101614101615101616101617101618101619101620101621101622101623101624101625101626101627101628101629101630101631101632101633101634101635101636101637101638101639101640101641101642101643101644101645101646101647101648101649101650101651101652101653101654101655101656101657101658101659101660101661101662101663101664101665101666101667101668101669101670101671101672101673101674101675101676101677101678101679101680101681101682101683101684101685101686101687101688101689101690101691101692101693101694101695101696101697101698101699101700101701101702101703101704101705101706101707101708101709101710101711101712101713101714101715101716101717101718101719101720101721101722101723101724101725101726101727101728101729101730101731101732101733101734101735101736101737101738101739101740101741101742101743101744101745101746101747101748101749101750101751101752101753101754101755101756101757101758101759101760101761101762101763101764101765101766101767101768101769101770101771101772101773101774101775101776101777101778101779101780101781101782101783101784101785101786101787101788101789101790101791101792101793101794101795101796101797101798101799101800101801101802101803101804101805101806101807101808101809101810101811101812101813101814101815101816101817101818101819101820101821101822101823101824101825101826101827101828101829101830101831101832101833101834101835101836101837101838101839101840101841101842101843101844101845101846101847101848101849101850101851101852101853101854101855101856101857101858101859101860101861101862101863101864101865101866101867101868101869101870101871101872101873101874101875101876101877101878101879101880101881101882101883101884101885101886101887101888101889101890101891101892101893101894101895101896101897101898101899101900101901101902101903101904101905101906101907101908101909101910101911101912101913101914101915101916101917101918101919101920101921101922101923101924101925101926101927101928101929101930101931101932101933101934101935101936101937101938101939101940101941101942101943101944101945101946101947101948101949101950101951101952101953101954101955101956101957101958101959101960101961101962101963101964101965101966101967101968101969101970101971101972101973101974101975101976101977101978101979101980101981101982101983101984101985101986101987101988101989101990101991101992101993101994101995101996101997101998101999102000102001102002102003102004102005102006102007102008102009102010102011102012102013102014102015102016102017102018102019102020102021102022102023102024102025102026102027102028102029102030102031102032102033102034102035102036102037102038102039102040102041102042102043102044102045102046102047102048102049102050102051102052102053102054102055102056102057102058102059102060102061102062102063102064102065102066102067102068102069102070102071102072102073102074102075102076102077102078102079102080102081102082102083102084102085102086102087102088102089102090102091102092102093102094102095102096102097102098102099102100102101102102102103102104102105102106102107102108102109102110102111102112102113102114102115102116102117102118102119102120102121102122102123102124102125102126102127102128102129102130102131102132102133102134102135102136102137102138102139102140102141102142102143102144102145102146102147102148102149102150102151102152102153102154102155102156102157102158102159102160102161102162102163102164102165102166102167102168102169102170102171102172102173102174102175102176102177102178102179102180102181102182102183102184102185102186102187102188102189102190102191102192102193102194102195102196102197102198102199102200102201102202102203102204102205102206102207102208102209102210102211102212102213102214102215102216102217102218102219102220102221102222102223102224102225102226102227102228102229102230102231102232102233102234102235102236102237102238102239102240102241102242102243102244102245102246102247102248102249102250102251102252102253102254102255102256102257102258102259102260102261102262102263102264102265102266102267102268102269102270102271102272102273102274102275102276102277102278102279102280102281102282102283102284102285102286102287102288102289102290102291102292102293102294102295102296102297102298102299102300102301102302102303102304102305102306102307102308102309102310102311102312102313102314102315102316102317102318102319102320102321102322102323102324102325102326102327102328102329102330102331102332102333102334102335102336102337102338102339102340102341102342102343102344102345102346102347102348102349102350102351102352102353102354102355102356102357102358102359102360102361102362102363102364102365102366102367102368102369102370102371102372102373102374102375102376102377102378102379102380102381102382102383102384102385102386102387102388102389102390102391102392102393102394102395102396102397102398102399102400102401102402102403102404102405102406102407102408102409102410102411102412102413102414102415102416102417102418102419102420102421102422102423102424102425102426102427102428102429102430102431102432102433102434102435102436102437102438102439102440102441102442102443102444102445102446102447102448102449102450102451102452102453102454102455102456102457102458102459102460102461102462102463102464102465102466102467102468102469102470102471102472102473102474102475102476102477102478102479102480102481102482102483102484102485102486102487102488102489102490102491102492102493102494102495102496102497102498102499102500102501102502102503102504102505102506102507102508102509102510102511102512102513102514102515102516102517102518102519102520102521102522102523102524102525102526102527102528102529102530102531102532102533102534102535102536102537102538102539102540102541102542102543102544102545102546102547102548102549102550102551102552102553102554102555102556102557102558102559102560102561102562102563102564102565102566102567102568102569102570102571102572102573102574102575102576102577102578102579102580102581102582102583102584102585102586102587102588102589102590102591102592102593102594102595102596102597102598102599102600102601102602102603102604102605102606102607102608102609102610102611102612102613102614102615102616102617102618102619102620102621102622102623102624102625102626102627102628102629102630102631102632102633102634102635102636102637102638102639102640102641102642102643102644102645102646102647102648102649102650102651102652102653102654102655102656102657102658102659102660102661102662102663102664102665102666102667102668102669102670102671102672102673102674102675102676102677102678102679102680102681102682102683102684102685102686102687102688102689102690102691102692102693102694102695102696102697102698102699102700102701102702102703102704102705102706102707102708102709102710102711102712102713102714102715102716102717102718102719102720102721102722102723102724102725102726102727102728102729102730102731102732102733102734102735102736102737102738102739102740102741102742102743102744102745102746102747102748102749102750102751102752102753102754102755102756102757102758102759102760102761102762102763102764102765102766102767102768102769102770102771102772102773102774102775102776102777102778102779102780102781102782102783102784102785102786102787102788102789102790102791102792102793102794102795102796102797102798102799102800102801102802102803102804102805102806102807102808102809102810102811102812102813102814102815102816102817102818102819102820102821102822102823102824102825102826102827102828102829102830102831102832102833102834102835102836102837102838102839102840102841102842102843102844102845102846102847102848102849102850102851102852102853102854102855102856102857102858102859102860102861102862102863102864102865102866102867102868102869102870102871102872102873102874102875102876102877102878102879102880102881102882102883102884102885102886102887102888102889102890102891102892102893102894102895102896102897102898102899102900102901102902102903102904102905102906102907102908102909102910102911102912102913102914102915102916102917102918102919102920102921102922102923102924102925102926102927102928102929102930102931102932102933102934102935102936102937102938102939102940102941102942102943102944102945102946102947102948102949102950102951102952102953102954102955102956102957102958102959102960102961102962102963102964102965102966102967102968102969102970102971102972102973102974102975102976102977102978102979102980102981102982102983102984102985102986102987102988102989102990102991102992102993102994102995102996102997102998102999103000103001103002103003103004103005103006103007103008103009103010103011103012103013103014103015103016103017103018103019103020103021103022103023103024103025103026103027103028103029103030103031103032103033103034103035103036103037103038103039103040103041103042103043103044103045103046103047103048103049103050103051103052103053103054103055103056103057103058103059103060103061103062103063103064103065103066103067103068103069103070103071103072103073103074103075103076103077103078103079103080103081103082103083103084103085103086103087103088103089103090103091103092103093103094103095103096103097103098103099103100103101103102103103103104103105103106103107103108103109103110103111103112103113103114103115103116103117103118103119103120103121103122103123103124103125103126103127103128103129103130103131103132103133103134103135103136103137103138103139103140103141103142103143103144103145103146103147103148103149103150103151103152103153103154103155103156103157103158103159103160103161103162103163103164103165103166103167103168103169103170103171103172103173103174103175103176103177103178103179103180103181103182103183103184103185103186103187103188103189103190103191103192103193103194103195103196103197103198103199103200103201103202103203103204103205103206103207103208103209103210103211103212103213103214103215103216103217103218103219103220103221103222103223103224103225103226103227103228103229103230103231103232103233103234103235103236103237103238103239103240103241103242103243103244103245103246103247103248103249103250103251103252103253103254103255103256103257103258103259103260103261103262103263103264103265103266103267103268103269103270103271103272103273103274103275103276103277103278103279103280103281103282103283103284103285103286103287103288103289103290103291103292103293103294103295103296103297103298103299103300103301103302103303103304103305103306103307103308103309103310103311103312103313103314103315103316103317103318103319103320103321103322103323103324103325103326103327103328103329103330103331103332103333103334103335103336103337103338103339103340103341103342103343103344103345103346103347103348103349103350103351103352103353103354103355103356103357103358103359103360103361103362103363103364103365103366103367103368103369103370103371103372103373103374103375103376103377103378103379103380103381103382103383103384103385103386103387103388103389103390103391103392103393103394103395103396103397103398103399103400103401103402103403103404103405103406103407103408103409103410103411103412103413103414103415103416103417103418103419103420103421103422103423103424103425103426103427103428103429103430103431103432103433103434103435103436103437103438103439103440103441103442103443103444103445103446103447103448103449103450103451103452103453103454103455103456103457103458103459103460103461103462103463103464103465103466103467103468103469103470103471103472103473103474103475103476103477103478103479103480103481103482103483103484103485103486103487103488103489103490103491103492103493103494103495103496103497103498103499103500103501103502103503103504103505103506103507103508103509103510103511103512103513103514103515103516103517103518103519103520103521103522103523103524103525103526103527103528103529103530103531103532103533103534103535103536103537103538103539103540103541103542103543103544103545103546103547103548103549103550103551103552103553103554103555103556103557103558103559103560103561103562103563103564103565103566103567103568103569103570103571103572103573103574103575103576103577103578103579103580103581103582103583103584103585103586103587103588103589103590103591103592103593103594103595103596103597103598103599103600103601103602103603103604103605103606103607103608103609103610103611103612103613103614103615103616103617103618103619103620103621103622103623103624103625103626103627103628103629103630103631103632103633103634103635103636103637103638103639103640103641103642103643103644103645103646103647103648103649103650103651103652103653103654103655103656103657103658103659103660103661103662103663103664103665103666103667103668103669103670103671103672103673103674103675103676103677103678103679103680103681103682103683103684103685103686103687103688103689103690103691103692103693103694103695103696103697103698103699103700103701103702103703103704103705103706103707103708103709103710103711103712103713103714103715103716103717103718103719103720103721103722103723103724103725103726103727103728103729103730103731103732103733103734103735103736103737103738103739103740103741103742103743103744103745103746103747103748103749103750103751103752103753103754103755103756103757103758103759103760103761103762103763103764103765103766103767103768103769103770103771103772103773103774103775103776103777103778103779103780103781103782103783103784103785103786103787103788103789103790103791103792103793103794103795103796103797103798103799103800103801103802103803103804103805103806103807103808103809103810103811103812103813103814103815103816103817103818103819103820103821103822103823103824103825103826103827103828103829103830103831103832103833103834103835103836103837103838103839103840103841103842103843103844103845103846103847103848103849103850103851103852103853103854103855103856103857103858103859103860103861103862103863103864103865103866103867103868103869103870103871103872103873103874103875103876103877103878103879103880103881103882103883103884103885103886103887103888103889103890103891103892103893103894103895103896103897103898103899103900103901103902103903103904103905103906103907103908103909103910103911103912103913103914103915103916103917103918103919103920103921103922103923103924103925103926103927103928103929103930103931103932103933103934103935103936103937103938103939103940103941103942103943103944103945103946103947103948103949103950103951103952103953103954103955103956103957103958103959103960103961103962103963103964103965103966103967103968103969103970103971103972103973103974103975103976103977103978103979103980103981103982103983103984103985103986103987103988103989103990103991103992103993103994103995103996103997103998103999104000104001104002104003104004104005104006104007104008104009104010104011104012104013104014104015104016104017104018104019104020104021104022104023104024104025104026104027104028104029104030104031104032104033104034104035104036104037104038104039104040104041104042104043104044104045104046104047104048104049104050104051104052104053104054104055104056104057104058104059104060104061104062104063104064104065104066104067104068104069104070104071104072104073104074104075104076104077104078104079104080104081104082104083104084104085104086104087104088104089104090104091104092104093104094104095104096104097104098104099104100104101104102104103104104104105104106104107104108104109104110104111104112104113104114104115104116104117104118104119104120104121104122104123104124104125104126104127104128104129104130104131104132104133104134104135104136104137104138104139104140104141104142104143104144104145104146104147104148104149104150104151104152104153104154104155104156104157104158104159104160104161104162104163104164104165104166104167104168104169104170104171104172104173104174104175104176104177104178104179104180104181104182104183104184104185104186104187104188104189104190104191104192104193104194104195104196104197104198104199104200104201104202104203104204104205104206104207104208104209104210104211104212104213104214104215104216104217104218104219104220104221104222104223104224104225104226104227104228104229104230104231104232104233104234104235104236104237104238104239104240104241104242104243104244104245104246104247104248104249104250104251104252104253104254104255104256104257104258104259104260104261104262104263104264104265104266104267104268104269104270104271104272104273104274104275104276104277104278104279104280104281104282104283104284104285104286104287104288104289104290104291104292104293104294104295104296104297104298104299104300104301104302104303104304104305104306104307104308104309104310104311104312104313104314104315104316104317104318104319104320104321104322104323104324104325104326104327104328104329104330104331104332104333104334104335104336104337104338104339104340104341104342104343104344104345104346104347104348104349104350104351104352104353104354104355104356104357104358104359104360104361104362104363104364104365104366104367104368104369104370104371104372104373104374104375104376104377104378104379104380104381104382104383104384104385104386104387104388104389104390104391104392104393104394104395104396104397104398104399104400104401104402104403104404104405104406104407104408104409104410104411104412104413104414104415104416104417104418104419104420104421104422104423104424104425104426104427104428104429104430104431104432104433104434104435104436104437104438104439104440104441104442104443104444104445104446104447104448104449104450104451104452104453104454104455104456104457104458104459104460104461104462104463104464104465104466104467104468104469104470104471104472104473104474104475104476104477104478104479104480104481104482104483104484104485104486104487104488104489104490104491104492104493104494104495104496104497104498104499104500104501104502104503104504104505104506104507104508104509104510104511104512104513104514104515104516104517104518104519104520104521104522104523104524104525104526104527104528104529104530104531104532104533104534104535104536104537104538104539104540104541104542104543104544104545104546104547104548104549104550104551104552104553104554104555104556104557104558104559104560104561104562104563104564104565104566104567104568104569104570104571104572104573104574104575104576104577104578104579104580104581104582104583104584104585104586104587104588104589104590104591104592104593104594104595104596104597104598104599104600104601104602104603104604104605104606104607104608104609104610104611104612104613104614104615104616104617104618104619104620104621104622104623104624104625104626104627104628104629104630104631104632104633104634104635104636104637104638104639104640104641104642104643104644104645104646104647104648104649104650104651104652104653104654104655104656104657104658104659104660104661104662104663104664104665104666104667104668104669104670104671104672104673104674104675104676104677104678104679104680104681104682104683104684104685104686104687104688104689104690104691104692104693104694104695104696104697104698104699104700104701104702104703104704104705104706104707104708104709104710104711104712104713104714104715104716104717104718104719104720104721104722104723104724104725104726104727104728104729104730104731104732104733104734104735104736104737104738104739104740104741104742104743104744104745104746104747104748104749104750104751104752104753104754104755104756104757104758104759104760104761104762104763104764104765104766104767104768104769104770104771104772104773104774104775104776104777104778104779104780104781104782104783104784104785104786104787104788104789104790104791104792104793104794104795104796104797104798104799104800104801104802104803104804104805104806104807104808104809104810104811104812104813104814104815104816104817104818104819104820104821104822104823104824104825104826104827104828104829104830104831104832104833104834104835104836104837104838104839104840104841104842104843104844104845104846104847104848104849104850104851104852104853104854104855104856104857104858104859104860104861104862104863104864104865104866104867104868104869104870104871104872104873104874104875104876104877104878104879104880104881104882104883104884104885104886104887104888104889104890104891104892104893104894104895104896104897104898104899104900104901104902104903104904104905104906104907104908104909104910104911104912104913104914104915104916104917104918104919104920104921104922104923104924104925104926104927104928104929104930104931104932104933104934104935104936104937104938104939104940104941104942104943104944104945104946104947104948104949104950104951104952104953104954104955104956104957104958104959104960104961104962104963104964104965104966104967104968104969104970104971104972104973104974104975104976104977104978104979104980104981104982104983104984104985104986104987104988104989104990104991104992104993104994104995104996104997104998104999105000105001105002105003105004105005105006105007105008105009105010105011105012105013105014105015105016105017105018105019105020105021105022105023105024105025105026105027105028105029105030105031105032105033105034105035105036105037105038105039105040105041105042105043105044105045105046105047105048105049105050105051105052105053105054105055105056105057105058105059105060105061105062105063105064105065105066105067105068105069105070105071105072105073105074105075105076105077105078105079105080105081105082105083105084105085105086105087105088105089105090105091105092105093105094105095105096105097105098105099105100105101105102105103105104105105105106105107105108105109105110105111105112105113105114105115105116105117105118105119105120105121105122105123105124105125105126105127105128105129105130105131105132105133105134105135105136105137105138105139105140105141105142105143105144105145105146105147105148105149105150105151105152105153105154105155105156105157105158105159105160105161105162105163105164105165105166105167105168105169105170105171105172105173105174105175105176105177105178105179105180105181105182105183105184105185105186105187105188105189105190105191105192105193105194105195105196105197105198105199105200105201105202105203105204105205105206105207105208105209105210105211105212105213105214105215105216105217105218105219105220105221105222105223105224105225105226105227105228105229105230105231105232105233105234105235105236105237105238105239105240105241105242105243105244105245105246105247105248105249105250105251105252105253105254105255105256105257105258105259105260105261105262105263105264105265105266105267105268105269105270105271105272105273105274105275105276105277105278105279105280105281105282105283105284105285105286105287105288105289105290105291105292105293105294105295105296105297105298105299105300105301105302105303105304105305105306105307105308105309105310105311105312105313105314105315105316105317105318105319105320105321105322105323105324105325105326105327105328105329105330105331105332105333105334105335105336105337105338105339105340105341105342105343105344105345105346105347105348105349105350105351105352105353105354105355105356105357105358105359105360105361105362105363105364105365105366105367105368105369105370105371105372105373105374105375105376105377105378105379105380105381105382105383105384105385105386105387105388105389105390105391105392105393105394105395105396105397105398105399105400105401105402105403105404105405105406105407105408105409105410105411105412105413105414105415105416105417105418105419105420105421105422105423105424105425105426105427105428105429105430105431105432105433105434105435105436105437105438105439105440105441105442105443105444105445105446105447105448105449105450105451105452105453105454105455105456105457105458105459105460105461105462105463105464105465105466105467105468105469105470105471105472105473105474105475105476105477105478105479105480105481105482105483105484105485105486105487105488105489105490105491105492105493105494105495105496105497105498105499105500105501105502105503105504105505105506105507105508105509105510105511105512105513105514105515105516105517105518105519105520105521105522105523105524105525105526105527105528105529105530105531105532105533105534105535105536105537105538105539105540105541105542105543105544105545105546105547105548105549105550105551105552105553105554105555105556105557105558105559105560105561105562105563105564105565105566105567105568105569105570105571105572105573105574105575105576105577105578105579105580105581105582105583105584105585105586105587105588105589105590105591105592105593105594105595105596105597105598105599105600105601105602105603105604105605105606105607105608105609105610105611105612105613105614105615105616105617105618105619105620105621105622105623105624105625105626105627105628105629105630105631105632105633105634105635105636105637105638105639105640105641105642105643105644105645105646105647105648105649105650105651105652105653105654105655105656105657105658105659105660105661105662105663105664105665105666105667105668105669105670105671105672105673105674105675105676105677105678105679105680105681105682105683105684105685105686105687105688105689105690105691105692105693105694105695105696105697105698105699105700105701105702105703105704105705105706105707105708105709105710105711105712105713105714105715105716105717105718105719105720105721105722105723105724105725105726105727105728105729105730105731105732105733105734105735105736105737105738105739105740105741105742105743105744105745105746105747105748105749105750105751105752105753105754105755105756105757105758105759105760105761105762105763105764105765105766105767105768105769105770105771105772105773105774105775105776105777105778105779105780105781105782105783105784105785105786105787105788105789105790105791105792105793105794105795105796105797105798105799105800105801105802105803105804105805105806105807105808105809105810105811105812105813105814105815105816105817105818105819105820105821105822105823105824105825105826105827105828105829105830105831105832105833105834105835105836105837105838105839105840105841105842105843105844105845105846105847105848105849105850105851105852105853105854105855105856105857105858105859105860105861105862105863105864105865105866105867105868105869105870105871105872105873105874105875105876105877105878105879105880105881105882105883105884105885105886105887105888105889105890105891105892105893105894105895105896105897105898105899105900105901105902105903105904105905105906105907105908105909105910105911105912105913105914105915105916105917105918105919105920105921105922105923105924105925105926105927105928105929105930105931105932105933105934105935105936105937105938105939105940105941105942105943105944105945105946105947105948105949105950105951105952105953105954105955105956105957105958105959105960105961105962105963105964105965105966105967105968105969105970105971105972105973105974105975105976105977105978105979105980105981105982105983105984105985105986105987105988105989105990105991105992105993105994105995105996105997105998105999106000106001106002106003106004106005106006106007106008106009106010106011106012106013106014106015106016106017106018106019106020106021106022106023106024106025106026106027106028106029106030106031106032106033106034106035106036106037106038106039106040106041106042106043106044106045106046106047106048106049106050106051106052106053106054106055106056106057106058106059106060106061106062106063106064106065106066106067106068106069106070106071106072106073106074106075106076106077106078106079106080106081106082106083106084106085106086106087106088106089106090106091106092106093106094106095106096106097106098106099106100106101106102106103106104106105106106106107106108106109106110106111106112106113106114106115106116106117106118106119106120106121106122106123106124106125106126106127106128106129106130106131106132106133106134106135106136106137106138106139106140106141106142106143106144106145106146106147106148106149106150106151106152106153106154106155106156106157106158106159106160106161106162106163106164106165106166106167106168106169106170106171106172106173106174106175106176106177106178106179106180106181106182106183106184106185106186106187106188106189106190106191106192106193106194106195106196106197106198106199106200106201106202106203106204106205106206106207106208106209106210106211106212106213106214106215106216106217106218106219106220106221106222106223106224106225106226106227106228106229106230106231106232106233106234106235106236106237106238106239106240106241106242106243106244106245106246106247106248106249106250106251106252106253106254106255106256106257106258106259106260106261106262106263106264106265106266106267106268106269106270106271106272106273106274106275106276106277106278106279106280106281106282106283106284106285106286106287106288106289106290106291106292106293106294106295106296106297106298106299106300106301106302106303106304106305106306106307106308106309106310106311106312106313106314106315106316106317106318106319106320106321106322106323106324106325106326106327106328106329106330106331106332106333106334106335106336106337106338106339106340106341106342106343106344106345106346106347106348106349106350106351106352106353106354106355106356106357106358106359106360106361106362106363106364106365106366106367106368106369106370106371106372106373106374106375106376106377106378106379106380106381106382106383106384106385106386106387106388106389106390106391106392106393106394106395106396106397106398106399106400106401106402106403106404106405106406106407106408106409106410106411106412106413106414106415106416106417106418106419106420106421106422106423106424106425106426106427106428106429106430106431106432106433106434106435106436106437106438106439106440106441106442106443106444106445106446106447106448106449106450106451106452106453106454106455106456106457106458106459106460106461106462106463106464106465106466106467106468106469106470106471106472106473106474106475106476106477106478106479106480106481106482106483106484106485106486106487106488106489106490106491106492106493106494106495106496106497106498106499106500106501106502106503106504106505106506106507106508106509106510106511106512106513106514106515106516106517106518106519106520106521106522106523106524106525106526106527106528106529106530106531106532106533106534106535106536106537106538106539106540106541106542106543106544106545106546106547106548106549106550106551106552106553106554106555106556106557106558106559106560106561106562106563106564106565106566106567106568106569106570106571106572106573106574106575106576106577106578106579106580106581106582106583106584106585106586106587106588106589106590106591106592106593106594106595106596106597106598106599106600106601106602106603106604106605106606106607106608106609106610106611106612106613106614106615106616106617106618106619106620106621106622106623106624106625106626106627106628106629106630106631106632106633106634106635106636106637106638106639106640106641106642106643106644106645106646106647106648106649106650106651106652106653106654106655106656106657106658106659106660106661106662106663106664106665106666106667106668106669106670106671106672106673106674106675106676106677106678106679106680106681106682106683106684106685106686106687106688106689106690106691106692106693106694106695106696106697106698106699106700106701106702106703106704106705106706106707106708106709106710106711106712106713106714106715106716106717106718106719106720106721106722106723106724106725106726106727106728106729106730106731106732106733106734106735106736106737106738106739106740106741106742106743106744106745106746106747106748106749106750106751106752106753106754106755106756106757106758106759106760106761106762106763106764106765106766106767106768106769106770106771106772106773106774106775106776106777106778106779106780106781106782106783106784106785106786106787106788106789106790106791106792106793106794106795106796106797106798106799106800106801106802106803106804106805106806106807106808106809106810106811106812106813106814106815106816106817106818106819106820106821106822106823106824106825106826106827106828106829106830106831106832106833106834106835106836106837106838106839106840106841106842106843106844106845106846106847106848106849106850106851106852106853106854106855106856106857106858106859106860106861106862106863106864106865106866106867106868106869106870106871106872106873106874106875106876106877106878106879106880106881106882106883106884106885106886106887106888106889106890106891106892106893106894106895106896106897106898106899106900106901106902106903106904106905106906106907106908106909106910106911106912106913106914106915106916106917106918106919106920106921106922106923106924106925106926106927106928106929106930106931106932106933106934106935106936106937106938106939106940106941106942106943106944106945106946106947106948106949106950106951106952106953106954106955106956106957106958106959106960106961106962106963106964106965106966106967106968106969106970106971106972106973106974106975106976106977106978106979106980106981106982106983106984106985106986106987106988106989106990106991106992106993106994106995106996106997106998106999107000107001107002107003107004107005107006107007107008107009107010107011107012107013107014107015107016107017107018107019107020107021107022107023107024107025107026107027107028107029107030107031107032107033107034107035107036107037107038107039107040107041107042107043107044107045107046107047107048107049107050107051107052107053107054107055107056107057107058107059107060107061107062107063107064107065107066107067107068107069107070107071107072107073107074107075107076107077107078107079107080107081107082107083107084107085107086107087107088107089107090
  1. /**
  2. * @author Richard Davey <rich@photonstorm.com>
  3. * @copyright 2016 Photon Storm Ltd.
  4. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  5. *
  6. * @overview
  7. *
  8. * Phaser - http://phaser.io
  9. *
  10. * v2.9.1 "2017-10-10" - Built: Tue Oct 10 2017 11:17:47
  11. *
  12. * By Richard Davey http://www.photonstorm.com @photonstorm
  13. *
  14. * Phaser is a fun, free and fast 2D game framework for making HTML5 games
  15. * for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
  16. *
  17. * Phaser uses Pixi.js for rendering, created by Mat Groves http://matgroves.com @Doormat23
  18. * Phaser uses p2.js for full-body physics, created by Stefan Hedman https://github.com/schteppe/p2.js @schteppe
  19. * Phaser contains a port of N+ Physics, converted by Richard Davey, original by http://www.metanetsoftware.com
  20. *
  21. * Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from which both Phaser and my love of framework development originate.
  22. *
  23. * Follow development at http://phaser.io and on our forum
  24. *
  25. * "If you want your children to be intelligent, read them fairy tales."
  26. * "If you want them to be more intelligent, read them more fairy tales."
  27. * -- Albert Einstein
  28. */
  29. /**
  30. * The MIT License (MIT)
  31. *
  32. * Copyright (c) 2015 p2.js authors
  33. *
  34. * Permission is hereby granted, free of charge, to any person obtaining a copy
  35. * of this software and associated documentation files (the "Software"), to deal
  36. * in the Software without restriction, including without limitation the rights
  37. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  38. * copies of the Software, and to permit persons to whom the Software is
  39. * furnished to do so, subject to the following conditions:
  40. *
  41. * The above copyright notice and this permission notice shall be included in
  42. * all copies or substantial portions of the Software.
  43. *
  44. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  45. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  46. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  47. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  48. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  49. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  50. * THE SOFTWARE.
  51. */
  52. !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&false)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.p2=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
  53. var Scalar = _dereq_('./Scalar');
  54. module.exports = Line;
  55. /**
  56. * Container for line-related functions
  57. * @class Line
  58. */
  59. function Line(){};
  60. /**
  61. * Compute the intersection between two lines.
  62. * @static
  63. * @method lineInt
  64. * @param {Array} l1 Line vector 1
  65. * @param {Array} l2 Line vector 2
  66. * @param {Number} precision Precision to use when checking if the lines are parallel
  67. * @return {Array} The intersection point.
  68. */
  69. Line.lineInt = function(l1,l2,precision){
  70. precision = precision || 0;
  71. var i = [0,0]; // point
  72. var a1, b1, c1, a2, b2, c2, det; // scalars
  73. a1 = l1[1][1] - l1[0][1];
  74. b1 = l1[0][0] - l1[1][0];
  75. c1 = a1 * l1[0][0] + b1 * l1[0][1];
  76. a2 = l2[1][1] - l2[0][1];
  77. b2 = l2[0][0] - l2[1][0];
  78. c2 = a2 * l2[0][0] + b2 * l2[0][1];
  79. det = a1 * b2 - a2*b1;
  80. if (!Scalar.eq(det, 0, precision)) { // lines are not parallel
  81. i[0] = (b2 * c1 - b1 * c2) / det;
  82. i[1] = (a1 * c2 - a2 * c1) / det;
  83. }
  84. return i;
  85. };
  86. /**
  87. * Checks if two line segments intersects.
  88. * @method segmentsIntersect
  89. * @param {Array} p1 The start vertex of the first line segment.
  90. * @param {Array} p2 The end vertex of the first line segment.
  91. * @param {Array} q1 The start vertex of the second line segment.
  92. * @param {Array} q2 The end vertex of the second line segment.
  93. * @return {Boolean} True if the two line segments intersect
  94. */
  95. Line.segmentsIntersect = function(p1, p2, q1, q2){
  96. var dx = p2[0] - p1[0];
  97. var dy = p2[1] - p1[1];
  98. var da = q2[0] - q1[0];
  99. var db = q2[1] - q1[1];
  100. // segments are parallel
  101. if(da*dy - db*dx == 0)
  102. return false;
  103. var s = (dx * (q1[1] - p1[1]) + dy * (p1[0] - q1[0])) / (da * dy - db * dx)
  104. var t = (da * (p1[1] - q1[1]) + db * (q1[0] - p1[0])) / (db * dx - da * dy)
  105. return (s>=0 && s<=1 && t>=0 && t<=1);
  106. };
  107. },{"./Scalar":4}],2:[function(_dereq_,module,exports){
  108. module.exports = Point;
  109. /**
  110. * Point related functions
  111. * @class Point
  112. */
  113. function Point(){};
  114. /**
  115. * Get the area of a triangle spanned by the three given points. Note that the area will be negative if the points are not given in counter-clockwise order.
  116. * @static
  117. * @method area
  118. * @param {Array} a
  119. * @param {Array} b
  120. * @param {Array} c
  121. * @return {Number}
  122. */
  123. Point.area = function(a,b,c){
  124. return (((b[0] - a[0])*(c[1] - a[1]))-((c[0] - a[0])*(b[1] - a[1])));
  125. };
  126. Point.left = function(a,b,c){
  127. return Point.area(a,b,c) > 0;
  128. };
  129. Point.leftOn = function(a,b,c) {
  130. return Point.area(a, b, c) >= 0;
  131. };
  132. Point.right = function(a,b,c) {
  133. return Point.area(a, b, c) < 0;
  134. };
  135. Point.rightOn = function(a,b,c) {
  136. return Point.area(a, b, c) <= 0;
  137. };
  138. var tmpPoint1 = [],
  139. tmpPoint2 = [];
  140. /**
  141. * Check if three points are collinear
  142. * @method collinear
  143. * @param {Array} a
  144. * @param {Array} b
  145. * @param {Array} c
  146. * @param {Number} [thresholdAngle=0] Threshold angle to use when comparing the vectors. The function will return true if the angle between the resulting vectors is less than this value. Use zero for max precision.
  147. * @return {Boolean}
  148. */
  149. Point.collinear = function(a,b,c,thresholdAngle) {
  150. if(!thresholdAngle)
  151. return Point.area(a, b, c) == 0;
  152. else {
  153. var ab = tmpPoint1,
  154. bc = tmpPoint2;
  155. ab[0] = b[0]-a[0];
  156. ab[1] = b[1]-a[1];
  157. bc[0] = c[0]-b[0];
  158. bc[1] = c[1]-b[1];
  159. var dot = ab[0]*bc[0] + ab[1]*bc[1],
  160. magA = Math.sqrt(ab[0]*ab[0] + ab[1]*ab[1]),
  161. magB = Math.sqrt(bc[0]*bc[0] + bc[1]*bc[1]),
  162. angle = Math.acos(dot/(magA*magB));
  163. return angle < thresholdAngle;
  164. }
  165. };
  166. Point.sqdist = function(a,b){
  167. var dx = b[0] - a[0];
  168. var dy = b[1] - a[1];
  169. return dx * dx + dy * dy;
  170. };
  171. },{}],3:[function(_dereq_,module,exports){
  172. var Line = _dereq_("./Line")
  173. , Point = _dereq_("./Point")
  174. , Scalar = _dereq_("./Scalar")
  175. module.exports = Polygon;
  176. /**
  177. * Polygon class.
  178. * @class Polygon
  179. * @constructor
  180. */
  181. function Polygon(){
  182. /**
  183. * Vertices that this polygon consists of. An array of array of numbers, example: [[0,0],[1,0],..]
  184. * @property vertices
  185. * @type {Array}
  186. */
  187. this.vertices = [];
  188. }
  189. /**
  190. * Get a vertex at position i. It does not matter if i is out of bounds, this function will just cycle.
  191. * @method at
  192. * @param {Number} i
  193. * @return {Array}
  194. */
  195. Polygon.prototype.at = function(i){
  196. var v = this.vertices,
  197. s = v.length;
  198. return v[i < 0 ? i % s + s : i % s];
  199. };
  200. /**
  201. * Get first vertex
  202. * @method first
  203. * @return {Array}
  204. */
  205. Polygon.prototype.first = function(){
  206. return this.vertices[0];
  207. };
  208. /**
  209. * Get last vertex
  210. * @method last
  211. * @return {Array}
  212. */
  213. Polygon.prototype.last = function(){
  214. return this.vertices[this.vertices.length-1];
  215. };
  216. /**
  217. * Clear the polygon data
  218. * @method clear
  219. * @return {Array}
  220. */
  221. Polygon.prototype.clear = function(){
  222. this.vertices.length = 0;
  223. };
  224. /**
  225. * Append points "from" to "to"-1 from an other polygon "poly" onto this one.
  226. * @method append
  227. * @param {Polygon} poly The polygon to get points from.
  228. * @param {Number} from The vertex index in "poly".
  229. * @param {Number} to The end vertex index in "poly". Note that this vertex is NOT included when appending.
  230. * @return {Array}
  231. */
  232. Polygon.prototype.append = function(poly,from,to){
  233. if(typeof(from) == "undefined") throw new Error("From is not given!");
  234. if(typeof(to) == "undefined") throw new Error("To is not given!");
  235. if(to-1 < from) throw new Error("lol1");
  236. if(to > poly.vertices.length) throw new Error("lol2");
  237. if(from < 0) throw new Error("lol3");
  238. for(var i=from; i<to; i++){
  239. this.vertices.push(poly.vertices[i]);
  240. }
  241. };
  242. /**
  243. * Make sure that the polygon vertices are ordered counter-clockwise.
  244. * @method makeCCW
  245. */
  246. Polygon.prototype.makeCCW = function(){
  247. var br = 0,
  248. v = this.vertices;
  249. // find bottom right point
  250. for (var i = 1; i < this.vertices.length; ++i) {
  251. if (v[i][1] < v[br][1] || (v[i][1] == v[br][1] && v[i][0] > v[br][0])) {
  252. br = i;
  253. }
  254. }
  255. // reverse poly if clockwise
  256. if (!Point.left(this.at(br - 1), this.at(br), this.at(br + 1))) {
  257. this.reverse();
  258. }
  259. };
  260. /**
  261. * Reverse the vertices in the polygon
  262. * @method reverse
  263. */
  264. Polygon.prototype.reverse = function(){
  265. var tmp = [];
  266. for(var i=0, N=this.vertices.length; i!==N; i++){
  267. tmp.push(this.vertices.pop());
  268. }
  269. this.vertices = tmp;
  270. };
  271. /**
  272. * Check if a point in the polygon is a reflex point
  273. * @method isReflex
  274. * @param {Number} i
  275. * @return {Boolean}
  276. */
  277. Polygon.prototype.isReflex = function(i){
  278. return Point.right(this.at(i - 1), this.at(i), this.at(i + 1));
  279. };
  280. var tmpLine1=[],
  281. tmpLine2=[];
  282. /**
  283. * Check if two vertices in the polygon can see each other
  284. * @method canSee
  285. * @param {Number} a Vertex index 1
  286. * @param {Number} b Vertex index 2
  287. * @return {Boolean}
  288. */
  289. Polygon.prototype.canSee = function(a,b) {
  290. var p, dist, l1=tmpLine1, l2=tmpLine2;
  291. if (Point.leftOn(this.at(a + 1), this.at(a), this.at(b)) && Point.rightOn(this.at(a - 1), this.at(a), this.at(b))) {
  292. return false;
  293. }
  294. dist = Point.sqdist(this.at(a), this.at(b));
  295. for (var i = 0; i !== this.vertices.length; ++i) { // for each edge
  296. if ((i + 1) % this.vertices.length === a || i === a) // ignore incident edges
  297. continue;
  298. if (Point.leftOn(this.at(a), this.at(b), this.at(i + 1)) && Point.rightOn(this.at(a), this.at(b), this.at(i))) { // if diag intersects an edge
  299. l1[0] = this.at(a);
  300. l1[1] = this.at(b);
  301. l2[0] = this.at(i);
  302. l2[1] = this.at(i + 1);
  303. p = Line.lineInt(l1,l2);
  304. if (Point.sqdist(this.at(a), p) < dist) { // if edge is blocking visibility to b
  305. return false;
  306. }
  307. }
  308. }
  309. return true;
  310. };
  311. /**
  312. * Copy the polygon from vertex i to vertex j.
  313. * @method copy
  314. * @param {Number} i
  315. * @param {Number} j
  316. * @param {Polygon} [targetPoly] Optional target polygon to save in.
  317. * @return {Polygon} The resulting copy.
  318. */
  319. Polygon.prototype.copy = function(i,j,targetPoly){
  320. var p = targetPoly || new Polygon();
  321. p.clear();
  322. if (i < j) {
  323. // Insert all vertices from i to j
  324. for(var k=i; k<=j; k++)
  325. p.vertices.push(this.vertices[k]);
  326. } else {
  327. // Insert vertices 0 to j
  328. for(var k=0; k<=j; k++)
  329. p.vertices.push(this.vertices[k]);
  330. // Insert vertices i to end
  331. for(var k=i; k<this.vertices.length; k++)
  332. p.vertices.push(this.vertices[k]);
  333. }
  334. return p;
  335. };
  336. /**
  337. * Decomposes the polygon into convex pieces. Returns a list of edges [[p1,p2],[p2,p3],...] that cuts the polygon.
  338. * Note that this algorithm has complexity O(N^4) and will be very slow for polygons with many vertices.
  339. * @method getCutEdges
  340. * @return {Array}
  341. */
  342. Polygon.prototype.getCutEdges = function() {
  343. var min=[], tmp1=[], tmp2=[], tmpPoly = new Polygon();
  344. var nDiags = Number.MAX_VALUE;
  345. for (var i = 0; i < this.vertices.length; ++i) {
  346. if (this.isReflex(i)) {
  347. for (var j = 0; j < this.vertices.length; ++j) {
  348. if (this.canSee(i, j)) {
  349. tmp1 = this.copy(i, j, tmpPoly).getCutEdges();
  350. tmp2 = this.copy(j, i, tmpPoly).getCutEdges();
  351. for(var k=0; k<tmp2.length; k++)
  352. tmp1.push(tmp2[k]);
  353. if (tmp1.length < nDiags) {
  354. min = tmp1;
  355. nDiags = tmp1.length;
  356. min.push([this.at(i), this.at(j)]);
  357. }
  358. }
  359. }
  360. }
  361. }
  362. return min;
  363. };
  364. /**
  365. * Decomposes the polygon into one or more convex sub-Polygons.
  366. * @method decomp
  367. * @return {Array} An array or Polygon objects.
  368. */
  369. Polygon.prototype.decomp = function(){
  370. var edges = this.getCutEdges();
  371. if(edges.length > 0)
  372. return this.slice(edges);
  373. else
  374. return [this];
  375. };
  376. /**
  377. * Slices the polygon given one or more cut edges. If given one, this function will return two polygons (false on failure). If many, an array of polygons.
  378. * @method slice
  379. * @param {Array} cutEdges A list of edges, as returned by .getCutEdges()
  380. * @return {Array}
  381. */
  382. Polygon.prototype.slice = function(cutEdges){
  383. if(cutEdges.length == 0) return [this];
  384. if(cutEdges instanceof Array && cutEdges.length && cutEdges[0] instanceof Array && cutEdges[0].length==2 && cutEdges[0][0] instanceof Array){
  385. var polys = [this];
  386. for(var i=0; i<cutEdges.length; i++){
  387. var cutEdge = cutEdges[i];
  388. // Cut all polys
  389. for(var j=0; j<polys.length; j++){
  390. var poly = polys[j];
  391. var result = poly.slice(cutEdge);
  392. if(result){
  393. // Found poly! Cut and quit
  394. polys.splice(j,1);
  395. polys.push(result[0],result[1]);
  396. break;
  397. }
  398. }
  399. }
  400. return polys;
  401. } else {
  402. // Was given one edge
  403. var cutEdge = cutEdges;
  404. var i = this.vertices.indexOf(cutEdge[0]);
  405. var j = this.vertices.indexOf(cutEdge[1]);
  406. if(i != -1 && j != -1){
  407. return [this.copy(i,j),
  408. this.copy(j,i)];
  409. } else {
  410. return false;
  411. }
  412. }
  413. };
  414. /**
  415. * Checks that the line segments of this polygon do not intersect each other.
  416. * @method isSimple
  417. * @param {Array} path An array of vertices e.g. [[0,0],[0,1],...]
  418. * @return {Boolean}
  419. * @todo Should it check all segments with all others?
  420. */
  421. Polygon.prototype.isSimple = function(){
  422. var path = this.vertices;
  423. // Check
  424. for(var i=0; i<path.length-1; i++){
  425. for(var j=0; j<i-1; j++){
  426. if(Line.segmentsIntersect(path[i], path[i+1], path[j], path[j+1] )){
  427. return false;
  428. }
  429. }
  430. }
  431. // Check the segment between the last and the first point to all others
  432. for(var i=1; i<path.length-2; i++){
  433. if(Line.segmentsIntersect(path[0], path[path.length-1], path[i], path[i+1] )){
  434. return false;
  435. }
  436. }
  437. return true;
  438. };
  439. function getIntersectionPoint(p1, p2, q1, q2, delta){
  440. delta = delta || 0;
  441. var a1 = p2[1] - p1[1];
  442. var b1 = p1[0] - p2[0];
  443. var c1 = (a1 * p1[0]) + (b1 * p1[1]);
  444. var a2 = q2[1] - q1[1];
  445. var b2 = q1[0] - q2[0];
  446. var c2 = (a2 * q1[0]) + (b2 * q1[1]);
  447. var det = (a1 * b2) - (a2 * b1);
  448. if(!Scalar.eq(det,0,delta))
  449. return [((b2 * c1) - (b1 * c2)) / det, ((a1 * c2) - (a2 * c1)) / det]
  450. else
  451. return [0,0]
  452. }
  453. /**
  454. * Quickly decompose the Polygon into convex sub-polygons.
  455. * @method quickDecomp
  456. * @param {Array} result
  457. * @param {Array} [reflexVertices]
  458. * @param {Array} [steinerPoints]
  459. * @param {Number} [delta]
  460. * @param {Number} [maxlevel]
  461. * @param {Number} [level]
  462. * @return {Array}
  463. */
  464. Polygon.prototype.quickDecomp = function(result,reflexVertices,steinerPoints,delta,maxlevel,level){
  465. maxlevel = maxlevel || 100;
  466. level = level || 0;
  467. delta = delta || 25;
  468. result = typeof(result)!="undefined" ? result : [];
  469. reflexVertices = reflexVertices || [];
  470. steinerPoints = steinerPoints || [];
  471. var upperInt=[0,0], lowerInt=[0,0], p=[0,0]; // Points
  472. var upperDist=0, lowerDist=0, d=0, closestDist=0; // scalars
  473. var upperIndex=0, lowerIndex=0, closestIndex=0; // Integers
  474. var lowerPoly=new Polygon(), upperPoly=new Polygon(); // polygons
  475. var poly = this,
  476. v = this.vertices;
  477. if(v.length < 3) return result;
  478. level++;
  479. if(level > maxlevel){
  480. console.warn("quickDecomp: max level ("+maxlevel+") reached.");
  481. return result;
  482. }
  483. for (var i = 0; i < this.vertices.length; ++i) {
  484. if (poly.isReflex(i)) {
  485. reflexVertices.push(poly.vertices[i]);
  486. upperDist = lowerDist = Number.MAX_VALUE;
  487. for (var j = 0; j < this.vertices.length; ++j) {
  488. if (Point.left(poly.at(i - 1), poly.at(i), poly.at(j))
  489. && Point.rightOn(poly.at(i - 1), poly.at(i), poly.at(j - 1))) { // if line intersects with an edge
  490. p = getIntersectionPoint(poly.at(i - 1), poly.at(i), poly.at(j), poly.at(j - 1)); // find the point of intersection
  491. if (Point.right(poly.at(i + 1), poly.at(i), p)) { // make sure it's inside the poly
  492. d = Point.sqdist(poly.vertices[i], p);
  493. if (d < lowerDist) { // keep only the closest intersection
  494. lowerDist = d;
  495. lowerInt = p;
  496. lowerIndex = j;
  497. }
  498. }
  499. }
  500. if (Point.left(poly.at(i + 1), poly.at(i), poly.at(j + 1))
  501. && Point.rightOn(poly.at(i + 1), poly.at(i), poly.at(j))) {
  502. p = getIntersectionPoint(poly.at(i + 1), poly.at(i), poly.at(j), poly.at(j + 1));
  503. if (Point.left(poly.at(i - 1), poly.at(i), p)) {
  504. d = Point.sqdist(poly.vertices[i], p);
  505. if (d < upperDist) {
  506. upperDist = d;
  507. upperInt = p;
  508. upperIndex = j;
  509. }
  510. }
  511. }
  512. }
  513. // if there are no vertices to connect to, choose a point in the middle
  514. if (lowerIndex == (upperIndex + 1) % this.vertices.length) {
  515. //console.log("Case 1: Vertex("+i+"), lowerIndex("+lowerIndex+"), upperIndex("+upperIndex+"), poly.size("+this.vertices.length+")");
  516. p[0] = (lowerInt[0] + upperInt[0]) / 2;
  517. p[1] = (lowerInt[1] + upperInt[1]) / 2;
  518. steinerPoints.push(p);
  519. if (i < upperIndex) {
  520. //lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.begin() + upperIndex + 1);
  521. lowerPoly.append(poly, i, upperIndex+1);
  522. lowerPoly.vertices.push(p);
  523. upperPoly.vertices.push(p);
  524. if (lowerIndex != 0){
  525. //upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.end());
  526. upperPoly.append(poly,lowerIndex,poly.vertices.length);
  527. }
  528. //upperPoly.insert(upperPoly.end(), poly.begin(), poly.begin() + i + 1);
  529. upperPoly.append(poly,0,i+1);
  530. } else {
  531. if (i != 0){
  532. //lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.end());
  533. lowerPoly.append(poly,i,poly.vertices.length);
  534. }
  535. //lowerPoly.insert(lowerPoly.end(), poly.begin(), poly.begin() + upperIndex + 1);
  536. lowerPoly.append(poly,0,upperIndex+1);
  537. lowerPoly.vertices.push(p);
  538. upperPoly.vertices.push(p);
  539. //upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.begin() + i + 1);
  540. upperPoly.append(poly,lowerIndex,i+1);
  541. }
  542. } else {
  543. // connect to the closest point within the triangle
  544. //console.log("Case 2: Vertex("+i+"), closestIndex("+closestIndex+"), poly.size("+this.vertices.length+")\n");
  545. if (lowerIndex > upperIndex) {
  546. upperIndex += this.vertices.length;
  547. }
  548. closestDist = Number.MAX_VALUE;
  549. if(upperIndex < lowerIndex){
  550. return result;
  551. }
  552. for (var j = lowerIndex; j <= upperIndex; ++j) {
  553. if (Point.leftOn(poly.at(i - 1), poly.at(i), poly.at(j))
  554. && Point.rightOn(poly.at(i + 1), poly.at(i), poly.at(j))) {
  555. d = Point.sqdist(poly.at(i), poly.at(j));
  556. if (d < closestDist) {
  557. closestDist = d;
  558. closestIndex = j % this.vertices.length;
  559. }
  560. }
  561. }
  562. if (i < closestIndex) {
  563. lowerPoly.append(poly,i,closestIndex+1);
  564. if (closestIndex != 0){
  565. upperPoly.append(poly,closestIndex,v.length);
  566. }
  567. upperPoly.append(poly,0,i+1);
  568. } else {
  569. if (i != 0){
  570. lowerPoly.append(poly,i,v.length);
  571. }
  572. lowerPoly.append(poly,0,closestIndex+1);
  573. upperPoly.append(poly,closestIndex,i+1);
  574. }
  575. }
  576. // solve smallest poly first
  577. if (lowerPoly.vertices.length < upperPoly.vertices.length) {
  578. lowerPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  579. upperPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  580. } else {
  581. upperPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  582. lowerPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  583. }
  584. return result;
  585. }
  586. }
  587. result.push(this);
  588. return result;
  589. };
  590. /**
  591. * Remove collinear points in the polygon.
  592. * @method removeCollinearPoints
  593. * @param {Number} [precision] The threshold angle to use when determining whether two edges are collinear. Use zero for finest precision.
  594. * @return {Number} The number of points removed
  595. */
  596. Polygon.prototype.removeCollinearPoints = function(precision){
  597. var num = 0;
  598. for(var i=this.vertices.length-1; this.vertices.length>3 && i>=0; --i){
  599. if(Point.collinear(this.at(i-1),this.at(i),this.at(i+1),precision)){
  600. // Remove the middle point
  601. this.vertices.splice(i%this.vertices.length,1);
  602. i--; // Jump one point forward. Otherwise we may get a chain removal
  603. num++;
  604. }
  605. }
  606. return num;
  607. };
  608. },{"./Line":1,"./Point":2,"./Scalar":4}],4:[function(_dereq_,module,exports){
  609. module.exports = Scalar;
  610. /**
  611. * Scalar functions
  612. * @class Scalar
  613. */
  614. function Scalar(){}
  615. /**
  616. * Check if two scalars are equal
  617. * @static
  618. * @method eq
  619. * @param {Number} a
  620. * @param {Number} b
  621. * @param {Number} [precision]
  622. * @return {Boolean}
  623. */
  624. Scalar.eq = function(a,b,precision){
  625. precision = precision || 0;
  626. return Math.abs(a-b) < precision;
  627. };
  628. },{}],5:[function(_dereq_,module,exports){
  629. module.exports = {
  630. Polygon : _dereq_("./Polygon"),
  631. Point : _dereq_("./Point"),
  632. };
  633. },{"./Point":2,"./Polygon":3}],6:[function(_dereq_,module,exports){
  634. module.exports={
  635. "name": "p2",
  636. "version": "0.7.1",
  637. "description": "A JavaScript 2D physics engine.",
  638. "author": "Stefan Hedman <schteppe@gmail.com> (http://steffe.se)",
  639. "keywords": [
  640. "p2.js",
  641. "p2",
  642. "physics",
  643. "engine",
  644. "2d"
  645. ],
  646. "main": "./src/p2.js",
  647. "engines": {
  648. "node": "*"
  649. },
  650. "repository": {
  651. "type": "git",
  652. "url": "https://github.com/schteppe/p2.js.git"
  653. },
  654. "bugs": {
  655. "url": "https://github.com/schteppe/p2.js/issues"
  656. },
  657. "licenses": [
  658. {
  659. "type": "MIT"
  660. }
  661. ],
  662. "devDependencies": {
  663. "grunt": "^0.4.5",
  664. "grunt-contrib-jshint": "^0.11.2",
  665. "grunt-contrib-nodeunit": "^0.4.1",
  666. "grunt-contrib-uglify": "~0.4.0",
  667. "grunt-contrib-watch": "~0.5.0",
  668. "grunt-browserify": "~2.0.1",
  669. "grunt-contrib-concat": "^0.4.0"
  670. },
  671. "dependencies": {
  672. "poly-decomp": "0.1.1"
  673. }
  674. }
  675. },{}],7:[function(_dereq_,module,exports){
  676. var vec2 = _dereq_('../math/vec2')
  677. , Utils = _dereq_('../utils/Utils');
  678. module.exports = AABB;
  679. /**
  680. * Axis aligned bounding box class.
  681. * @class AABB
  682. * @constructor
  683. * @param {Object} [options]
  684. * @param {Array} [options.upperBound]
  685. * @param {Array} [options.lowerBound]
  686. */
  687. function AABB(options){
  688. /**
  689. * The lower bound of the bounding box.
  690. * @property lowerBound
  691. * @type {Array}
  692. */
  693. this.lowerBound = vec2.create();
  694. if(options && options.lowerBound){
  695. vec2.copy(this.lowerBound, options.lowerBound);
  696. }
  697. /**
  698. * The upper bound of the bounding box.
  699. * @property upperBound
  700. * @type {Array}
  701. */
  702. this.upperBound = vec2.create();
  703. if(options && options.upperBound){
  704. vec2.copy(this.upperBound, options.upperBound);
  705. }
  706. }
  707. var tmp = vec2.create();
  708. /**
  709. * Set the AABB bounds from a set of points, transformed by the given position and angle.
  710. * @method setFromPoints
  711. * @param {Array} points An array of vec2's.
  712. * @param {Array} position
  713. * @param {number} angle
  714. * @param {number} skinSize Some margin to be added to the AABB.
  715. */
  716. AABB.prototype.setFromPoints = function(points, position, angle, skinSize){
  717. var l = this.lowerBound,
  718. u = this.upperBound;
  719. if(typeof(angle) !== "number"){
  720. angle = 0;
  721. }
  722. // Set to the first point
  723. if(angle !== 0){
  724. vec2.rotate(l, points[0], angle);
  725. } else {
  726. vec2.copy(l, points[0]);
  727. }
  728. vec2.copy(u, l);
  729. // Compute cosines and sines just once
  730. var cosAngle = Math.cos(angle),
  731. sinAngle = Math.sin(angle);
  732. for(var i = 1; i<points.length; i++){
  733. var p = points[i];
  734. if(angle !== 0){
  735. var x = p[0],
  736. y = p[1];
  737. tmp[0] = cosAngle * x -sinAngle * y;
  738. tmp[1] = sinAngle * x +cosAngle * y;
  739. p = tmp;
  740. }
  741. for(var j=0; j<2; j++){
  742. if(p[j] > u[j]){
  743. u[j] = p[j];
  744. }
  745. if(p[j] < l[j]){
  746. l[j] = p[j];
  747. }
  748. }
  749. }
  750. // Add offset
  751. if(position){
  752. vec2.add(this.lowerBound, this.lowerBound, position);
  753. vec2.add(this.upperBound, this.upperBound, position);
  754. }
  755. if(skinSize){
  756. this.lowerBound[0] -= skinSize;
  757. this.lowerBound[1] -= skinSize;
  758. this.upperBound[0] += skinSize;
  759. this.upperBound[1] += skinSize;
  760. }
  761. };
  762. /**
  763. * Copy bounds from an AABB to this AABB
  764. * @method copy
  765. * @param {AABB} aabb
  766. */
  767. AABB.prototype.copy = function(aabb){
  768. vec2.copy(this.lowerBound, aabb.lowerBound);
  769. vec2.copy(this.upperBound, aabb.upperBound);
  770. };
  771. /**
  772. * Extend this AABB so that it covers the given AABB too.
  773. * @method extend
  774. * @param {AABB} aabb
  775. */
  776. AABB.prototype.extend = function(aabb){
  777. // Loop over x and y
  778. var i = 2;
  779. while(i--){
  780. // Extend lower bound
  781. var l = aabb.lowerBound[i];
  782. if(this.lowerBound[i] > l){
  783. this.lowerBound[i] = l;
  784. }
  785. // Upper
  786. var u = aabb.upperBound[i];
  787. if(this.upperBound[i] < u){
  788. this.upperBound[i] = u;
  789. }
  790. }
  791. };
  792. /**
  793. * Returns true if the given AABB overlaps this AABB.
  794. * @method overlaps
  795. * @param {AABB} aabb
  796. * @return {Boolean}
  797. */
  798. AABB.prototype.overlaps = function(aabb){
  799. var l1 = this.lowerBound,
  800. u1 = this.upperBound,
  801. l2 = aabb.lowerBound,
  802. u2 = aabb.upperBound;
  803. // l2 u2
  804. // |---------|
  805. // |--------|
  806. // l1 u1
  807. return ((l2[0] <= u1[0] && u1[0] <= u2[0]) || (l1[0] <= u2[0] && u2[0] <= u1[0])) &&
  808. ((l2[1] <= u1[1] && u1[1] <= u2[1]) || (l1[1] <= u2[1] && u2[1] <= u1[1]));
  809. };
  810. /**
  811. * @method containsPoint
  812. * @param {Array} point
  813. * @return {boolean}
  814. */
  815. AABB.prototype.containsPoint = function(point){
  816. var l = this.lowerBound,
  817. u = this.upperBound;
  818. return l[0] <= point[0] && point[0] <= u[0] && l[1] <= point[1] && point[1] <= u[1];
  819. };
  820. /**
  821. * Check if the AABB is hit by a ray.
  822. * @method overlapsRay
  823. * @param {Ray} ray
  824. * @return {number} -1 if no hit, a number between 0 and 1 if hit.
  825. */
  826. AABB.prototype.overlapsRay = function(ray){
  827. var t = 0;
  828. // ray.direction is unit direction vector of ray
  829. var dirFracX = 1 / ray.direction[0];
  830. var dirFracY = 1 / ray.direction[1];
  831. // this.lowerBound is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
  832. var t1 = (this.lowerBound[0] - ray.from[0]) * dirFracX;
  833. var t2 = (this.upperBound[0] - ray.from[0]) * dirFracX;
  834. var t3 = (this.lowerBound[1] - ray.from[1]) * dirFracY;
  835. var t4 = (this.upperBound[1] - ray.from[1]) * dirFracY;
  836. var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)));
  837. var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)));
  838. // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
  839. if (tmax < 0){
  840. //t = tmax;
  841. return -1;
  842. }
  843. // if tmin > tmax, ray doesn't intersect AABB
  844. if (tmin > tmax){
  845. //t = tmax;
  846. return -1;
  847. }
  848. return tmin;
  849. };
  850. },{"../math/vec2":30,"../utils/Utils":57}],8:[function(_dereq_,module,exports){
  851. var vec2 = _dereq_('../math/vec2');
  852. var Body = _dereq_('../objects/Body');
  853. module.exports = Broadphase;
  854. /**
  855. * Base class for broadphase implementations.
  856. * @class Broadphase
  857. * @constructor
  858. */
  859. function Broadphase(type){
  860. this.type = type;
  861. /**
  862. * The resulting overlapping pairs. Will be filled with results during .getCollisionPairs().
  863. * @property result
  864. * @type {Array}
  865. */
  866. this.result = [];
  867. /**
  868. * The world to search for collision pairs in. To change it, use .setWorld()
  869. * @property world
  870. * @type {World}
  871. * @readOnly
  872. */
  873. this.world = null;
  874. /**
  875. * The bounding volume type to use in the broadphase algorithms. Should be set to Broadphase.AABB or Broadphase.BOUNDING_CIRCLE.
  876. * @property {Number} boundingVolumeType
  877. */
  878. this.boundingVolumeType = Broadphase.AABB;
  879. }
  880. /**
  881. * Axis aligned bounding box type.
  882. * @static
  883. * @property {Number} AABB
  884. */
  885. Broadphase.AABB = 1;
  886. /**
  887. * Bounding circle type.
  888. * @static
  889. * @property {Number} BOUNDING_CIRCLE
  890. */
  891. Broadphase.BOUNDING_CIRCLE = 2;
  892. /**
  893. * Set the world that we are searching for collision pairs in.
  894. * @method setWorld
  895. * @param {World} world
  896. */
  897. Broadphase.prototype.setWorld = function(world){
  898. this.world = world;
  899. };
  900. /**
  901. * Get all potential intersecting body pairs.
  902. * @method getCollisionPairs
  903. * @param {World} world The world to search in.
  904. * @return {Array} An array of the bodies, ordered in pairs. Example: A result of [a,b,c,d] means that the potential pairs are: (a,b), (c,d).
  905. */
  906. Broadphase.prototype.getCollisionPairs = function(world){};
  907. var dist = vec2.create();
  908. /**
  909. * Check whether the bounding radius of two bodies overlap.
  910. * @method boundingRadiusCheck
  911. * @param {Body} bodyA
  912. * @param {Body} bodyB
  913. * @return {Boolean}
  914. */
  915. Broadphase.boundingRadiusCheck = function(bodyA, bodyB){
  916. vec2.sub(dist, bodyA.position, bodyB.position);
  917. var d2 = vec2.squaredLength(dist),
  918. r = bodyA.boundingRadius + bodyB.boundingRadius;
  919. return d2 <= r*r;
  920. };
  921. /**
  922. * Check whether the bounding radius of two bodies overlap.
  923. * @method boundingRadiusCheck
  924. * @param {Body} bodyA
  925. * @param {Body} bodyB
  926. * @return {Boolean}
  927. */
  928. Broadphase.aabbCheck = function(bodyA, bodyB){
  929. return bodyA.getAABB().overlaps(bodyB.getAABB());
  930. };
  931. /**
  932. * Check whether the bounding radius of two bodies overlap.
  933. * @method boundingRadiusCheck
  934. * @param {Body} bodyA
  935. * @param {Body} bodyB
  936. * @return {Boolean}
  937. */
  938. Broadphase.prototype.boundingVolumeCheck = function(bodyA, bodyB){
  939. var result;
  940. switch(this.boundingVolumeType){
  941. case Broadphase.BOUNDING_CIRCLE:
  942. result = Broadphase.boundingRadiusCheck(bodyA,bodyB);
  943. break;
  944. case Broadphase.AABB:
  945. result = Broadphase.aabbCheck(bodyA,bodyB);
  946. break;
  947. default:
  948. throw new Error('Bounding volume type not recognized: '+this.boundingVolumeType);
  949. }
  950. return result;
  951. };
  952. /**
  953. * Check whether two bodies are allowed to collide at all.
  954. * @method canCollide
  955. * @param {Body} bodyA
  956. * @param {Body} bodyB
  957. * @return {Boolean}
  958. */
  959. Broadphase.canCollide = function(bodyA, bodyB){
  960. var KINEMATIC = Body.KINEMATIC;
  961. var STATIC = Body.STATIC;
  962. // Cannot collide static bodies
  963. if(bodyA.type === STATIC && bodyB.type === STATIC){
  964. return false;
  965. }
  966. // Cannot collide static vs kinematic bodies
  967. if( (bodyA.type === KINEMATIC && bodyB.type === STATIC) ||
  968. (bodyA.type === STATIC && bodyB.type === KINEMATIC)){
  969. return false;
  970. }
  971. // Cannot collide kinematic vs kinematic
  972. if(bodyA.type === KINEMATIC && bodyB.type === KINEMATIC){
  973. return false;
  974. }
  975. // Cannot collide both sleeping bodies
  976. if(bodyA.sleepState === Body.SLEEPING && bodyB.sleepState === Body.SLEEPING){
  977. return false;
  978. }
  979. // Cannot collide if one is static and the other is sleeping
  980. if( (bodyA.sleepState === Body.SLEEPING && bodyB.type === STATIC) ||
  981. (bodyB.sleepState === Body.SLEEPING && bodyA.type === STATIC)){
  982. return false;
  983. }
  984. return true;
  985. };
  986. Broadphase.NAIVE = 1;
  987. Broadphase.SAP = 2;
  988. },{"../math/vec2":30,"../objects/Body":31}],9:[function(_dereq_,module,exports){
  989. var Circle = _dereq_('../shapes/Circle'),
  990. Plane = _dereq_('../shapes/Plane'),
  991. Shape = _dereq_('../shapes/Shape'),
  992. Particle = _dereq_('../shapes/Particle'),
  993. Broadphase = _dereq_('../collision/Broadphase'),
  994. vec2 = _dereq_('../math/vec2');
  995. module.exports = NaiveBroadphase;
  996. /**
  997. * Naive broadphase implementation. Does N^2 tests.
  998. *
  999. * @class NaiveBroadphase
  1000. * @constructor
  1001. * @extends Broadphase
  1002. */
  1003. function NaiveBroadphase(){
  1004. Broadphase.call(this, Broadphase.NAIVE);
  1005. }
  1006. NaiveBroadphase.prototype = new Broadphase();
  1007. NaiveBroadphase.prototype.constructor = NaiveBroadphase;
  1008. /**
  1009. * Get the colliding pairs
  1010. * @method getCollisionPairs
  1011. * @param {World} world
  1012. * @return {Array}
  1013. */
  1014. NaiveBroadphase.prototype.getCollisionPairs = function(world){
  1015. var bodies = world.bodies,
  1016. result = this.result;
  1017. result.length = 0;
  1018. for(var i=0, Ncolliding=bodies.length; i!==Ncolliding; i++){
  1019. var bi = bodies[i];
  1020. for(var j=0; j<i; j++){
  1021. var bj = bodies[j];
  1022. if(Broadphase.canCollide(bi,bj) && this.boundingVolumeCheck(bi,bj)){
  1023. result.push(bi,bj);
  1024. }
  1025. }
  1026. }
  1027. return result;
  1028. };
  1029. /**
  1030. * Returns all the bodies within an AABB.
  1031. * @method aabbQuery
  1032. * @param {World} world
  1033. * @param {AABB} aabb
  1034. * @param {array} result An array to store resulting bodies in.
  1035. * @return {array}
  1036. */
  1037. NaiveBroadphase.prototype.aabbQuery = function(world, aabb, result){
  1038. result = result || [];
  1039. var bodies = world.bodies;
  1040. for(var i = 0; i < bodies.length; i++){
  1041. var b = bodies[i];
  1042. if(b.aabbNeedsUpdate){
  1043. b.updateAABB();
  1044. }
  1045. if(b.aabb.overlaps(aabb)){
  1046. result.push(b);
  1047. }
  1048. }
  1049. return result;
  1050. };
  1051. },{"../collision/Broadphase":8,"../math/vec2":30,"../shapes/Circle":39,"../shapes/Particle":43,"../shapes/Plane":44,"../shapes/Shape":45}],10:[function(_dereq_,module,exports){
  1052. var vec2 = _dereq_('../math/vec2')
  1053. , sub = vec2.sub
  1054. , add = vec2.add
  1055. , dot = vec2.dot
  1056. , Utils = _dereq_('../utils/Utils')
  1057. , ContactEquationPool = _dereq_('../utils/ContactEquationPool')
  1058. , FrictionEquationPool = _dereq_('../utils/FrictionEquationPool')
  1059. , TupleDictionary = _dereq_('../utils/TupleDictionary')
  1060. , Equation = _dereq_('../equations/Equation')
  1061. , ContactEquation = _dereq_('../equations/ContactEquation')
  1062. , FrictionEquation = _dereq_('../equations/FrictionEquation')
  1063. , Circle = _dereq_('../shapes/Circle')
  1064. , Convex = _dereq_('../shapes/Convex')
  1065. , Shape = _dereq_('../shapes/Shape')
  1066. , Body = _dereq_('../objects/Body')
  1067. , Box = _dereq_('../shapes/Box');
  1068. module.exports = Narrowphase;
  1069. // Temp things
  1070. var yAxis = vec2.fromValues(0,1);
  1071. var tmp1 = vec2.fromValues(0,0)
  1072. , tmp2 = vec2.fromValues(0,0)
  1073. , tmp3 = vec2.fromValues(0,0)
  1074. , tmp4 = vec2.fromValues(0,0)
  1075. , tmp5 = vec2.fromValues(0,0)
  1076. , tmp6 = vec2.fromValues(0,0)
  1077. , tmp7 = vec2.fromValues(0,0)
  1078. , tmp8 = vec2.fromValues(0,0)
  1079. , tmp9 = vec2.fromValues(0,0)
  1080. , tmp10 = vec2.fromValues(0,0)
  1081. , tmp11 = vec2.fromValues(0,0)
  1082. , tmp12 = vec2.fromValues(0,0)
  1083. , tmp13 = vec2.fromValues(0,0)
  1084. , tmp14 = vec2.fromValues(0,0)
  1085. , tmp15 = vec2.fromValues(0,0)
  1086. , tmp16 = vec2.fromValues(0,0)
  1087. , tmp17 = vec2.fromValues(0,0)
  1088. , tmp18 = vec2.fromValues(0,0)
  1089. , tmpArray = [];
  1090. /**
  1091. * Narrowphase. Creates contacts and friction given shapes and transforms.
  1092. * @class Narrowphase
  1093. * @constructor
  1094. */
  1095. function Narrowphase(){
  1096. /**
  1097. * @property contactEquations
  1098. * @type {Array}
  1099. */
  1100. this.contactEquations = [];
  1101. /**
  1102. * @property frictionEquations
  1103. * @type {Array}
  1104. */
  1105. this.frictionEquations = [];
  1106. /**
  1107. * Whether to make friction equations in the upcoming contacts.
  1108. * @property enableFriction
  1109. * @type {Boolean}
  1110. */
  1111. this.enableFriction = true;
  1112. /**
  1113. * Whether to make equations enabled in upcoming contacts.
  1114. * @property enabledEquations
  1115. * @type {Boolean}
  1116. */
  1117. this.enabledEquations = true;
  1118. /**
  1119. * The friction slip force to use when creating friction equations.
  1120. * @property slipForce
  1121. * @type {Number}
  1122. */
  1123. this.slipForce = 10.0;
  1124. /**
  1125. * The friction value to use in the upcoming friction equations.
  1126. * @property frictionCoefficient
  1127. * @type {Number}
  1128. */
  1129. this.frictionCoefficient = 0.3;
  1130. /**
  1131. * Will be the .relativeVelocity in each produced FrictionEquation.
  1132. * @property {Number} surfaceVelocity
  1133. */
  1134. this.surfaceVelocity = 0;
  1135. /**
  1136. * Keeps track of the allocated ContactEquations.
  1137. * @property {ContactEquationPool} contactEquationPool
  1138. *
  1139. * @example
  1140. *
  1141. * // Allocate a few equations before starting the simulation.
  1142. * // This way, no contact objects need to be created on the fly in the game loop.
  1143. * world.narrowphase.contactEquationPool.resize(1024);
  1144. * world.narrowphase.frictionEquationPool.resize(1024);
  1145. */
  1146. this.contactEquationPool = new ContactEquationPool({ size: 32 });
  1147. /**
  1148. * Keeps track of the allocated ContactEquations.
  1149. * @property {FrictionEquationPool} frictionEquationPool
  1150. */
  1151. this.frictionEquationPool = new FrictionEquationPool({ size: 64 });
  1152. /**
  1153. * The restitution value to use in the next contact equations.
  1154. * @property restitution
  1155. * @type {Number}
  1156. */
  1157. this.restitution = 0;
  1158. /**
  1159. * The stiffness value to use in the next contact equations.
  1160. * @property {Number} stiffness
  1161. */
  1162. this.stiffness = Equation.DEFAULT_STIFFNESS;
  1163. /**
  1164. * The stiffness value to use in the next contact equations.
  1165. * @property {Number} stiffness
  1166. */
  1167. this.relaxation = Equation.DEFAULT_RELAXATION;
  1168. /**
  1169. * The stiffness value to use in the next friction equations.
  1170. * @property frictionStiffness
  1171. * @type {Number}
  1172. */
  1173. this.frictionStiffness = Equation.DEFAULT_STIFFNESS;
  1174. /**
  1175. * The relaxation value to use in the next friction equations.
  1176. * @property frictionRelaxation
  1177. * @type {Number}
  1178. */
  1179. this.frictionRelaxation = Equation.DEFAULT_RELAXATION;
  1180. /**
  1181. * Enable reduction of friction equations. If disabled, a box on a plane will generate 2 contact equations and 2 friction equations. If enabled, there will be only one friction equation. Same kind of simplifications are made for all collision types.
  1182. * @property enableFrictionReduction
  1183. * @type {Boolean}
  1184. * @deprecated This flag will be removed when the feature is stable enough.
  1185. * @default true
  1186. */
  1187. this.enableFrictionReduction = true;
  1188. /**
  1189. * Keeps track of the colliding bodies last step.
  1190. * @private
  1191. * @property collidingBodiesLastStep
  1192. * @type {TupleDictionary}
  1193. */
  1194. this.collidingBodiesLastStep = new TupleDictionary();
  1195. /**
  1196. * Contact skin size value to use in the next contact equations.
  1197. * @property {Number} contactSkinSize
  1198. * @default 0.01
  1199. */
  1200. this.contactSkinSize = 0.01;
  1201. }
  1202. var bodiesOverlap_shapePositionA = vec2.create();
  1203. var bodiesOverlap_shapePositionB = vec2.create();
  1204. /**
  1205. * @method bodiesOverlap
  1206. * @param {Body} bodyA
  1207. * @param {Body} bodyB
  1208. * @return {Boolean}
  1209. * @todo shape world transforms are wrong
  1210. */
  1211. Narrowphase.prototype.bodiesOverlap = function(bodyA, bodyB){
  1212. var shapePositionA = bodiesOverlap_shapePositionA;
  1213. var shapePositionB = bodiesOverlap_shapePositionB;
  1214. // Loop over all shapes of bodyA
  1215. for(var k=0, Nshapesi=bodyA.shapes.length; k!==Nshapesi; k++){
  1216. var shapeA = bodyA.shapes[k];
  1217. bodyA.toWorldFrame(shapePositionA, shapeA.position);
  1218. // All shapes of body j
  1219. for(var l=0, Nshapesj=bodyB.shapes.length; l!==Nshapesj; l++){
  1220. var shapeB = bodyB.shapes[l];
  1221. bodyB.toWorldFrame(shapePositionB, shapeB.position);
  1222. if(this[shapeA.type | shapeB.type](
  1223. bodyA,
  1224. shapeA,
  1225. shapePositionA,
  1226. shapeA.angle + bodyA.angle,
  1227. bodyB,
  1228. shapeB,
  1229. shapePositionB,
  1230. shapeB.angle + bodyB.angle,
  1231. true
  1232. )){
  1233. return true;
  1234. }
  1235. }
  1236. }
  1237. return false;
  1238. };
  1239. /**
  1240. * Check if the bodies were in contact since the last reset().
  1241. * @method collidedLastStep
  1242. * @param {Body} bodyA
  1243. * @param {Body} bodyB
  1244. * @return {Boolean}
  1245. */
  1246. Narrowphase.prototype.collidedLastStep = function(bodyA, bodyB){
  1247. var id1 = bodyA.id|0,
  1248. id2 = bodyB.id|0;
  1249. return !!this.collidingBodiesLastStep.get(id1, id2);
  1250. };
  1251. /**
  1252. * Throws away the old equations and gets ready to create new
  1253. * @method reset
  1254. */
  1255. Narrowphase.prototype.reset = function(){
  1256. this.collidingBodiesLastStep.reset();
  1257. var eqs = this.contactEquations;
  1258. var l = eqs.length;
  1259. while(l--){
  1260. var eq = eqs[l],
  1261. id1 = eq.bodyA.id,
  1262. id2 = eq.bodyB.id;
  1263. this.collidingBodiesLastStep.set(id1, id2, true);
  1264. }
  1265. var ce = this.contactEquations,
  1266. fe = this.frictionEquations;
  1267. for(var i=0; i<ce.length; i++){
  1268. this.contactEquationPool.release(ce[i]);
  1269. }
  1270. for(var i=0; i<fe.length; i++){
  1271. this.frictionEquationPool.release(fe[i]);
  1272. }
  1273. // Reset
  1274. this.contactEquations.length = this.frictionEquations.length = 0;
  1275. };
  1276. /**
  1277. * Creates a ContactEquation, either by reusing an existing object or creating a new one.
  1278. * @method createContactEquation
  1279. * @param {Body} bodyA
  1280. * @param {Body} bodyB
  1281. * @return {ContactEquation}
  1282. */
  1283. Narrowphase.prototype.createContactEquation = function(bodyA, bodyB, shapeA, shapeB){
  1284. var c = this.contactEquationPool.get();
  1285. c.bodyA = bodyA;
  1286. c.bodyB = bodyB;
  1287. c.shapeA = shapeA;
  1288. c.shapeB = shapeB;
  1289. c.restitution = this.restitution;
  1290. c.firstImpact = !this.collidedLastStep(bodyA,bodyB);
  1291. c.stiffness = this.stiffness;
  1292. c.relaxation = this.relaxation;
  1293. c.needsUpdate = true;
  1294. c.enabled = this.enabledEquations;
  1295. c.offset = this.contactSkinSize;
  1296. return c;
  1297. };
  1298. /**
  1299. * Creates a FrictionEquation, either by reusing an existing object or creating a new one.
  1300. * @method createFrictionEquation
  1301. * @param {Body} bodyA
  1302. * @param {Body} bodyB
  1303. * @return {FrictionEquation}
  1304. */
  1305. Narrowphase.prototype.createFrictionEquation = function(bodyA, bodyB, shapeA, shapeB){
  1306. var c = this.frictionEquationPool.get();
  1307. c.bodyA = bodyA;
  1308. c.bodyB = bodyB;
  1309. c.shapeA = shapeA;
  1310. c.shapeB = shapeB;
  1311. c.setSlipForce(this.slipForce);
  1312. c.frictionCoefficient = this.frictionCoefficient;
  1313. c.relativeVelocity = this.surfaceVelocity;
  1314. c.enabled = this.enabledEquations;
  1315. c.needsUpdate = true;
  1316. c.stiffness = this.frictionStiffness;
  1317. c.relaxation = this.frictionRelaxation;
  1318. c.contactEquations.length = 0;
  1319. return c;
  1320. };
  1321. /**
  1322. * Creates a FrictionEquation given the data in the ContactEquation. Uses same offset vectors ri and rj, but the tangent vector will be constructed from the collision normal.
  1323. * @method createFrictionFromContact
  1324. * @param {ContactEquation} contactEquation
  1325. * @return {FrictionEquation}
  1326. */
  1327. Narrowphase.prototype.createFrictionFromContact = function(c){
  1328. var eq = this.createFrictionEquation(c.bodyA, c.bodyB, c.shapeA, c.shapeB);
  1329. vec2.copy(eq.contactPointA, c.contactPointA);
  1330. vec2.copy(eq.contactPointB, c.contactPointB);
  1331. vec2.rotate90cw(eq.t, c.normalA);
  1332. eq.contactEquations.push(c);
  1333. return eq;
  1334. };
  1335. // Take the average N latest contact point on the plane.
  1336. Narrowphase.prototype.createFrictionFromAverage = function(numContacts){
  1337. var c = this.contactEquations[this.contactEquations.length - 1];
  1338. var eq = this.createFrictionEquation(c.bodyA, c.bodyB, c.shapeA, c.shapeB);
  1339. var bodyA = c.bodyA;
  1340. var bodyB = c.bodyB;
  1341. vec2.set(eq.contactPointA, 0, 0);
  1342. vec2.set(eq.contactPointB, 0, 0);
  1343. vec2.set(eq.t, 0, 0);
  1344. for(var i=0; i!==numContacts; i++){
  1345. c = this.contactEquations[this.contactEquations.length - 1 - i];
  1346. if(c.bodyA === bodyA){
  1347. vec2.add(eq.t, eq.t, c.normalA);
  1348. vec2.add(eq.contactPointA, eq.contactPointA, c.contactPointA);
  1349. vec2.add(eq.contactPointB, eq.contactPointB, c.contactPointB);
  1350. } else {
  1351. vec2.sub(eq.t, eq.t, c.normalA);
  1352. vec2.add(eq.contactPointA, eq.contactPointA, c.contactPointB);
  1353. vec2.add(eq.contactPointB, eq.contactPointB, c.contactPointA);
  1354. }
  1355. eq.contactEquations.push(c);
  1356. }
  1357. var invNumContacts = 1/numContacts;
  1358. vec2.scale(eq.contactPointA, eq.contactPointA, invNumContacts);
  1359. vec2.scale(eq.contactPointB, eq.contactPointB, invNumContacts);
  1360. vec2.normalize(eq.t, eq.t);
  1361. vec2.rotate90cw(eq.t, eq.t);
  1362. return eq;
  1363. };
  1364. /**
  1365. * Convex/line narrowphase
  1366. * @method convexLine
  1367. * @param {Body} convexBody
  1368. * @param {Convex} convexShape
  1369. * @param {Array} convexOffset
  1370. * @param {Number} convexAngle
  1371. * @param {Body} lineBody
  1372. * @param {Line} lineShape
  1373. * @param {Array} lineOffset
  1374. * @param {Number} lineAngle
  1375. * @param {boolean} justTest
  1376. * @todo Implement me!
  1377. */
  1378. Narrowphase.prototype[Shape.LINE | Shape.CONVEX] =
  1379. Narrowphase.prototype.convexLine = function(
  1380. convexBody,
  1381. convexShape,
  1382. convexOffset,
  1383. convexAngle,
  1384. lineBody,
  1385. lineShape,
  1386. lineOffset,
  1387. lineAngle,
  1388. justTest
  1389. ){
  1390. // TODO
  1391. if(justTest){
  1392. return false;
  1393. } else {
  1394. return 0;
  1395. }
  1396. };
  1397. /**
  1398. * Line/box narrowphase
  1399. * @method lineBox
  1400. * @param {Body} lineBody
  1401. * @param {Line} lineShape
  1402. * @param {Array} lineOffset
  1403. * @param {Number} lineAngle
  1404. * @param {Body} boxBody
  1405. * @param {Box} boxShape
  1406. * @param {Array} boxOffset
  1407. * @param {Number} boxAngle
  1408. * @param {Boolean} justTest
  1409. * @todo Implement me!
  1410. */
  1411. Narrowphase.prototype[Shape.LINE | Shape.BOX] =
  1412. Narrowphase.prototype.lineBox = function(
  1413. lineBody,
  1414. lineShape,
  1415. lineOffset,
  1416. lineAngle,
  1417. boxBody,
  1418. boxShape,
  1419. boxOffset,
  1420. boxAngle,
  1421. justTest
  1422. ){
  1423. // TODO
  1424. if(justTest){
  1425. return false;
  1426. } else {
  1427. return 0;
  1428. }
  1429. };
  1430. function setConvexToCapsuleShapeMiddle(convexShape, capsuleShape){
  1431. vec2.set(convexShape.vertices[0], -capsuleShape.length * 0.5, -capsuleShape.radius);
  1432. vec2.set(convexShape.vertices[1], capsuleShape.length * 0.5, -capsuleShape.radius);
  1433. vec2.set(convexShape.vertices[2], capsuleShape.length * 0.5, capsuleShape.radius);
  1434. vec2.set(convexShape.vertices[3], -capsuleShape.length * 0.5, capsuleShape.radius);
  1435. }
  1436. var convexCapsule_tempRect = new Box({ width: 1, height: 1 }),
  1437. convexCapsule_tempVec = vec2.create();
  1438. /**
  1439. * Convex/capsule narrowphase
  1440. * @method convexCapsule
  1441. * @param {Body} convexBody
  1442. * @param {Convex} convexShape
  1443. * @param {Array} convexPosition
  1444. * @param {Number} convexAngle
  1445. * @param {Body} capsuleBody
  1446. * @param {Capsule} capsuleShape
  1447. * @param {Array} capsulePosition
  1448. * @param {Number} capsuleAngle
  1449. */
  1450. Narrowphase.prototype[Shape.CAPSULE | Shape.CONVEX] =
  1451. Narrowphase.prototype[Shape.CAPSULE | Shape.BOX] =
  1452. Narrowphase.prototype.convexCapsule = function(
  1453. convexBody,
  1454. convexShape,
  1455. convexPosition,
  1456. convexAngle,
  1457. capsuleBody,
  1458. capsuleShape,
  1459. capsulePosition,
  1460. capsuleAngle,
  1461. justTest
  1462. ){
  1463. // Check the circles
  1464. // Add offsets!
  1465. var circlePos = convexCapsule_tempVec;
  1466. vec2.set(circlePos, capsuleShape.length/2,0);
  1467. vec2.rotate(circlePos,circlePos,capsuleAngle);
  1468. vec2.add(circlePos,circlePos,capsulePosition);
  1469. var result1 = this.circleConvex(capsuleBody,capsuleShape,circlePos,capsuleAngle, convexBody,convexShape,convexPosition,convexAngle, justTest, capsuleShape.radius);
  1470. vec2.set(circlePos,-capsuleShape.length/2, 0);
  1471. vec2.rotate(circlePos,circlePos,capsuleAngle);
  1472. vec2.add(circlePos,circlePos,capsulePosition);
  1473. var result2 = this.circleConvex(capsuleBody,capsuleShape,circlePos,capsuleAngle, convexBody,convexShape,convexPosition,convexAngle, justTest, capsuleShape.radius);
  1474. if(justTest && (result1 || result2)){
  1475. return true;
  1476. }
  1477. // Check center rect
  1478. var r = convexCapsule_tempRect;
  1479. setConvexToCapsuleShapeMiddle(r,capsuleShape);
  1480. var result = this.convexConvex(convexBody,convexShape,convexPosition,convexAngle, capsuleBody,r,capsulePosition,capsuleAngle, justTest);
  1481. return result + result1 + result2;
  1482. };
  1483. /**
  1484. * Capsule/line narrowphase
  1485. * @method lineCapsule
  1486. * @param {Body} lineBody
  1487. * @param {Line} lineShape
  1488. * @param {Array} linePosition
  1489. * @param {Number} lineAngle
  1490. * @param {Body} capsuleBody
  1491. * @param {Capsule} capsuleShape
  1492. * @param {Array} capsulePosition
  1493. * @param {Number} capsuleAngle
  1494. * @todo Implement me!
  1495. */
  1496. Narrowphase.prototype[Shape.CAPSULE | Shape.LINE] =
  1497. Narrowphase.prototype.lineCapsule = function(
  1498. lineBody,
  1499. lineShape,
  1500. linePosition,
  1501. lineAngle,
  1502. capsuleBody,
  1503. capsuleShape,
  1504. capsulePosition,
  1505. capsuleAngle,
  1506. justTest
  1507. ){
  1508. // TODO
  1509. if(justTest){
  1510. return false;
  1511. } else {
  1512. return 0;
  1513. }
  1514. };
  1515. var capsuleCapsule_tempVec1 = vec2.create();
  1516. var capsuleCapsule_tempVec2 = vec2.create();
  1517. var capsuleCapsule_tempRect1 = new Box({ width: 1, height: 1 });
  1518. /**
  1519. * Capsule/capsule narrowphase
  1520. * @method capsuleCapsule
  1521. * @param {Body} bi
  1522. * @param {Capsule} si
  1523. * @param {Array} xi
  1524. * @param {Number} ai
  1525. * @param {Body} bj
  1526. * @param {Capsule} sj
  1527. * @param {Array} xj
  1528. * @param {Number} aj
  1529. */
  1530. Narrowphase.prototype[Shape.CAPSULE | Shape.CAPSULE] =
  1531. Narrowphase.prototype.capsuleCapsule = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1532. var enableFrictionBefore;
  1533. // Check the circles
  1534. // Add offsets!
  1535. var circlePosi = capsuleCapsule_tempVec1,
  1536. circlePosj = capsuleCapsule_tempVec2;
  1537. var numContacts = 0;
  1538. // Need 4 circle checks, between all
  1539. for(var i=0; i<2; i++){
  1540. vec2.set(circlePosi,(i===0?-1:1)*si.length/2,0);
  1541. vec2.rotate(circlePosi,circlePosi,ai);
  1542. vec2.add(circlePosi,circlePosi,xi);
  1543. for(var j=0; j<2; j++){
  1544. vec2.set(circlePosj,(j===0?-1:1)*sj.length/2, 0);
  1545. vec2.rotate(circlePosj,circlePosj,aj);
  1546. vec2.add(circlePosj,circlePosj,xj);
  1547. // Temporarily turn off friction
  1548. if(this.enableFrictionReduction){
  1549. enableFrictionBefore = this.enableFriction;
  1550. this.enableFriction = false;
  1551. }
  1552. var result = this.circleCircle(bi,si,circlePosi,ai, bj,sj,circlePosj,aj, justTest, si.radius, sj.radius);
  1553. if(this.enableFrictionReduction){
  1554. this.enableFriction = enableFrictionBefore;
  1555. }
  1556. if(justTest && result){
  1557. return true;
  1558. }
  1559. numContacts += result;
  1560. }
  1561. }
  1562. if(this.enableFrictionReduction){
  1563. // Temporarily turn off friction
  1564. enableFrictionBefore = this.enableFriction;
  1565. this.enableFriction = false;
  1566. }
  1567. // Check circles against the center boxs
  1568. var rect = capsuleCapsule_tempRect1;
  1569. setConvexToCapsuleShapeMiddle(rect,si);
  1570. var result1 = this.convexCapsule(bi,rect,xi,ai, bj,sj,xj,aj, justTest);
  1571. if(this.enableFrictionReduction){
  1572. this.enableFriction = enableFrictionBefore;
  1573. }
  1574. if(justTest && result1){
  1575. return true;
  1576. }
  1577. numContacts += result1;
  1578. if(this.enableFrictionReduction){
  1579. // Temporarily turn off friction
  1580. var enableFrictionBefore = this.enableFriction;
  1581. this.enableFriction = false;
  1582. }
  1583. setConvexToCapsuleShapeMiddle(rect,sj);
  1584. var result2 = this.convexCapsule(bj,rect,xj,aj, bi,si,xi,ai, justTest);
  1585. if(this.enableFrictionReduction){
  1586. this.enableFriction = enableFrictionBefore;
  1587. }
  1588. if(justTest && result2){
  1589. return true;
  1590. }
  1591. numContacts += result2;
  1592. if(this.enableFrictionReduction){
  1593. if(numContacts && this.enableFriction){
  1594. this.frictionEquations.push(this.createFrictionFromAverage(numContacts));
  1595. }
  1596. }
  1597. return numContacts;
  1598. };
  1599. /**
  1600. * Line/line narrowphase
  1601. * @method lineLine
  1602. * @param {Body} bodyA
  1603. * @param {Line} shapeA
  1604. * @param {Array} positionA
  1605. * @param {Number} angleA
  1606. * @param {Body} bodyB
  1607. * @param {Line} shapeB
  1608. * @param {Array} positionB
  1609. * @param {Number} angleB
  1610. * @todo Implement me!
  1611. */
  1612. Narrowphase.prototype[Shape.LINE | Shape.LINE] =
  1613. Narrowphase.prototype.lineLine = function(
  1614. bodyA,
  1615. shapeA,
  1616. positionA,
  1617. angleA,
  1618. bodyB,
  1619. shapeB,
  1620. positionB,
  1621. angleB,
  1622. justTest
  1623. ){
  1624. // TODO
  1625. if(justTest){
  1626. return false;
  1627. } else {
  1628. return 0;
  1629. }
  1630. };
  1631. /**
  1632. * Plane/line Narrowphase
  1633. * @method planeLine
  1634. * @param {Body} planeBody
  1635. * @param {Plane} planeShape
  1636. * @param {Array} planeOffset
  1637. * @param {Number} planeAngle
  1638. * @param {Body} lineBody
  1639. * @param {Line} lineShape
  1640. * @param {Array} lineOffset
  1641. * @param {Number} lineAngle
  1642. */
  1643. Narrowphase.prototype[Shape.PLANE | Shape.LINE] =
  1644. Narrowphase.prototype.planeLine = function(planeBody, planeShape, planeOffset, planeAngle,
  1645. lineBody, lineShape, lineOffset, lineAngle, justTest){
  1646. var worldVertex0 = tmp1,
  1647. worldVertex1 = tmp2,
  1648. worldVertex01 = tmp3,
  1649. worldVertex11 = tmp4,
  1650. worldEdge = tmp5,
  1651. worldEdgeUnit = tmp6,
  1652. dist = tmp7,
  1653. worldNormal = tmp8,
  1654. worldTangent = tmp9,
  1655. verts = tmpArray,
  1656. numContacts = 0;
  1657. // Get start and end points
  1658. vec2.set(worldVertex0, -lineShape.length/2, 0);
  1659. vec2.set(worldVertex1, lineShape.length/2, 0);
  1660. // Not sure why we have to use worldVertex*1 here, but it won't work otherwise. Tired.
  1661. vec2.rotate(worldVertex01, worldVertex0, lineAngle);
  1662. vec2.rotate(worldVertex11, worldVertex1, lineAngle);
  1663. add(worldVertex01, worldVertex01, lineOffset);
  1664. add(worldVertex11, worldVertex11, lineOffset);
  1665. vec2.copy(worldVertex0,worldVertex01);
  1666. vec2.copy(worldVertex1,worldVertex11);
  1667. // Get vector along the line
  1668. sub(worldEdge, worldVertex1, worldVertex0);
  1669. vec2.normalize(worldEdgeUnit, worldEdge);
  1670. // Get tangent to the edge.
  1671. vec2.rotate90cw(worldTangent, worldEdgeUnit);
  1672. vec2.rotate(worldNormal, yAxis, planeAngle);
  1673. // Check line ends
  1674. verts[0] = worldVertex0;
  1675. verts[1] = worldVertex1;
  1676. for(var i=0; i<verts.length; i++){
  1677. var v = verts[i];
  1678. sub(dist, v, planeOffset);
  1679. var d = dot(dist,worldNormal);
  1680. if(d < 0){
  1681. if(justTest){
  1682. return true;
  1683. }
  1684. var c = this.createContactEquation(planeBody,lineBody,planeShape,lineShape);
  1685. numContacts++;
  1686. vec2.copy(c.normalA, worldNormal);
  1687. vec2.normalize(c.normalA,c.normalA);
  1688. // distance vector along plane normal
  1689. vec2.scale(dist, worldNormal, d);
  1690. // Vector from plane center to contact
  1691. sub(c.contactPointA, v, dist);
  1692. sub(c.contactPointA, c.contactPointA, planeBody.position);
  1693. // From line center to contact
  1694. sub(c.contactPointB, v, lineOffset);
  1695. add(c.contactPointB, c.contactPointB, lineOffset);
  1696. sub(c.contactPointB, c.contactPointB, lineBody.position);
  1697. this.contactEquations.push(c);
  1698. if(!this.enableFrictionReduction){
  1699. if(this.enableFriction){
  1700. this.frictionEquations.push(this.createFrictionFromContact(c));
  1701. }
  1702. }
  1703. }
  1704. }
  1705. if(justTest){
  1706. return false;
  1707. }
  1708. if(!this.enableFrictionReduction){
  1709. if(numContacts && this.enableFriction){
  1710. this.frictionEquations.push(this.createFrictionFromAverage(numContacts));
  1711. }
  1712. }
  1713. return numContacts;
  1714. };
  1715. Narrowphase.prototype[Shape.PARTICLE | Shape.CAPSULE] =
  1716. Narrowphase.prototype.particleCapsule = function(
  1717. particleBody,
  1718. particleShape,
  1719. particlePosition,
  1720. particleAngle,
  1721. capsuleBody,
  1722. capsuleShape,
  1723. capsulePosition,
  1724. capsuleAngle,
  1725. justTest
  1726. ){
  1727. return this.circleLine(particleBody,particleShape,particlePosition,particleAngle, capsuleBody,capsuleShape,capsulePosition,capsuleAngle, justTest, capsuleShape.radius, 0);
  1728. };
  1729. /**
  1730. * Circle/line Narrowphase
  1731. * @method circleLine
  1732. * @param {Body} circleBody
  1733. * @param {Circle} circleShape
  1734. * @param {Array} circleOffset
  1735. * @param {Number} circleAngle
  1736. * @param {Body} lineBody
  1737. * @param {Line} lineShape
  1738. * @param {Array} lineOffset
  1739. * @param {Number} lineAngle
  1740. * @param {Boolean} justTest If set to true, this function will return the result (intersection or not) without adding equations.
  1741. * @param {Number} lineRadius Radius to add to the line. Can be used to test Capsules.
  1742. * @param {Number} circleRadius If set, this value overrides the circle shape radius.
  1743. */
  1744. Narrowphase.prototype[Shape.CIRCLE | Shape.LINE] =
  1745. Narrowphase.prototype.circleLine = function(
  1746. circleBody,
  1747. circleShape,
  1748. circleOffset,
  1749. circleAngle,
  1750. lineBody,
  1751. lineShape,
  1752. lineOffset,
  1753. lineAngle,
  1754. justTest,
  1755. lineRadius,
  1756. circleRadius
  1757. ){
  1758. var lineRadius = lineRadius || 0,
  1759. circleRadius = typeof(circleRadius)!=="undefined" ? circleRadius : circleShape.radius,
  1760. orthoDist = tmp1,
  1761. lineToCircleOrthoUnit = tmp2,
  1762. projectedPoint = tmp3,
  1763. centerDist = tmp4,
  1764. worldTangent = tmp5,
  1765. worldEdge = tmp6,
  1766. worldEdgeUnit = tmp7,
  1767. worldVertex0 = tmp8,
  1768. worldVertex1 = tmp9,
  1769. worldVertex01 = tmp10,
  1770. worldVertex11 = tmp11,
  1771. dist = tmp12,
  1772. lineToCircle = tmp13,
  1773. lineEndToLineRadius = tmp14,
  1774. verts = tmpArray;
  1775. // Get start and end points
  1776. vec2.set(worldVertex0, -lineShape.length/2, 0);
  1777. vec2.set(worldVertex1, lineShape.length/2, 0);
  1778. // Not sure why we have to use worldVertex*1 here, but it won't work otherwise. Tired.
  1779. vec2.rotate(worldVertex01, worldVertex0, lineAngle);
  1780. vec2.rotate(worldVertex11, worldVertex1, lineAngle);
  1781. add(worldVertex01, worldVertex01, lineOffset);
  1782. add(worldVertex11, worldVertex11, lineOffset);
  1783. vec2.copy(worldVertex0,worldVertex01);
  1784. vec2.copy(worldVertex1,worldVertex11);
  1785. // Get vector along the line
  1786. sub(worldEdge, worldVertex1, worldVertex0);
  1787. vec2.normalize(worldEdgeUnit, worldEdge);
  1788. // Get tangent to the edge.
  1789. vec2.rotate90cw(worldTangent, worldEdgeUnit);
  1790. // Check distance from the plane spanned by the edge vs the circle
  1791. sub(dist, circleOffset, worldVertex0);
  1792. var d = dot(dist, worldTangent); // Distance from center of line to circle center
  1793. sub(centerDist, worldVertex0, lineOffset);
  1794. sub(lineToCircle, circleOffset, lineOffset);
  1795. var radiusSum = circleRadius + lineRadius;
  1796. if(Math.abs(d) < radiusSum){
  1797. // Now project the circle onto the edge
  1798. vec2.scale(orthoDist, worldTangent, d);
  1799. sub(projectedPoint, circleOffset, orthoDist);
  1800. // Add the missing line radius
  1801. vec2.scale(lineToCircleOrthoUnit, worldTangent, dot(worldTangent, lineToCircle));
  1802. vec2.normalize(lineToCircleOrthoUnit,lineToCircleOrthoUnit);
  1803. vec2.scale(lineToCircleOrthoUnit, lineToCircleOrthoUnit, lineRadius);
  1804. add(projectedPoint,projectedPoint,lineToCircleOrthoUnit);
  1805. // Check if the point is within the edge span
  1806. var pos = dot(worldEdgeUnit, projectedPoint);
  1807. var pos0 = dot(worldEdgeUnit, worldVertex0);
  1808. var pos1 = dot(worldEdgeUnit, worldVertex1);
  1809. if(pos > pos0 && pos < pos1){
  1810. // We got contact!
  1811. if(justTest){
  1812. return true;
  1813. }
  1814. var c = this.createContactEquation(circleBody,lineBody,circleShape,lineShape);
  1815. vec2.scale(c.normalA, orthoDist, -1);
  1816. vec2.normalize(c.normalA, c.normalA);
  1817. vec2.scale( c.contactPointA, c.normalA, circleRadius);
  1818. add(c.contactPointA, c.contactPointA, circleOffset);
  1819. sub(c.contactPointA, c.contactPointA, circleBody.position);
  1820. sub(c.contactPointB, projectedPoint, lineOffset);
  1821. add(c.contactPointB, c.contactPointB, lineOffset);
  1822. sub(c.contactPointB, c.contactPointB, lineBody.position);
  1823. this.contactEquations.push(c);
  1824. if(this.enableFriction){
  1825. this.frictionEquations.push(this.createFrictionFromContact(c));
  1826. }
  1827. return 1;
  1828. }
  1829. }
  1830. // Add corner
  1831. verts[0] = worldVertex0;
  1832. verts[1] = worldVertex1;
  1833. for(var i=0; i<verts.length; i++){
  1834. var v = verts[i];
  1835. sub(dist, v, circleOffset);
  1836. if(vec2.squaredLength(dist) < Math.pow(radiusSum, 2)){
  1837. if(justTest){
  1838. return true;
  1839. }
  1840. var c = this.createContactEquation(circleBody,lineBody,circleShape,lineShape);
  1841. vec2.copy(c.normalA, dist);
  1842. vec2.normalize(c.normalA,c.normalA);
  1843. // Vector from circle to contact point is the normal times the circle radius
  1844. vec2.scale(c.contactPointA, c.normalA, circleRadius);
  1845. add(c.contactPointA, c.contactPointA, circleOffset);
  1846. sub(c.contactPointA, c.contactPointA, circleBody.position);
  1847. sub(c.contactPointB, v, lineOffset);
  1848. vec2.scale(lineEndToLineRadius, c.normalA, -lineRadius);
  1849. add(c.contactPointB, c.contactPointB, lineEndToLineRadius);
  1850. add(c.contactPointB, c.contactPointB, lineOffset);
  1851. sub(c.contactPointB, c.contactPointB, lineBody.position);
  1852. this.contactEquations.push(c);
  1853. if(this.enableFriction){
  1854. this.frictionEquations.push(this.createFrictionFromContact(c));
  1855. }
  1856. return 1;
  1857. }
  1858. }
  1859. return 0;
  1860. };
  1861. /**
  1862. * Circle/capsule Narrowphase
  1863. * @method circleCapsule
  1864. * @param {Body} bi
  1865. * @param {Circle} si
  1866. * @param {Array} xi
  1867. * @param {Number} ai
  1868. * @param {Body} bj
  1869. * @param {Line} sj
  1870. * @param {Array} xj
  1871. * @param {Number} aj
  1872. */
  1873. Narrowphase.prototype[Shape.CIRCLE | Shape.CAPSULE] =
  1874. Narrowphase.prototype.circleCapsule = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1875. return this.circleLine(bi,si,xi,ai, bj,sj,xj,aj, justTest, sj.radius);
  1876. };
  1877. /**
  1878. * Circle/convex Narrowphase.
  1879. * @method circleConvex
  1880. * @param {Body} circleBody
  1881. * @param {Circle} circleShape
  1882. * @param {Array} circleOffset
  1883. * @param {Number} circleAngle
  1884. * @param {Body} convexBody
  1885. * @param {Convex} convexShape
  1886. * @param {Array} convexOffset
  1887. * @param {Number} convexAngle
  1888. * @param {Boolean} justTest
  1889. * @param {Number} circleRadius
  1890. */
  1891. Narrowphase.prototype[Shape.CIRCLE | Shape.CONVEX] =
  1892. Narrowphase.prototype[Shape.CIRCLE | Shape.BOX] =
  1893. Narrowphase.prototype.circleConvex = function(
  1894. circleBody,
  1895. circleShape,
  1896. circleOffset,
  1897. circleAngle,
  1898. convexBody,
  1899. convexShape,
  1900. convexOffset,
  1901. convexAngle,
  1902. justTest,
  1903. circleRadius
  1904. ){
  1905. var circleRadius = typeof(circleRadius)==="number" ? circleRadius : circleShape.radius;
  1906. var worldVertex0 = tmp1,
  1907. worldVertex1 = tmp2,
  1908. worldEdge = tmp3,
  1909. worldEdgeUnit = tmp4,
  1910. worldNormal = tmp5,
  1911. centerDist = tmp6,
  1912. convexToCircle = tmp7,
  1913. orthoDist = tmp8,
  1914. projectedPoint = tmp9,
  1915. dist = tmp10,
  1916. worldVertex = tmp11,
  1917. closestEdge = -1,
  1918. closestEdgeDistance = null,
  1919. closestEdgeOrthoDist = tmp12,
  1920. closestEdgeProjectedPoint = tmp13,
  1921. candidate = tmp14,
  1922. candidateDist = tmp15,
  1923. minCandidate = tmp16,
  1924. found = false,
  1925. minCandidateDistance = Number.MAX_VALUE;
  1926. var numReported = 0;
  1927. // New algorithm:
  1928. // 1. Check so center of circle is not inside the polygon. If it is, this wont work...
  1929. // 2. For each edge
  1930. // 2. 1. Get point on circle that is closest to the edge (scale normal with -radius)
  1931. // 2. 2. Check if point is inside.
  1932. var verts = convexShape.vertices;
  1933. // Check all edges first
  1934. for(var i=0; i!==verts.length+1; i++){
  1935. var v0 = verts[i%verts.length],
  1936. v1 = verts[(i+1)%verts.length];
  1937. vec2.rotate(worldVertex0, v0, convexAngle);
  1938. vec2.rotate(worldVertex1, v1, convexAngle);
  1939. add(worldVertex0, worldVertex0, convexOffset);
  1940. add(worldVertex1, worldVertex1, convexOffset);
  1941. sub(worldEdge, worldVertex1, worldVertex0);
  1942. vec2.normalize(worldEdgeUnit, worldEdge);
  1943. // Get tangent to the edge. Points out of the Convex
  1944. vec2.rotate90cw(worldNormal, worldEdgeUnit);
  1945. // Get point on circle, closest to the polygon
  1946. vec2.scale(candidate,worldNormal,-circleShape.radius);
  1947. add(candidate,candidate,circleOffset);
  1948. if(pointInConvex(candidate,convexShape,convexOffset,convexAngle)){
  1949. vec2.sub(candidateDist,worldVertex0,candidate);
  1950. var candidateDistance = Math.abs(vec2.dot(candidateDist,worldNormal));
  1951. if(candidateDistance < minCandidateDistance){
  1952. vec2.copy(minCandidate,candidate);
  1953. minCandidateDistance = candidateDistance;
  1954. vec2.scale(closestEdgeProjectedPoint,worldNormal,candidateDistance);
  1955. vec2.add(closestEdgeProjectedPoint,closestEdgeProjectedPoint,candidate);
  1956. found = true;
  1957. }
  1958. }
  1959. }
  1960. if(found){
  1961. if(justTest){
  1962. return true;
  1963. }
  1964. var c = this.createContactEquation(circleBody,convexBody,circleShape,convexShape);
  1965. vec2.sub(c.normalA, minCandidate, circleOffset);
  1966. vec2.normalize(c.normalA, c.normalA);
  1967. vec2.scale(c.contactPointA, c.normalA, circleRadius);
  1968. add(c.contactPointA, c.contactPointA, circleOffset);
  1969. sub(c.contactPointA, c.contactPointA, circleBody.position);
  1970. sub(c.contactPointB, closestEdgeProjectedPoint, convexOffset);
  1971. add(c.contactPointB, c.contactPointB, convexOffset);
  1972. sub(c.contactPointB, c.contactPointB, convexBody.position);
  1973. this.contactEquations.push(c);
  1974. if(this.enableFriction){
  1975. this.frictionEquations.push( this.createFrictionFromContact(c) );
  1976. }
  1977. return 1;
  1978. }
  1979. // Check all vertices
  1980. if(circleRadius > 0){
  1981. for(var i=0; i<verts.length; i++){
  1982. var localVertex = verts[i];
  1983. vec2.rotate(worldVertex, localVertex, convexAngle);
  1984. add(worldVertex, worldVertex, convexOffset);
  1985. sub(dist, worldVertex, circleOffset);
  1986. if(vec2.squaredLength(dist) < Math.pow(circleRadius, 2)){
  1987. if(justTest){
  1988. return true;
  1989. }
  1990. var c = this.createContactEquation(circleBody,convexBody,circleShape,convexShape);
  1991. vec2.copy(c.normalA, dist);
  1992. vec2.normalize(c.normalA,c.normalA);
  1993. // Vector from circle to contact point is the normal times the circle radius
  1994. vec2.scale(c.contactPointA, c.normalA, circleRadius);
  1995. add(c.contactPointA, c.contactPointA, circleOffset);
  1996. sub(c.contactPointA, c.contactPointA, circleBody.position);
  1997. sub(c.contactPointB, worldVertex, convexOffset);
  1998. add(c.contactPointB, c.contactPointB, convexOffset);
  1999. sub(c.contactPointB, c.contactPointB, convexBody.position);
  2000. this.contactEquations.push(c);
  2001. if(this.enableFriction){
  2002. this.frictionEquations.push(this.createFrictionFromContact(c));
  2003. }
  2004. return 1;
  2005. }
  2006. }
  2007. }
  2008. return 0;
  2009. };
  2010. var pic_worldVertex0 = vec2.create(),
  2011. pic_worldVertex1 = vec2.create(),
  2012. pic_r0 = vec2.create(),
  2013. pic_r1 = vec2.create();
  2014. /*
  2015. * Check if a point is in a polygon
  2016. */
  2017. function pointInConvex(worldPoint,convexShape,convexOffset,convexAngle){
  2018. var worldVertex0 = pic_worldVertex0,
  2019. worldVertex1 = pic_worldVertex1,
  2020. r0 = pic_r0,
  2021. r1 = pic_r1,
  2022. point = worldPoint,
  2023. verts = convexShape.vertices,
  2024. lastCross = null;
  2025. for(var i=0; i!==verts.length+1; i++){
  2026. var v0 = verts[i%verts.length],
  2027. v1 = verts[(i+1)%verts.length];
  2028. // Transform vertices to world
  2029. // @todo The point should be transformed to local coordinates in the convex, no need to transform each vertex
  2030. vec2.rotate(worldVertex0, v0, convexAngle);
  2031. vec2.rotate(worldVertex1, v1, convexAngle);
  2032. add(worldVertex0, worldVertex0, convexOffset);
  2033. add(worldVertex1, worldVertex1, convexOffset);
  2034. sub(r0, worldVertex0, point);
  2035. sub(r1, worldVertex1, point);
  2036. var cross = vec2.crossLength(r0,r1);
  2037. if(lastCross===null){
  2038. lastCross = cross;
  2039. }
  2040. // If we got a different sign of the distance vector, the point is out of the polygon
  2041. if(cross*lastCross <= 0){
  2042. return false;
  2043. }
  2044. lastCross = cross;
  2045. }
  2046. return true;
  2047. }
  2048. /**
  2049. * Particle/convex Narrowphase
  2050. * @method particleConvex
  2051. * @param {Body} particleBody
  2052. * @param {Particle} particleShape
  2053. * @param {Array} particleOffset
  2054. * @param {Number} particleAngle
  2055. * @param {Body} convexBody
  2056. * @param {Convex} convexShape
  2057. * @param {Array} convexOffset
  2058. * @param {Number} convexAngle
  2059. * @param {Boolean} justTest
  2060. * @todo use pointInConvex and code more similar to circleConvex
  2061. * @todo don't transform each vertex, but transform the particle position to convex-local instead
  2062. */
  2063. Narrowphase.prototype[Shape.PARTICLE | Shape.CONVEX] =
  2064. Narrowphase.prototype[Shape.PARTICLE | Shape.BOX] =
  2065. Narrowphase.prototype.particleConvex = function(
  2066. particleBody,
  2067. particleShape,
  2068. particleOffset,
  2069. particleAngle,
  2070. convexBody,
  2071. convexShape,
  2072. convexOffset,
  2073. convexAngle,
  2074. justTest
  2075. ){
  2076. var worldVertex0 = tmp1,
  2077. worldVertex1 = tmp2,
  2078. worldEdge = tmp3,
  2079. worldEdgeUnit = tmp4,
  2080. worldTangent = tmp5,
  2081. centerDist = tmp6,
  2082. convexToparticle = tmp7,
  2083. orthoDist = tmp8,
  2084. projectedPoint = tmp9,
  2085. dist = tmp10,
  2086. worldVertex = tmp11,
  2087. closestEdge = -1,
  2088. closestEdgeDistance = null,
  2089. closestEdgeOrthoDist = tmp12,
  2090. closestEdgeProjectedPoint = tmp13,
  2091. r0 = tmp14, // vector from particle to vertex0
  2092. r1 = tmp15,
  2093. localPoint = tmp16,
  2094. candidateDist = tmp17,
  2095. minEdgeNormal = tmp18,
  2096. minCandidateDistance = Number.MAX_VALUE;
  2097. var numReported = 0,
  2098. found = false,
  2099. verts = convexShape.vertices;
  2100. // Check if the particle is in the polygon at all
  2101. if(!pointInConvex(particleOffset,convexShape,convexOffset,convexAngle)){
  2102. return 0;
  2103. }
  2104. if(justTest){
  2105. return true;
  2106. }
  2107. // Check edges first
  2108. var lastCross = null;
  2109. for(var i=0; i!==verts.length+1; i++){
  2110. var v0 = verts[i%verts.length],
  2111. v1 = verts[(i+1)%verts.length];
  2112. // Transform vertices to world
  2113. vec2.rotate(worldVertex0, v0, convexAngle);
  2114. vec2.rotate(worldVertex1, v1, convexAngle);
  2115. add(worldVertex0, worldVertex0, convexOffset);
  2116. add(worldVertex1, worldVertex1, convexOffset);
  2117. // Get world edge
  2118. sub(worldEdge, worldVertex1, worldVertex0);
  2119. vec2.normalize(worldEdgeUnit, worldEdge);
  2120. // Get tangent to the edge. Points out of the Convex
  2121. vec2.rotate90cw(worldTangent, worldEdgeUnit);
  2122. // Check distance from the infinite line (spanned by the edge) to the particle
  2123. sub(dist, particleOffset, worldVertex0);
  2124. var d = dot(dist, worldTangent);
  2125. sub(centerDist, worldVertex0, convexOffset);
  2126. sub(convexToparticle, particleOffset, convexOffset);
  2127. vec2.sub(candidateDist,worldVertex0,particleOffset);
  2128. var candidateDistance = Math.abs(vec2.dot(candidateDist,worldTangent));
  2129. if(candidateDistance < minCandidateDistance){
  2130. minCandidateDistance = candidateDistance;
  2131. vec2.scale(closestEdgeProjectedPoint,worldTangent,candidateDistance);
  2132. vec2.add(closestEdgeProjectedPoint,closestEdgeProjectedPoint,particleOffset);
  2133. vec2.copy(minEdgeNormal,worldTangent);
  2134. found = true;
  2135. }
  2136. }
  2137. if(found){
  2138. var c = this.createContactEquation(particleBody,convexBody,particleShape,convexShape);
  2139. vec2.scale(c.normalA, minEdgeNormal, -1);
  2140. vec2.normalize(c.normalA, c.normalA);
  2141. // Particle has no extent to the contact point
  2142. vec2.set(c.contactPointA, 0, 0);
  2143. add(c.contactPointA, c.contactPointA, particleOffset);
  2144. sub(c.contactPointA, c.contactPointA, particleBody.position);
  2145. // From convex center to point
  2146. sub(c.contactPointB, closestEdgeProjectedPoint, convexOffset);
  2147. add(c.contactPointB, c.contactPointB, convexOffset);
  2148. sub(c.contactPointB, c.contactPointB, convexBody.position);
  2149. this.contactEquations.push(c);
  2150. if(this.enableFriction){
  2151. this.frictionEquations.push( this.createFrictionFromContact(c) );
  2152. }
  2153. return 1;
  2154. }
  2155. return 0;
  2156. };
  2157. /**
  2158. * Circle/circle Narrowphase
  2159. * @method circleCircle
  2160. * @param {Body} bodyA
  2161. * @param {Circle} shapeA
  2162. * @param {Array} offsetA
  2163. * @param {Number} angleA
  2164. * @param {Body} bodyB
  2165. * @param {Circle} shapeB
  2166. * @param {Array} offsetB
  2167. * @param {Number} angleB
  2168. * @param {Boolean} justTest
  2169. * @param {Number} [radiusA] Optional radius to use for shapeA
  2170. * @param {Number} [radiusB] Optional radius to use for shapeB
  2171. */
  2172. Narrowphase.prototype[Shape.CIRCLE] =
  2173. Narrowphase.prototype.circleCircle = function(
  2174. bodyA,
  2175. shapeA,
  2176. offsetA,
  2177. angleA,
  2178. bodyB,
  2179. shapeB,
  2180. offsetB,
  2181. angleB,
  2182. justTest,
  2183. radiusA,
  2184. radiusB
  2185. ){
  2186. var dist = tmp1,
  2187. radiusA = radiusA || shapeA.radius,
  2188. radiusB = radiusB || shapeB.radius;
  2189. sub(dist,offsetA,offsetB);
  2190. var r = radiusA + radiusB;
  2191. if(vec2.squaredLength(dist) > Math.pow(r,2)){
  2192. return 0;
  2193. }
  2194. if(justTest){
  2195. return true;
  2196. }
  2197. var c = this.createContactEquation(bodyA,bodyB,shapeA,shapeB);
  2198. sub(c.normalA, offsetB, offsetA);
  2199. vec2.normalize(c.normalA,c.normalA);
  2200. vec2.scale( c.contactPointA, c.normalA, radiusA);
  2201. vec2.scale( c.contactPointB, c.normalA, -radiusB);
  2202. add(c.contactPointA, c.contactPointA, offsetA);
  2203. sub(c.contactPointA, c.contactPointA, bodyA.position);
  2204. add(c.contactPointB, c.contactPointB, offsetB);
  2205. sub(c.contactPointB, c.contactPointB, bodyB.position);
  2206. this.contactEquations.push(c);
  2207. if(this.enableFriction){
  2208. this.frictionEquations.push(this.createFrictionFromContact(c));
  2209. }
  2210. return 1;
  2211. };
  2212. /**
  2213. * Plane/Convex Narrowphase
  2214. * @method planeConvex
  2215. * @param {Body} planeBody
  2216. * @param {Plane} planeShape
  2217. * @param {Array} planeOffset
  2218. * @param {Number} planeAngle
  2219. * @param {Body} convexBody
  2220. * @param {Convex} convexShape
  2221. * @param {Array} convexOffset
  2222. * @param {Number} convexAngle
  2223. * @param {Boolean} justTest
  2224. */
  2225. Narrowphase.prototype[Shape.PLANE | Shape.CONVEX] =
  2226. Narrowphase.prototype[Shape.PLANE | Shape.BOX] =
  2227. Narrowphase.prototype.planeConvex = function(
  2228. planeBody,
  2229. planeShape,
  2230. planeOffset,
  2231. planeAngle,
  2232. convexBody,
  2233. convexShape,
  2234. convexOffset,
  2235. convexAngle,
  2236. justTest
  2237. ){
  2238. var worldVertex = tmp1,
  2239. worldNormal = tmp2,
  2240. dist = tmp3;
  2241. var numReported = 0;
  2242. vec2.rotate(worldNormal, yAxis, planeAngle);
  2243. for(var i=0; i!==convexShape.vertices.length; i++){
  2244. var v = convexShape.vertices[i];
  2245. vec2.rotate(worldVertex, v, convexAngle);
  2246. add(worldVertex, worldVertex, convexOffset);
  2247. sub(dist, worldVertex, planeOffset);
  2248. if(dot(dist,worldNormal) <= 0){
  2249. if(justTest){
  2250. return true;
  2251. }
  2252. // Found vertex
  2253. numReported++;
  2254. var c = this.createContactEquation(planeBody,convexBody,planeShape,convexShape);
  2255. sub(dist, worldVertex, planeOffset);
  2256. vec2.copy(c.normalA, worldNormal);
  2257. var d = dot(dist, c.normalA);
  2258. vec2.scale(dist, c.normalA, d);
  2259. // rj is from convex center to contact
  2260. sub(c.contactPointB, worldVertex, convexBody.position);
  2261. // ri is from plane center to contact
  2262. sub( c.contactPointA, worldVertex, dist);
  2263. sub( c.contactPointA, c.contactPointA, planeBody.position);
  2264. this.contactEquations.push(c);
  2265. if(!this.enableFrictionReduction){
  2266. if(this.enableFriction){
  2267. this.frictionEquations.push(this.createFrictionFromContact(c));
  2268. }
  2269. }
  2270. }
  2271. }
  2272. if(this.enableFrictionReduction){
  2273. if(this.enableFriction && numReported){
  2274. this.frictionEquations.push(this.createFrictionFromAverage(numReported));
  2275. }
  2276. }
  2277. return numReported;
  2278. };
  2279. /**
  2280. * Narrowphase for particle vs plane
  2281. * @method particlePlane
  2282. * @param {Body} particleBody
  2283. * @param {Particle} particleShape
  2284. * @param {Array} particleOffset
  2285. * @param {Number} particleAngle
  2286. * @param {Body} planeBody
  2287. * @param {Plane} planeShape
  2288. * @param {Array} planeOffset
  2289. * @param {Number} planeAngle
  2290. * @param {Boolean} justTest
  2291. */
  2292. Narrowphase.prototype[Shape.PARTICLE | Shape.PLANE] =
  2293. Narrowphase.prototype.particlePlane = function(
  2294. particleBody,
  2295. particleShape,
  2296. particleOffset,
  2297. particleAngle,
  2298. planeBody,
  2299. planeShape,
  2300. planeOffset,
  2301. planeAngle,
  2302. justTest
  2303. ){
  2304. var dist = tmp1,
  2305. worldNormal = tmp2;
  2306. planeAngle = planeAngle || 0;
  2307. sub(dist, particleOffset, planeOffset);
  2308. vec2.rotate(worldNormal, yAxis, planeAngle);
  2309. var d = dot(dist, worldNormal);
  2310. if(d > 0){
  2311. return 0;
  2312. }
  2313. if(justTest){
  2314. return true;
  2315. }
  2316. var c = this.createContactEquation(planeBody,particleBody,planeShape,particleShape);
  2317. vec2.copy(c.normalA, worldNormal);
  2318. vec2.scale( dist, c.normalA, d );
  2319. // dist is now the distance vector in the normal direction
  2320. // ri is the particle position projected down onto the plane, from the plane center
  2321. sub( c.contactPointA, particleOffset, dist);
  2322. sub( c.contactPointA, c.contactPointA, planeBody.position);
  2323. // rj is from the body center to the particle center
  2324. sub( c.contactPointB, particleOffset, particleBody.position );
  2325. this.contactEquations.push(c);
  2326. if(this.enableFriction){
  2327. this.frictionEquations.push(this.createFrictionFromContact(c));
  2328. }
  2329. return 1;
  2330. };
  2331. /**
  2332. * Circle/Particle Narrowphase
  2333. * @method circleParticle
  2334. * @param {Body} circleBody
  2335. * @param {Circle} circleShape
  2336. * @param {Array} circleOffset
  2337. * @param {Number} circleAngle
  2338. * @param {Body} particleBody
  2339. * @param {Particle} particleShape
  2340. * @param {Array} particleOffset
  2341. * @param {Number} particleAngle
  2342. * @param {Boolean} justTest
  2343. */
  2344. Narrowphase.prototype[Shape.CIRCLE | Shape.PARTICLE] =
  2345. Narrowphase.prototype.circleParticle = function(
  2346. circleBody,
  2347. circleShape,
  2348. circleOffset,
  2349. circleAngle,
  2350. particleBody,
  2351. particleShape,
  2352. particleOffset,
  2353. particleAngle,
  2354. justTest
  2355. ){
  2356. var dist = tmp1;
  2357. sub(dist, particleOffset, circleOffset);
  2358. if(vec2.squaredLength(dist) > Math.pow(circleShape.radius, 2)){
  2359. return 0;
  2360. }
  2361. if(justTest){
  2362. return true;
  2363. }
  2364. var c = this.createContactEquation(circleBody,particleBody,circleShape,particleShape);
  2365. vec2.copy(c.normalA, dist);
  2366. vec2.normalize(c.normalA,c.normalA);
  2367. // Vector from circle to contact point is the normal times the circle radius
  2368. vec2.scale(c.contactPointA, c.normalA, circleShape.radius);
  2369. add(c.contactPointA, c.contactPointA, circleOffset);
  2370. sub(c.contactPointA, c.contactPointA, circleBody.position);
  2371. // Vector from particle center to contact point is zero
  2372. sub(c.contactPointB, particleOffset, particleBody.position);
  2373. this.contactEquations.push(c);
  2374. if(this.enableFriction){
  2375. this.frictionEquations.push(this.createFrictionFromContact(c));
  2376. }
  2377. return 1;
  2378. };
  2379. var planeCapsule_tmpCircle = new Circle({ radius: 1 }),
  2380. planeCapsule_tmp1 = vec2.create(),
  2381. planeCapsule_tmp2 = vec2.create(),
  2382. planeCapsule_tmp3 = vec2.create();
  2383. /**
  2384. * @method planeCapsule
  2385. * @param {Body} planeBody
  2386. * @param {Circle} planeShape
  2387. * @param {Array} planeOffset
  2388. * @param {Number} planeAngle
  2389. * @param {Body} capsuleBody
  2390. * @param {Particle} capsuleShape
  2391. * @param {Array} capsuleOffset
  2392. * @param {Number} capsuleAngle
  2393. * @param {Boolean} justTest
  2394. */
  2395. Narrowphase.prototype[Shape.PLANE | Shape.CAPSULE] =
  2396. Narrowphase.prototype.planeCapsule = function(
  2397. planeBody,
  2398. planeShape,
  2399. planeOffset,
  2400. planeAngle,
  2401. capsuleBody,
  2402. capsuleShape,
  2403. capsuleOffset,
  2404. capsuleAngle,
  2405. justTest
  2406. ){
  2407. var end1 = planeCapsule_tmp1,
  2408. end2 = planeCapsule_tmp2,
  2409. circle = planeCapsule_tmpCircle,
  2410. dst = planeCapsule_tmp3;
  2411. // Compute world end positions
  2412. vec2.set(end1, -capsuleShape.length/2, 0);
  2413. vec2.rotate(end1,end1,capsuleAngle);
  2414. add(end1,end1,capsuleOffset);
  2415. vec2.set(end2, capsuleShape.length/2, 0);
  2416. vec2.rotate(end2,end2,capsuleAngle);
  2417. add(end2,end2,capsuleOffset);
  2418. circle.radius = capsuleShape.radius;
  2419. var enableFrictionBefore;
  2420. // Temporarily turn off friction
  2421. if(this.enableFrictionReduction){
  2422. enableFrictionBefore = this.enableFriction;
  2423. this.enableFriction = false;
  2424. }
  2425. // Do Narrowphase as two circles
  2426. var numContacts1 = this.circlePlane(capsuleBody,circle,end1,0, planeBody,planeShape,planeOffset,planeAngle, justTest),
  2427. numContacts2 = this.circlePlane(capsuleBody,circle,end2,0, planeBody,planeShape,planeOffset,planeAngle, justTest);
  2428. // Restore friction
  2429. if(this.enableFrictionReduction){
  2430. this.enableFriction = enableFrictionBefore;
  2431. }
  2432. if(justTest){
  2433. return numContacts1 || numContacts2;
  2434. } else {
  2435. var numTotal = numContacts1 + numContacts2;
  2436. if(this.enableFrictionReduction){
  2437. if(numTotal){
  2438. this.frictionEquations.push(this.createFrictionFromAverage(numTotal));
  2439. }
  2440. }
  2441. return numTotal;
  2442. }
  2443. };
  2444. /**
  2445. * Creates ContactEquations and FrictionEquations for a collision.
  2446. * @method circlePlane
  2447. * @param {Body} bi The first body that should be connected to the equations.
  2448. * @param {Circle} si The circle shape participating in the collision.
  2449. * @param {Array} xi Extra offset to take into account for the Shape, in addition to the one in circleBody.position. Will *not* be rotated by circleBody.angle (maybe it should, for sake of homogenity?). Set to null if none.
  2450. * @param {Body} bj The second body that should be connected to the equations.
  2451. * @param {Plane} sj The Plane shape that is participating
  2452. * @param {Array} xj Extra offset for the plane shape.
  2453. * @param {Number} aj Extra angle to apply to the plane
  2454. */
  2455. Narrowphase.prototype[Shape.CIRCLE | Shape.PLANE] =
  2456. Narrowphase.prototype.circlePlane = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2457. var circleBody = bi,
  2458. circleShape = si,
  2459. circleOffset = xi, // Offset from body center, rotated!
  2460. planeBody = bj,
  2461. shapeB = sj,
  2462. planeOffset = xj,
  2463. planeAngle = aj;
  2464. planeAngle = planeAngle || 0;
  2465. // Vector from plane to circle
  2466. var planeToCircle = tmp1,
  2467. worldNormal = tmp2,
  2468. temp = tmp3;
  2469. sub(planeToCircle, circleOffset, planeOffset);
  2470. // World plane normal
  2471. vec2.rotate(worldNormal, yAxis, planeAngle);
  2472. // Normal direction distance
  2473. var d = dot(worldNormal, planeToCircle);
  2474. if(d > circleShape.radius){
  2475. return 0; // No overlap. Abort.
  2476. }
  2477. if(justTest){
  2478. return true;
  2479. }
  2480. // Create contact
  2481. var contact = this.createContactEquation(planeBody,circleBody,sj,si);
  2482. // ni is the plane world normal
  2483. vec2.copy(contact.normalA, worldNormal);
  2484. // rj is the vector from circle center to the contact point
  2485. vec2.scale(contact.contactPointB, contact.normalA, -circleShape.radius);
  2486. add(contact.contactPointB, contact.contactPointB, circleOffset);
  2487. sub(contact.contactPointB, contact.contactPointB, circleBody.position);
  2488. // ri is the distance from plane center to contact.
  2489. vec2.scale(temp, contact.normalA, d);
  2490. sub(contact.contactPointA, planeToCircle, temp ); // Subtract normal distance vector from the distance vector
  2491. add(contact.contactPointA, contact.contactPointA, planeOffset);
  2492. sub(contact.contactPointA, contact.contactPointA, planeBody.position);
  2493. this.contactEquations.push(contact);
  2494. if(this.enableFriction){
  2495. this.frictionEquations.push( this.createFrictionFromContact(contact) );
  2496. }
  2497. return 1;
  2498. };
  2499. /**
  2500. * Convex/convex Narrowphase.See <a href="http://www.altdevblogaday.com/2011/05/13/contact-generation-between-3d-convex-meshes/">this article</a> for more info.
  2501. * @method convexConvex
  2502. * @param {Body} bi
  2503. * @param {Convex} si
  2504. * @param {Array} xi
  2505. * @param {Number} ai
  2506. * @param {Body} bj
  2507. * @param {Convex} sj
  2508. * @param {Array} xj
  2509. * @param {Number} aj
  2510. */
  2511. Narrowphase.prototype[Shape.CONVEX] =
  2512. Narrowphase.prototype[Shape.CONVEX | Shape.BOX] =
  2513. Narrowphase.prototype[Shape.BOX] =
  2514. Narrowphase.prototype.convexConvex = function( bi,si,xi,ai, bj,sj,xj,aj, justTest, precision ){
  2515. var sepAxis = tmp1,
  2516. worldPoint = tmp2,
  2517. worldPoint0 = tmp3,
  2518. worldPoint1 = tmp4,
  2519. worldEdge = tmp5,
  2520. projected = tmp6,
  2521. penetrationVec = tmp7,
  2522. dist = tmp8,
  2523. worldNormal = tmp9,
  2524. numContacts = 0,
  2525. precision = typeof(precision) === 'number' ? precision : 0;
  2526. var found = Narrowphase.findSeparatingAxis(si,xi,ai,sj,xj,aj,sepAxis);
  2527. if(!found){
  2528. return 0;
  2529. }
  2530. // Make sure the separating axis is directed from shape i to shape j
  2531. sub(dist,xj,xi);
  2532. if(dot(sepAxis,dist) > 0){
  2533. vec2.scale(sepAxis,sepAxis,-1);
  2534. }
  2535. // Find edges with normals closest to the separating axis
  2536. var closestEdge1 = Narrowphase.getClosestEdge(si,ai,sepAxis,true), // Flipped axis
  2537. closestEdge2 = Narrowphase.getClosestEdge(sj,aj,sepAxis);
  2538. if(closestEdge1 === -1 || closestEdge2 === -1){
  2539. return 0;
  2540. }
  2541. // Loop over the shapes
  2542. for(var k=0; k<2; k++){
  2543. var closestEdgeA = closestEdge1,
  2544. closestEdgeB = closestEdge2,
  2545. shapeA = si, shapeB = sj,
  2546. offsetA = xi, offsetB = xj,
  2547. angleA = ai, angleB = aj,
  2548. bodyA = bi, bodyB = bj;
  2549. if(k === 0){
  2550. // Swap!
  2551. var tmp;
  2552. tmp = closestEdgeA;
  2553. closestEdgeA = closestEdgeB;
  2554. closestEdgeB = tmp;
  2555. tmp = shapeA;
  2556. shapeA = shapeB;
  2557. shapeB = tmp;
  2558. tmp = offsetA;
  2559. offsetA = offsetB;
  2560. offsetB = tmp;
  2561. tmp = angleA;
  2562. angleA = angleB;
  2563. angleB = tmp;
  2564. tmp = bodyA;
  2565. bodyA = bodyB;
  2566. bodyB = tmp;
  2567. }
  2568. // Loop over 2 points in convex B
  2569. for(var j=closestEdgeB; j<closestEdgeB+2; j++){
  2570. // Get world point
  2571. var v = shapeB.vertices[(j+shapeB.vertices.length)%shapeB.vertices.length];
  2572. vec2.rotate(worldPoint, v, angleB);
  2573. add(worldPoint, worldPoint, offsetB);
  2574. var insideNumEdges = 0;
  2575. // Loop over the 3 closest edges in convex A
  2576. for(var i=closestEdgeA-1; i<closestEdgeA+2; i++){
  2577. var v0 = shapeA.vertices[(i +shapeA.vertices.length)%shapeA.vertices.length],
  2578. v1 = shapeA.vertices[(i+1+shapeA.vertices.length)%shapeA.vertices.length];
  2579. // Construct the edge
  2580. vec2.rotate(worldPoint0, v0, angleA);
  2581. vec2.rotate(worldPoint1, v1, angleA);
  2582. add(worldPoint0, worldPoint0, offsetA);
  2583. add(worldPoint1, worldPoint1, offsetA);
  2584. sub(worldEdge, worldPoint1, worldPoint0);
  2585. vec2.rotate90cw(worldNormal, worldEdge); // Normal points out of convex 1
  2586. vec2.normalize(worldNormal,worldNormal);
  2587. sub(dist, worldPoint, worldPoint0);
  2588. var d = dot(worldNormal,dist);
  2589. if((i === closestEdgeA && d <= precision) || (i !== closestEdgeA && d <= 0)){
  2590. insideNumEdges++;
  2591. }
  2592. }
  2593. if(insideNumEdges >= 3){
  2594. if(justTest){
  2595. return true;
  2596. }
  2597. // worldPoint was on the "inside" side of each of the 3 checked edges.
  2598. // Project it to the center edge and use the projection direction as normal
  2599. // Create contact
  2600. var c = this.createContactEquation(bodyA,bodyB,shapeA,shapeB);
  2601. numContacts++;
  2602. // Get center edge from body A
  2603. var v0 = shapeA.vertices[(closestEdgeA) % shapeA.vertices.length],
  2604. v1 = shapeA.vertices[(closestEdgeA+1) % shapeA.vertices.length];
  2605. // Construct the edge
  2606. vec2.rotate(worldPoint0, v0, angleA);
  2607. vec2.rotate(worldPoint1, v1, angleA);
  2608. add(worldPoint0, worldPoint0, offsetA);
  2609. add(worldPoint1, worldPoint1, offsetA);
  2610. sub(worldEdge, worldPoint1, worldPoint0);
  2611. vec2.rotate90cw(c.normalA, worldEdge); // Normal points out of convex A
  2612. vec2.normalize(c.normalA,c.normalA);
  2613. sub(dist, worldPoint, worldPoint0); // From edge point to the penetrating point
  2614. var d = dot(c.normalA,dist); // Penetration
  2615. vec2.scale(penetrationVec, c.normalA, d); // Vector penetration
  2616. sub(c.contactPointA, worldPoint, offsetA);
  2617. sub(c.contactPointA, c.contactPointA, penetrationVec);
  2618. add(c.contactPointA, c.contactPointA, offsetA);
  2619. sub(c.contactPointA, c.contactPointA, bodyA.position);
  2620. sub(c.contactPointB, worldPoint, offsetB);
  2621. add(c.contactPointB, c.contactPointB, offsetB);
  2622. sub(c.contactPointB, c.contactPointB, bodyB.position);
  2623. this.contactEquations.push(c);
  2624. // Todo reduce to 1 friction equation if we have 2 contact points
  2625. if(!this.enableFrictionReduction){
  2626. if(this.enableFriction){
  2627. this.frictionEquations.push(this.createFrictionFromContact(c));
  2628. }
  2629. }
  2630. }
  2631. }
  2632. }
  2633. if(this.enableFrictionReduction){
  2634. if(this.enableFriction && numContacts){
  2635. this.frictionEquations.push(this.createFrictionFromAverage(numContacts));
  2636. }
  2637. }
  2638. return numContacts;
  2639. };
  2640. // .projectConvex is called by other functions, need local tmp vectors
  2641. var pcoa_tmp1 = vec2.fromValues(0,0);
  2642. /**
  2643. * Project a Convex onto a world-oriented axis
  2644. * @method projectConvexOntoAxis
  2645. * @static
  2646. * @param {Convex} convexShape
  2647. * @param {Array} convexOffset
  2648. * @param {Number} convexAngle
  2649. * @param {Array} worldAxis
  2650. * @param {Array} result
  2651. */
  2652. Narrowphase.projectConvexOntoAxis = function(convexShape, convexOffset, convexAngle, worldAxis, result){
  2653. var max=null,
  2654. min=null,
  2655. v,
  2656. value,
  2657. localAxis = pcoa_tmp1;
  2658. // Convert the axis to local coords of the body
  2659. vec2.rotate(localAxis, worldAxis, -convexAngle);
  2660. // Get projected position of all vertices
  2661. for(var i=0; i<convexShape.vertices.length; i++){
  2662. v = convexShape.vertices[i];
  2663. value = dot(v,localAxis);
  2664. if(max === null || value > max){
  2665. max = value;
  2666. }
  2667. if(min === null || value < min){
  2668. min = value;
  2669. }
  2670. }
  2671. if(min > max){
  2672. var t = min;
  2673. min = max;
  2674. max = t;
  2675. }
  2676. // Project the position of the body onto the axis - need to add this to the result
  2677. var offset = dot(convexOffset, worldAxis);
  2678. vec2.set( result, min + offset, max + offset);
  2679. };
  2680. // .findSeparatingAxis is called by other functions, need local tmp vectors
  2681. var fsa_tmp1 = vec2.fromValues(0,0)
  2682. , fsa_tmp2 = vec2.fromValues(0,0)
  2683. , fsa_tmp3 = vec2.fromValues(0,0)
  2684. , fsa_tmp4 = vec2.fromValues(0,0)
  2685. , fsa_tmp5 = vec2.fromValues(0,0)
  2686. , fsa_tmp6 = vec2.fromValues(0,0);
  2687. /**
  2688. * Find a separating axis between the shapes, that maximizes the separating distance between them.
  2689. * @method findSeparatingAxis
  2690. * @static
  2691. * @param {Convex} c1
  2692. * @param {Array} offset1
  2693. * @param {Number} angle1
  2694. * @param {Convex} c2
  2695. * @param {Array} offset2
  2696. * @param {Number} angle2
  2697. * @param {Array} sepAxis The resulting axis
  2698. * @return {Boolean} Whether the axis could be found.
  2699. */
  2700. Narrowphase.findSeparatingAxis = function(c1,offset1,angle1,c2,offset2,angle2,sepAxis){
  2701. var maxDist = null,
  2702. overlap = false,
  2703. found = false,
  2704. edge = fsa_tmp1,
  2705. worldPoint0 = fsa_tmp2,
  2706. worldPoint1 = fsa_tmp3,
  2707. normal = fsa_tmp4,
  2708. span1 = fsa_tmp5,
  2709. span2 = fsa_tmp6;
  2710. if(c1 instanceof Box && c2 instanceof Box){
  2711. for(var j=0; j!==2; j++){
  2712. var c = c1,
  2713. angle = angle1;
  2714. if(j===1){
  2715. c = c2;
  2716. angle = angle2;
  2717. }
  2718. for(var i=0; i!==2; i++){
  2719. // Get the world edge
  2720. if(i === 0){
  2721. vec2.set(normal, 0, 1);
  2722. } else if(i === 1) {
  2723. vec2.set(normal, 1, 0);
  2724. }
  2725. if(angle !== 0){
  2726. vec2.rotate(normal, normal, angle);
  2727. }
  2728. // Project hulls onto that normal
  2729. Narrowphase.projectConvexOntoAxis(c1,offset1,angle1,normal,span1);
  2730. Narrowphase.projectConvexOntoAxis(c2,offset2,angle2,normal,span2);
  2731. // Order by span position
  2732. var a=span1,
  2733. b=span2,
  2734. swapped = false;
  2735. if(span1[0] > span2[0]){
  2736. b=span1;
  2737. a=span2;
  2738. swapped = true;
  2739. }
  2740. // Get separating distance
  2741. var dist = b[0] - a[1];
  2742. overlap = (dist <= 0);
  2743. if(maxDist===null || dist > maxDist){
  2744. vec2.copy(sepAxis, normal);
  2745. maxDist = dist;
  2746. found = overlap;
  2747. }
  2748. }
  2749. }
  2750. } else {
  2751. for(var j=0; j!==2; j++){
  2752. var c = c1,
  2753. angle = angle1;
  2754. if(j===1){
  2755. c = c2;
  2756. angle = angle2;
  2757. }
  2758. for(var i=0; i!==c.vertices.length; i++){
  2759. // Get the world edge
  2760. vec2.rotate(worldPoint0, c.vertices[i], angle);
  2761. vec2.rotate(worldPoint1, c.vertices[(i+1)%c.vertices.length], angle);
  2762. sub(edge, worldPoint1, worldPoint0);
  2763. // Get normal - just rotate 90 degrees since vertices are given in CCW
  2764. vec2.rotate90cw(normal, edge);
  2765. vec2.normalize(normal,normal);
  2766. // Project hulls onto that normal
  2767. Narrowphase.projectConvexOntoAxis(c1,offset1,angle1,normal,span1);
  2768. Narrowphase.projectConvexOntoAxis(c2,offset2,angle2,normal,span2);
  2769. // Order by span position
  2770. var a=span1,
  2771. b=span2,
  2772. swapped = false;
  2773. if(span1[0] > span2[0]){
  2774. b=span1;
  2775. a=span2;
  2776. swapped = true;
  2777. }
  2778. // Get separating distance
  2779. var dist = b[0] - a[1];
  2780. overlap = (dist <= 0);
  2781. if(maxDist===null || dist > maxDist){
  2782. vec2.copy(sepAxis, normal);
  2783. maxDist = dist;
  2784. found = overlap;
  2785. }
  2786. }
  2787. }
  2788. }
  2789. /*
  2790. // Needs to be tested some more
  2791. for(var j=0; j!==2; j++){
  2792. var c = c1,
  2793. angle = angle1;
  2794. if(j===1){
  2795. c = c2;
  2796. angle = angle2;
  2797. }
  2798. for(var i=0; i!==c.axes.length; i++){
  2799. var normal = c.axes[i];
  2800. // Project hulls onto that normal
  2801. Narrowphase.projectConvexOntoAxis(c1, offset1, angle1, normal, span1);
  2802. Narrowphase.projectConvexOntoAxis(c2, offset2, angle2, normal, span2);
  2803. // Order by span position
  2804. var a=span1,
  2805. b=span2,
  2806. swapped = false;
  2807. if(span1[0] > span2[0]){
  2808. b=span1;
  2809. a=span2;
  2810. swapped = true;
  2811. }
  2812. // Get separating distance
  2813. var dist = b[0] - a[1];
  2814. overlap = (dist <= Narrowphase.convexPrecision);
  2815. if(maxDist===null || dist > maxDist){
  2816. vec2.copy(sepAxis, normal);
  2817. maxDist = dist;
  2818. found = overlap;
  2819. }
  2820. }
  2821. }
  2822. */
  2823. return found;
  2824. };
  2825. // .getClosestEdge is called by other functions, need local tmp vectors
  2826. var gce_tmp1 = vec2.fromValues(0,0)
  2827. , gce_tmp2 = vec2.fromValues(0,0)
  2828. , gce_tmp3 = vec2.fromValues(0,0);
  2829. /**
  2830. * Get the edge that has a normal closest to an axis.
  2831. * @method getClosestEdge
  2832. * @static
  2833. * @param {Convex} c
  2834. * @param {Number} angle
  2835. * @param {Array} axis
  2836. * @param {Boolean} flip
  2837. * @return {Number} Index of the edge that is closest. This index and the next spans the resulting edge. Returns -1 if failed.
  2838. */
  2839. Narrowphase.getClosestEdge = function(c,angle,axis,flip){
  2840. var localAxis = gce_tmp1,
  2841. edge = gce_tmp2,
  2842. normal = gce_tmp3;
  2843. // Convert the axis to local coords of the body
  2844. vec2.rotate(localAxis, axis, -angle);
  2845. if(flip){
  2846. vec2.scale(localAxis,localAxis,-1);
  2847. }
  2848. var closestEdge = -1,
  2849. N = c.vertices.length,
  2850. maxDot = -1;
  2851. for(var i=0; i!==N; i++){
  2852. // Get the edge
  2853. sub(edge, c.vertices[(i+1)%N], c.vertices[i%N]);
  2854. // Get normal - just rotate 90 degrees since vertices are given in CCW
  2855. vec2.rotate90cw(normal, edge);
  2856. vec2.normalize(normal,normal);
  2857. var d = dot(normal,localAxis);
  2858. if(closestEdge === -1 || d > maxDot){
  2859. closestEdge = i % N;
  2860. maxDot = d;
  2861. }
  2862. }
  2863. return closestEdge;
  2864. };
  2865. var circleHeightfield_candidate = vec2.create(),
  2866. circleHeightfield_dist = vec2.create(),
  2867. circleHeightfield_v0 = vec2.create(),
  2868. circleHeightfield_v1 = vec2.create(),
  2869. circleHeightfield_minCandidate = vec2.create(),
  2870. circleHeightfield_worldNormal = vec2.create(),
  2871. circleHeightfield_minCandidateNormal = vec2.create();
  2872. /**
  2873. * @method circleHeightfield
  2874. * @param {Body} bi
  2875. * @param {Circle} si
  2876. * @param {Array} xi
  2877. * @param {Body} bj
  2878. * @param {Heightfield} sj
  2879. * @param {Array} xj
  2880. * @param {Number} aj
  2881. */
  2882. Narrowphase.prototype[Shape.CIRCLE | Shape.HEIGHTFIELD] =
  2883. Narrowphase.prototype.circleHeightfield = function( circleBody,circleShape,circlePos,circleAngle,
  2884. hfBody,hfShape,hfPos,hfAngle, justTest, radius ){
  2885. var data = hfShape.heights,
  2886. radius = radius || circleShape.radius,
  2887. w = hfShape.elementWidth,
  2888. dist = circleHeightfield_dist,
  2889. candidate = circleHeightfield_candidate,
  2890. minCandidate = circleHeightfield_minCandidate,
  2891. minCandidateNormal = circleHeightfield_minCandidateNormal,
  2892. worldNormal = circleHeightfield_worldNormal,
  2893. v0 = circleHeightfield_v0,
  2894. v1 = circleHeightfield_v1;
  2895. // Get the index of the points to test against
  2896. var idxA = Math.floor( (circlePos[0] - radius - hfPos[0]) / w ),
  2897. idxB = Math.ceil( (circlePos[0] + radius - hfPos[0]) / w );
  2898. /*if(idxB < 0 || idxA >= data.length)
  2899. return justTest ? false : 0;*/
  2900. if(idxA < 0){
  2901. idxA = 0;
  2902. }
  2903. if(idxB >= data.length){
  2904. idxB = data.length-1;
  2905. }
  2906. // Get max and min
  2907. var max = data[idxA],
  2908. min = data[idxB];
  2909. for(var i=idxA; i<idxB; i++){
  2910. if(data[i] < min){
  2911. min = data[i];
  2912. }
  2913. if(data[i] > max){
  2914. max = data[i];
  2915. }
  2916. }
  2917. if(circlePos[1]-radius > max){
  2918. return justTest ? false : 0;
  2919. }
  2920. /*
  2921. if(circlePos[1]+radius < min){
  2922. // Below the minimum point... We can just guess.
  2923. // TODO
  2924. }
  2925. */
  2926. // 1. Check so center of circle is not inside the field. If it is, this wont work...
  2927. // 2. For each edge
  2928. // 2. 1. Get point on circle that is closest to the edge (scale normal with -radius)
  2929. // 2. 2. Check if point is inside.
  2930. var found = false;
  2931. // Check all edges first
  2932. for(var i=idxA; i<idxB; i++){
  2933. // Get points
  2934. vec2.set(v0, i*w, data[i] );
  2935. vec2.set(v1, (i+1)*w, data[i+1]);
  2936. vec2.add(v0,v0,hfPos);
  2937. vec2.add(v1,v1,hfPos);
  2938. // Get normal
  2939. vec2.sub(worldNormal, v1, v0);
  2940. vec2.rotate(worldNormal, worldNormal, Math.PI/2);
  2941. vec2.normalize(worldNormal,worldNormal);
  2942. // Get point on circle, closest to the edge
  2943. vec2.scale(candidate,worldNormal,-radius);
  2944. vec2.add(candidate,candidate,circlePos);
  2945. // Distance from v0 to the candidate point
  2946. vec2.sub(dist,candidate,v0);
  2947. // Check if it is in the element "stick"
  2948. var d = vec2.dot(dist,worldNormal);
  2949. if(candidate[0] >= v0[0] && candidate[0] < v1[0] && d <= 0){
  2950. if(justTest){
  2951. return true;
  2952. }
  2953. found = true;
  2954. // Store the candidate point, projected to the edge
  2955. vec2.scale(dist,worldNormal,-d);
  2956. vec2.add(minCandidate,candidate,dist);
  2957. vec2.copy(minCandidateNormal,worldNormal);
  2958. var c = this.createContactEquation(hfBody,circleBody,hfShape,circleShape);
  2959. // Normal is out of the heightfield
  2960. vec2.copy(c.normalA, minCandidateNormal);
  2961. // Vector from circle to heightfield
  2962. vec2.scale(c.contactPointB, c.normalA, -radius);
  2963. add(c.contactPointB, c.contactPointB, circlePos);
  2964. sub(c.contactPointB, c.contactPointB, circleBody.position);
  2965. vec2.copy(c.contactPointA, minCandidate);
  2966. vec2.sub(c.contactPointA, c.contactPointA, hfBody.position);
  2967. this.contactEquations.push(c);
  2968. if(this.enableFriction){
  2969. this.frictionEquations.push( this.createFrictionFromContact(c) );
  2970. }
  2971. }
  2972. }
  2973. // Check all vertices
  2974. found = false;
  2975. if(radius > 0){
  2976. for(var i=idxA; i<=idxB; i++){
  2977. // Get point
  2978. vec2.set(v0, i*w, data[i]);
  2979. vec2.add(v0,v0,hfPos);
  2980. vec2.sub(dist, circlePos, v0);
  2981. if(vec2.squaredLength(dist) < Math.pow(radius, 2)){
  2982. if(justTest){
  2983. return true;
  2984. }
  2985. found = true;
  2986. var c = this.createContactEquation(hfBody,circleBody,hfShape,circleShape);
  2987. // Construct normal - out of heightfield
  2988. vec2.copy(c.normalA, dist);
  2989. vec2.normalize(c.normalA,c.normalA);
  2990. vec2.scale(c.contactPointB, c.normalA, -radius);
  2991. add(c.contactPointB, c.contactPointB, circlePos);
  2992. sub(c.contactPointB, c.contactPointB, circleBody.position);
  2993. sub(c.contactPointA, v0, hfPos);
  2994. add(c.contactPointA, c.contactPointA, hfPos);
  2995. sub(c.contactPointA, c.contactPointA, hfBody.position);
  2996. this.contactEquations.push(c);
  2997. if(this.enableFriction){
  2998. this.frictionEquations.push(this.createFrictionFromContact(c));
  2999. }
  3000. }
  3001. }
  3002. }
  3003. if(found){
  3004. return 1;
  3005. }
  3006. return 0;
  3007. };
  3008. var convexHeightfield_v0 = vec2.create(),
  3009. convexHeightfield_v1 = vec2.create(),
  3010. convexHeightfield_tilePos = vec2.create(),
  3011. convexHeightfield_tempConvexShape = new Convex({ vertices: [vec2.create(),vec2.create(),vec2.create(),vec2.create()] });
  3012. /**
  3013. * @method circleHeightfield
  3014. * @param {Body} bi
  3015. * @param {Circle} si
  3016. * @param {Array} xi
  3017. * @param {Body} bj
  3018. * @param {Heightfield} sj
  3019. * @param {Array} xj
  3020. * @param {Number} aj
  3021. */
  3022. Narrowphase.prototype[Shape.BOX | Shape.HEIGHTFIELD] =
  3023. Narrowphase.prototype[Shape.CONVEX | Shape.HEIGHTFIELD] =
  3024. Narrowphase.prototype.convexHeightfield = function( convexBody,convexShape,convexPos,convexAngle,
  3025. hfBody,hfShape,hfPos,hfAngle, justTest ){
  3026. var data = hfShape.heights,
  3027. w = hfShape.elementWidth,
  3028. v0 = convexHeightfield_v0,
  3029. v1 = convexHeightfield_v1,
  3030. tilePos = convexHeightfield_tilePos,
  3031. tileConvex = convexHeightfield_tempConvexShape;
  3032. // Get the index of the points to test against
  3033. var idxA = Math.floor( (convexBody.aabb.lowerBound[0] - hfPos[0]) / w ),
  3034. idxB = Math.ceil( (convexBody.aabb.upperBound[0] - hfPos[0]) / w );
  3035. if(idxA < 0){
  3036. idxA = 0;
  3037. }
  3038. if(idxB >= data.length){
  3039. idxB = data.length-1;
  3040. }
  3041. // Get max and min
  3042. var max = data[idxA],
  3043. min = data[idxB];
  3044. for(var i=idxA; i<idxB; i++){
  3045. if(data[i] < min){
  3046. min = data[i];
  3047. }
  3048. if(data[i] > max){
  3049. max = data[i];
  3050. }
  3051. }
  3052. if(convexBody.aabb.lowerBound[1] > max){
  3053. return justTest ? false : 0;
  3054. }
  3055. var found = false;
  3056. var numContacts = 0;
  3057. // Loop over all edges
  3058. // TODO: If possible, construct a convex from several data points (need o check if the points make a convex shape)
  3059. for(var i=idxA; i<idxB; i++){
  3060. // Get points
  3061. vec2.set(v0, i*w, data[i] );
  3062. vec2.set(v1, (i+1)*w, data[i+1]);
  3063. vec2.add(v0,v0,hfPos);
  3064. vec2.add(v1,v1,hfPos);
  3065. // Construct a convex
  3066. var tileHeight = 100; // todo
  3067. vec2.set(tilePos, (v1[0] + v0[0])*0.5, (v1[1] + v0[1] - tileHeight)*0.5);
  3068. vec2.sub(tileConvex.vertices[0], v1, tilePos);
  3069. vec2.sub(tileConvex.vertices[1], v0, tilePos);
  3070. vec2.copy(tileConvex.vertices[2], tileConvex.vertices[1]);
  3071. vec2.copy(tileConvex.vertices[3], tileConvex.vertices[0]);
  3072. tileConvex.vertices[2][1] -= tileHeight;
  3073. tileConvex.vertices[3][1] -= tileHeight;
  3074. // Do convex collision
  3075. numContacts += this.convexConvex( convexBody, convexShape, convexPos, convexAngle,
  3076. hfBody, tileConvex, tilePos, 0, justTest);
  3077. }
  3078. return numContacts;
  3079. };
  3080. },{"../equations/ContactEquation":21,"../equations/Equation":22,"../equations/FrictionEquation":23,"../math/vec2":30,"../objects/Body":31,"../shapes/Box":37,"../shapes/Circle":39,"../shapes/Convex":40,"../shapes/Shape":45,"../utils/ContactEquationPool":48,"../utils/FrictionEquationPool":49,"../utils/TupleDictionary":56,"../utils/Utils":57}],11:[function(_dereq_,module,exports){
  3081. module.exports = Ray;
  3082. var vec2 = _dereq_('../math/vec2');
  3083. var RaycastResult = _dereq_('../collision/RaycastResult');
  3084. var Shape = _dereq_('../shapes/Shape');
  3085. var AABB = _dereq_('../collision/AABB');
  3086. /**
  3087. * A line with a start and end point that is used to intersect shapes. For an example, see {{#crossLink "World/raycast:method"}}World.raycast{{/crossLink}}
  3088. * @class Ray
  3089. * @constructor
  3090. * @param {object} [options]
  3091. * @param {array} [options.from]
  3092. * @param {array} [options.to]
  3093. * @param {boolean} [options.checkCollisionResponse=true]
  3094. * @param {boolean} [options.skipBackfaces=false]
  3095. * @param {number} [options.collisionMask=-1]
  3096. * @param {number} [options.collisionGroup=-1]
  3097. * @param {number} [options.mode=Ray.ANY]
  3098. * @param {number} [options.callback]
  3099. */
  3100. function Ray(options){
  3101. options = options || {};
  3102. /**
  3103. * Ray start point.
  3104. * @property {array} from
  3105. */
  3106. this.from = options.from ? vec2.fromValues(options.from[0], options.from[1]) : vec2.create();
  3107. /**
  3108. * Ray end point
  3109. * @property {array} to
  3110. */
  3111. this.to = options.to ? vec2.fromValues(options.to[0], options.to[1]) : vec2.create();
  3112. /**
  3113. * Set to true if you want the Ray to take .collisionResponse flags into account on bodies and shapes.
  3114. * @property {Boolean} checkCollisionResponse
  3115. */
  3116. this.checkCollisionResponse = options.checkCollisionResponse !== undefined ? options.checkCollisionResponse : true;
  3117. /**
  3118. * If set to true, the ray skips any hits with normal.dot(rayDirection) < 0.
  3119. * @property {Boolean} skipBackfaces
  3120. */
  3121. this.skipBackfaces = !!options.skipBackfaces;
  3122. /**
  3123. * @property {number} collisionMask
  3124. * @default -1
  3125. */
  3126. this.collisionMask = options.collisionMask !== undefined ? options.collisionMask : -1;
  3127. /**
  3128. * @property {number} collisionGroup
  3129. * @default -1
  3130. */
  3131. this.collisionGroup = options.collisionGroup !== undefined ? options.collisionGroup : -1;
  3132. /**
  3133. * The intersection mode. Should be {{#crossLink "Ray/ANY:property"}}Ray.ANY{{/crossLink}}, {{#crossLink "Ray/ALL:property"}}Ray.ALL{{/crossLink}} or {{#crossLink "Ray/CLOSEST:property"}}Ray.CLOSEST{{/crossLink}}.
  3134. * @property {number} mode
  3135. */
  3136. this.mode = options.mode !== undefined ? options.mode : Ray.ANY;
  3137. /**
  3138. * Current, user-provided result callback. Will be used if mode is Ray.ALL.
  3139. * @property {Function} callback
  3140. */
  3141. this.callback = options.callback || function(result){};
  3142. /**
  3143. * @readOnly
  3144. * @property {array} direction
  3145. */
  3146. this.direction = vec2.create();
  3147. /**
  3148. * Length of the ray
  3149. * @readOnly
  3150. * @property {number} length
  3151. */
  3152. this.length = 1;
  3153. this.update();
  3154. }
  3155. Ray.prototype.constructor = Ray;
  3156. /**
  3157. * This raycasting mode will make the Ray traverse through all intersection points and only return the closest one.
  3158. * @static
  3159. * @property {Number} CLOSEST
  3160. */
  3161. Ray.CLOSEST = 1;
  3162. /**
  3163. * This raycasting mode will make the Ray stop when it finds the first intersection point.
  3164. * @static
  3165. * @property {Number} ANY
  3166. */
  3167. Ray.ANY = 2;
  3168. /**
  3169. * This raycasting mode will traverse all intersection points and executes a callback for each one.
  3170. * @static
  3171. * @property {Number} ALL
  3172. */
  3173. Ray.ALL = 4;
  3174. /**
  3175. * Should be called if you change the from or to point.
  3176. * @method update
  3177. */
  3178. Ray.prototype.update = function(){
  3179. // Update .direction and .length
  3180. var d = this.direction;
  3181. vec2.sub(d, this.to, this.from);
  3182. this.length = vec2.length(d);
  3183. vec2.normalize(d, d);
  3184. };
  3185. /**
  3186. * @method intersectBodies
  3187. * @param {Array} bodies An array of Body objects.
  3188. */
  3189. Ray.prototype.intersectBodies = function (result, bodies) {
  3190. for (var i = 0, l = bodies.length; !result.shouldStop(this) && i < l; i++) {
  3191. var body = bodies[i];
  3192. var aabb = body.getAABB();
  3193. if(aabb.overlapsRay(this) >= 0 || aabb.containsPoint(this.from)){
  3194. this.intersectBody(result, body);
  3195. }
  3196. }
  3197. };
  3198. var intersectBody_worldPosition = vec2.create();
  3199. /**
  3200. * Shoot a ray at a body, get back information about the hit.
  3201. * @method intersectBody
  3202. * @private
  3203. * @param {Body} body
  3204. */
  3205. Ray.prototype.intersectBody = function (result, body) {
  3206. var checkCollisionResponse = this.checkCollisionResponse;
  3207. if(checkCollisionResponse && !body.collisionResponse){
  3208. return;
  3209. }
  3210. var worldPosition = intersectBody_worldPosition;
  3211. for (var i = 0, N = body.shapes.length; i < N; i++) {
  3212. var shape = body.shapes[i];
  3213. if(checkCollisionResponse && !shape.collisionResponse){
  3214. continue; // Skip
  3215. }
  3216. if((this.collisionGroup & shape.collisionMask) === 0 || (shape.collisionGroup & this.collisionMask) === 0){
  3217. continue;
  3218. }
  3219. // Get world angle and position of the shape
  3220. vec2.rotate(worldPosition, shape.position, body.angle);
  3221. vec2.add(worldPosition, worldPosition, body.position);
  3222. var worldAngle = shape.angle + body.angle;
  3223. this.intersectShape(
  3224. result,
  3225. shape,
  3226. worldAngle,
  3227. worldPosition,
  3228. body
  3229. );
  3230. if(result.shouldStop(this)){
  3231. break;
  3232. }
  3233. }
  3234. };
  3235. /**
  3236. * @method intersectShape
  3237. * @private
  3238. * @param {Shape} shape
  3239. * @param {number} angle
  3240. * @param {array} position
  3241. * @param {Body} body
  3242. */
  3243. Ray.prototype.intersectShape = function(result, shape, angle, position, body){
  3244. var from = this.from;
  3245. // Checking radius
  3246. var distance = distanceFromIntersectionSquared(from, this.direction, position);
  3247. if (distance > shape.boundingRadius * shape.boundingRadius) {
  3248. return;
  3249. }
  3250. this._currentBody = body;
  3251. this._currentShape = shape;
  3252. shape.raycast(result, this, position, angle);
  3253. this._currentBody = this._currentShape = null;
  3254. };
  3255. /**
  3256. * Get the AABB of the ray.
  3257. * @method getAABB
  3258. * @param {AABB} aabb
  3259. */
  3260. Ray.prototype.getAABB = function(result){
  3261. var to = this.to;
  3262. var from = this.from;
  3263. vec2.set(
  3264. result.lowerBound,
  3265. Math.min(to[0], from[0]),
  3266. Math.min(to[1], from[1])
  3267. );
  3268. vec2.set(
  3269. result.upperBound,
  3270. Math.max(to[0], from[0]),
  3271. Math.max(to[1], from[1])
  3272. );
  3273. };
  3274. var hitPointWorld = vec2.create();
  3275. /**
  3276. * @method reportIntersection
  3277. * @private
  3278. * @param {number} fraction
  3279. * @param {array} normal
  3280. * @param {number} [faceIndex=-1]
  3281. * @return {boolean} True if the intersections should continue
  3282. */
  3283. Ray.prototype.reportIntersection = function(result, fraction, normal, faceIndex){
  3284. var from = this.from;
  3285. var to = this.to;
  3286. var shape = this._currentShape;
  3287. var body = this._currentBody;
  3288. // Skip back faces?
  3289. if(this.skipBackfaces && vec2.dot(normal, this.direction) > 0){
  3290. return;
  3291. }
  3292. switch(this.mode){
  3293. case Ray.ALL:
  3294. result.set(
  3295. normal,
  3296. shape,
  3297. body,
  3298. fraction,
  3299. faceIndex
  3300. );
  3301. this.callback(result);
  3302. break;
  3303. case Ray.CLOSEST:
  3304. // Store if closer than current closest
  3305. if(fraction < result.fraction || !result.hasHit()){
  3306. result.set(
  3307. normal,
  3308. shape,
  3309. body,
  3310. fraction,
  3311. faceIndex
  3312. );
  3313. }
  3314. break;
  3315. case Ray.ANY:
  3316. // Report and stop.
  3317. result.set(
  3318. normal,
  3319. shape,
  3320. body,
  3321. fraction,
  3322. faceIndex
  3323. );
  3324. break;
  3325. }
  3326. };
  3327. var v0 = vec2.create(),
  3328. intersect = vec2.create();
  3329. function distanceFromIntersectionSquared(from, direction, position) {
  3330. // v0 is vector from from to position
  3331. vec2.sub(v0, position, from);
  3332. var dot = vec2.dot(v0, direction);
  3333. // intersect = direction * dot + from
  3334. vec2.scale(intersect, direction, dot);
  3335. vec2.add(intersect, intersect, from);
  3336. return vec2.squaredDistance(position, intersect);
  3337. }
  3338. },{"../collision/AABB":7,"../collision/RaycastResult":12,"../math/vec2":30,"../shapes/Shape":45}],12:[function(_dereq_,module,exports){
  3339. var vec2 = _dereq_('../math/vec2');
  3340. var Ray = _dereq_('../collision/Ray');
  3341. module.exports = RaycastResult;
  3342. /**
  3343. * Storage for Ray casting hit data.
  3344. * @class RaycastResult
  3345. * @constructor
  3346. */
  3347. function RaycastResult(){
  3348. /**
  3349. * The normal of the hit, oriented in world space.
  3350. * @property {array} normal
  3351. */
  3352. this.normal = vec2.create();
  3353. /**
  3354. * The hit shape, or null.
  3355. * @property {Shape} shape
  3356. */
  3357. this.shape = null;
  3358. /**
  3359. * The hit body, or null.
  3360. * @property {Body} body
  3361. */
  3362. this.body = null;
  3363. /**
  3364. * The index of the hit triangle, if the hit shape was indexable.
  3365. * @property {number} faceIndex
  3366. * @default -1
  3367. */
  3368. this.faceIndex = -1;
  3369. /**
  3370. * Distance to the hit, as a fraction. 0 is at the "from" point, 1 is at the "to" point. Will be set to -1 if there was no hit yet.
  3371. * @property {number} fraction
  3372. * @default -1
  3373. */
  3374. this.fraction = -1;
  3375. /**
  3376. * If the ray should stop traversing.
  3377. * @readonly
  3378. * @property {Boolean} isStopped
  3379. */
  3380. this.isStopped = false;
  3381. }
  3382. /**
  3383. * Reset all result data. Must be done before re-using the result object.
  3384. * @method reset
  3385. */
  3386. RaycastResult.prototype.reset = function () {
  3387. vec2.set(this.normal, 0, 0);
  3388. this.shape = null;
  3389. this.body = null;
  3390. this.faceIndex = -1;
  3391. this.fraction = -1;
  3392. this.isStopped = false;
  3393. };
  3394. /**
  3395. * Get the distance to the hit point.
  3396. * @method getHitDistance
  3397. * @param {Ray} ray
  3398. */
  3399. RaycastResult.prototype.getHitDistance = function (ray) {
  3400. return vec2.distance(ray.from, ray.to) * this.fraction;
  3401. };
  3402. /**
  3403. * Returns true if the ray hit something since the last reset().
  3404. * @method hasHit
  3405. */
  3406. RaycastResult.prototype.hasHit = function () {
  3407. return this.fraction !== -1;
  3408. };
  3409. /**
  3410. * Get world hit point.
  3411. * @method getHitPoint
  3412. * @param {array} out
  3413. * @param {Ray} ray
  3414. */
  3415. RaycastResult.prototype.getHitPoint = function (out, ray) {
  3416. vec2.lerp(out, ray.from, ray.to, this.fraction);
  3417. };
  3418. /**
  3419. * Can be called while iterating over hits to stop searching for hit points.
  3420. * @method stop
  3421. */
  3422. RaycastResult.prototype.stop = function(){
  3423. this.isStopped = true;
  3424. };
  3425. /**
  3426. * @method shouldStop
  3427. * @private
  3428. * @param {Ray} ray
  3429. * @return {boolean}
  3430. */
  3431. RaycastResult.prototype.shouldStop = function(ray){
  3432. return this.isStopped || (this.fraction !== -1 && ray.mode === Ray.ANY);
  3433. };
  3434. /**
  3435. * @method set
  3436. * @private
  3437. * @param {array} normal
  3438. * @param {Shape} shape
  3439. * @param {Body} body
  3440. * @param {number} fraction
  3441. */
  3442. RaycastResult.prototype.set = function(
  3443. normal,
  3444. shape,
  3445. body,
  3446. fraction,
  3447. faceIndex
  3448. ){
  3449. vec2.copy(this.normal, normal);
  3450. this.shape = shape;
  3451. this.body = body;
  3452. this.fraction = fraction;
  3453. this.faceIndex = faceIndex;
  3454. };
  3455. },{"../collision/Ray":11,"../math/vec2":30}],13:[function(_dereq_,module,exports){
  3456. var Utils = _dereq_('../utils/Utils')
  3457. , Broadphase = _dereq_('../collision/Broadphase');
  3458. module.exports = SAPBroadphase;
  3459. /**
  3460. * Sweep and prune broadphase along one axis.
  3461. *
  3462. * @class SAPBroadphase
  3463. * @constructor
  3464. * @extends Broadphase
  3465. */
  3466. function SAPBroadphase(){
  3467. Broadphase.call(this,Broadphase.SAP);
  3468. /**
  3469. * List of bodies currently in the broadphase.
  3470. * @property axisList
  3471. * @type {Array}
  3472. */
  3473. this.axisList = [];
  3474. /**
  3475. * The axis to sort along. 0 means x-axis and 1 y-axis. If your bodies are more spread out over the X axis, set axisIndex to 0, and you will gain some performance.
  3476. * @property axisIndex
  3477. * @type {Number}
  3478. */
  3479. this.axisIndex = 0;
  3480. var that = this;
  3481. this._addBodyHandler = function(e){
  3482. that.axisList.push(e.body);
  3483. };
  3484. this._removeBodyHandler = function(e){
  3485. // Remove from list
  3486. var idx = that.axisList.indexOf(e.body);
  3487. if(idx !== -1){
  3488. that.axisList.splice(idx,1);
  3489. }
  3490. };
  3491. }
  3492. SAPBroadphase.prototype = new Broadphase();
  3493. SAPBroadphase.prototype.constructor = SAPBroadphase;
  3494. /**
  3495. * Change the world
  3496. * @method setWorld
  3497. * @param {World} world
  3498. */
  3499. SAPBroadphase.prototype.setWorld = function(world){
  3500. // Clear the old axis array
  3501. this.axisList.length = 0;
  3502. // Add all bodies from the new world
  3503. Utils.appendArray(this.axisList, world.bodies);
  3504. // Remove old handlers, if any
  3505. world
  3506. .off("addBody",this._addBodyHandler)
  3507. .off("removeBody",this._removeBodyHandler);
  3508. // Add handlers to update the list of bodies.
  3509. world.on("addBody",this._addBodyHandler).on("removeBody",this._removeBodyHandler);
  3510. this.world = world;
  3511. };
  3512. /**
  3513. * Sorts bodies along an axis.
  3514. * @method sortAxisList
  3515. * @param {Array} a
  3516. * @param {number} axisIndex
  3517. * @return {Array}
  3518. */
  3519. SAPBroadphase.sortAxisList = function(a, axisIndex){
  3520. axisIndex = axisIndex|0;
  3521. for(var i=1,l=a.length; i<l; i++) {
  3522. var v = a[i];
  3523. for(var j=i - 1;j>=0;j--) {
  3524. if(a[j].aabb.lowerBound[axisIndex] <= v.aabb.lowerBound[axisIndex]){
  3525. break;
  3526. }
  3527. a[j+1] = a[j];
  3528. }
  3529. a[j+1] = v;
  3530. }
  3531. return a;
  3532. };
  3533. SAPBroadphase.prototype.sortList = function(){
  3534. var bodies = this.axisList,
  3535. axisIndex = this.axisIndex;
  3536. // Sort the lists
  3537. SAPBroadphase.sortAxisList(bodies, axisIndex);
  3538. };
  3539. /**
  3540. * Get the colliding pairs
  3541. * @method getCollisionPairs
  3542. * @param {World} world
  3543. * @return {Array}
  3544. */
  3545. SAPBroadphase.prototype.getCollisionPairs = function(world){
  3546. var bodies = this.axisList,
  3547. result = this.result,
  3548. axisIndex = this.axisIndex;
  3549. result.length = 0;
  3550. // Update all AABBs if needed
  3551. var l = bodies.length;
  3552. while(l--){
  3553. var b = bodies[l];
  3554. if(b.aabbNeedsUpdate){
  3555. b.updateAABB();
  3556. }
  3557. }
  3558. // Sort the lists
  3559. this.sortList();
  3560. // Look through the X list
  3561. for(var i=0, N=bodies.length|0; i!==N; i++){
  3562. var bi = bodies[i];
  3563. for(var j=i+1; j<N; j++){
  3564. var bj = bodies[j];
  3565. // Bounds overlap?
  3566. var overlaps = (bj.aabb.lowerBound[axisIndex] <= bi.aabb.upperBound[axisIndex]);
  3567. if(!overlaps){
  3568. break;
  3569. }
  3570. if(Broadphase.canCollide(bi,bj) && this.boundingVolumeCheck(bi,bj)){
  3571. result.push(bi,bj);
  3572. }
  3573. }
  3574. }
  3575. return result;
  3576. };
  3577. /**
  3578. * Returns all the bodies within an AABB.
  3579. * @method aabbQuery
  3580. * @param {World} world
  3581. * @param {AABB} aabb
  3582. * @param {array} result An array to store resulting bodies in.
  3583. * @return {array}
  3584. */
  3585. SAPBroadphase.prototype.aabbQuery = function(world, aabb, result){
  3586. result = result || [];
  3587. this.sortList();
  3588. var axisIndex = this.axisIndex;
  3589. var axis = 'x';
  3590. if(axisIndex === 1){ axis = 'y'; }
  3591. if(axisIndex === 2){ axis = 'z'; }
  3592. var axisList = this.axisList;
  3593. var lower = aabb.lowerBound[axis];
  3594. var upper = aabb.upperBound[axis];
  3595. for(var i = 0; i < axisList.length; i++){
  3596. var b = axisList[i];
  3597. if(b.aabbNeedsUpdate){
  3598. b.updateAABB();
  3599. }
  3600. if(b.aabb.overlaps(aabb)){
  3601. result.push(b);
  3602. }
  3603. }
  3604. return result;
  3605. };
  3606. },{"../collision/Broadphase":8,"../utils/Utils":57}],14:[function(_dereq_,module,exports){
  3607. module.exports = Constraint;
  3608. var Utils = _dereq_('../utils/Utils');
  3609. /**
  3610. * Base constraint class.
  3611. *
  3612. * @class Constraint
  3613. * @constructor
  3614. * @author schteppe
  3615. * @param {Body} bodyA
  3616. * @param {Body} bodyB
  3617. * @param {Number} type
  3618. * @param {Object} [options]
  3619. * @param {Object} [options.collideConnected=true]
  3620. */
  3621. function Constraint(bodyA, bodyB, type, options){
  3622. /**
  3623. * The type of constraint. May be one of Constraint.DISTANCE, Constraint.GEAR, Constraint.LOCK, Constraint.PRISMATIC or Constraint.REVOLUTE.
  3624. * @property {number} type
  3625. */
  3626. this.type = type;
  3627. options = Utils.defaults(options,{
  3628. collideConnected : true,
  3629. wakeUpBodies : true,
  3630. });
  3631. /**
  3632. * Equations to be solved in this constraint
  3633. *
  3634. * @property equations
  3635. * @type {Array}
  3636. */
  3637. this.equations = [];
  3638. /**
  3639. * First body participating in the constraint.
  3640. * @property bodyA
  3641. * @type {Body}
  3642. */
  3643. this.bodyA = bodyA;
  3644. /**
  3645. * Second body participating in the constraint.
  3646. * @property bodyB
  3647. * @type {Body}
  3648. */
  3649. this.bodyB = bodyB;
  3650. /**
  3651. * Set to true if you want the connected bodies to collide.
  3652. * @property collideConnected
  3653. * @type {Boolean}
  3654. * @default true
  3655. */
  3656. this.collideConnected = options.collideConnected;
  3657. // Wake up bodies when connected
  3658. if(options.wakeUpBodies){
  3659. if(bodyA){
  3660. bodyA.wakeUp();
  3661. }
  3662. if(bodyB){
  3663. bodyB.wakeUp();
  3664. }
  3665. }
  3666. }
  3667. /**
  3668. * Updates the internal constraint parameters before solve.
  3669. * @method update
  3670. */
  3671. Constraint.prototype.update = function(){
  3672. throw new Error("method update() not implmemented in this Constraint subclass!");
  3673. };
  3674. /**
  3675. * @static
  3676. * @property {number} DISTANCE
  3677. */
  3678. Constraint.DISTANCE = 1;
  3679. /**
  3680. * @static
  3681. * @property {number} GEAR
  3682. */
  3683. Constraint.GEAR = 2;
  3684. /**
  3685. * @static
  3686. * @property {number} LOCK
  3687. */
  3688. Constraint.LOCK = 3;
  3689. /**
  3690. * @static
  3691. * @property {number} PRISMATIC
  3692. */
  3693. Constraint.PRISMATIC = 4;
  3694. /**
  3695. * @static
  3696. * @property {number} REVOLUTE
  3697. */
  3698. Constraint.REVOLUTE = 5;
  3699. /**
  3700. * Set stiffness for this constraint.
  3701. * @method setStiffness
  3702. * @param {Number} stiffness
  3703. */
  3704. Constraint.prototype.setStiffness = function(stiffness){
  3705. var eqs = this.equations;
  3706. for(var i=0; i !== eqs.length; i++){
  3707. var eq = eqs[i];
  3708. eq.stiffness = stiffness;
  3709. eq.needsUpdate = true;
  3710. }
  3711. };
  3712. /**
  3713. * Set relaxation for this constraint.
  3714. * @method setRelaxation
  3715. * @param {Number} relaxation
  3716. */
  3717. Constraint.prototype.setRelaxation = function(relaxation){
  3718. var eqs = this.equations;
  3719. for(var i=0; i !== eqs.length; i++){
  3720. var eq = eqs[i];
  3721. eq.relaxation = relaxation;
  3722. eq.needsUpdate = true;
  3723. }
  3724. };
  3725. },{"../utils/Utils":57}],15:[function(_dereq_,module,exports){
  3726. var Constraint = _dereq_('./Constraint')
  3727. , Equation = _dereq_('../equations/Equation')
  3728. , vec2 = _dereq_('../math/vec2')
  3729. , Utils = _dereq_('../utils/Utils');
  3730. module.exports = DistanceConstraint;
  3731. /**
  3732. * Constraint that tries to keep the distance between two bodies constant.
  3733. *
  3734. * @class DistanceConstraint
  3735. * @constructor
  3736. * @author schteppe
  3737. * @param {Body} bodyA
  3738. * @param {Body} bodyB
  3739. * @param {object} [options]
  3740. * @param {number} [options.distance] The distance to keep between the anchor points. Defaults to the current distance between the bodies.
  3741. * @param {Array} [options.localAnchorA] The anchor point for bodyA, defined locally in bodyA frame. Defaults to [0,0].
  3742. * @param {Array} [options.localAnchorB] The anchor point for bodyB, defined locally in bodyB frame. Defaults to [0,0].
  3743. * @param {object} [options.maxForce=Number.MAX_VALUE] Maximum force to apply.
  3744. * @extends Constraint
  3745. *
  3746. * @example
  3747. * // If distance is not given as an option, then the current distance between the bodies is used.
  3748. * // In this example, the bodies will be constrained to have a distance of 2 between their centers.
  3749. * var bodyA = new Body({ mass: 1, position: [-1, 0] });
  3750. * var bodyB = new Body({ mass: 1, position: [1, 0] });
  3751. * var constraint = new DistanceConstraint(bodyA, bodyB);
  3752. * world.addConstraint(constraint);
  3753. *
  3754. * @example
  3755. * // Manually set the distance and anchors
  3756. * var constraint = new DistanceConstraint(bodyA, bodyB, {
  3757. * distance: 1, // Distance to keep between the points
  3758. * localAnchorA: [1, 0], // Point on bodyA
  3759. * localAnchorB: [-1, 0] // Point on bodyB
  3760. * });
  3761. * world.addConstraint(constraint);
  3762. */
  3763. function DistanceConstraint(bodyA,bodyB,options){
  3764. options = Utils.defaults(options,{
  3765. localAnchorA:[0,0],
  3766. localAnchorB:[0,0]
  3767. });
  3768. Constraint.call(this,bodyA,bodyB,Constraint.DISTANCE,options);
  3769. /**
  3770. * Local anchor in body A.
  3771. * @property localAnchorA
  3772. * @type {Array}
  3773. */
  3774. this.localAnchorA = vec2.fromValues(options.localAnchorA[0], options.localAnchorA[1]);
  3775. /**
  3776. * Local anchor in body B.
  3777. * @property localAnchorB
  3778. * @type {Array}
  3779. */
  3780. this.localAnchorB = vec2.fromValues(options.localAnchorB[0], options.localAnchorB[1]);
  3781. var localAnchorA = this.localAnchorA;
  3782. var localAnchorB = this.localAnchorB;
  3783. /**
  3784. * The distance to keep.
  3785. * @property distance
  3786. * @type {Number}
  3787. */
  3788. this.distance = 0;
  3789. if(typeof(options.distance) === 'number'){
  3790. this.distance = options.distance;
  3791. } else {
  3792. // Use the current world distance between the world anchor points.
  3793. var worldAnchorA = vec2.create(),
  3794. worldAnchorB = vec2.create(),
  3795. r = vec2.create();
  3796. // Transform local anchors to world
  3797. vec2.rotate(worldAnchorA, localAnchorA, bodyA.angle);
  3798. vec2.rotate(worldAnchorB, localAnchorB, bodyB.angle);
  3799. vec2.add(r, bodyB.position, worldAnchorB);
  3800. vec2.sub(r, r, worldAnchorA);
  3801. vec2.sub(r, r, bodyA.position);
  3802. this.distance = vec2.length(r);
  3803. }
  3804. var maxForce;
  3805. if(typeof(options.maxForce)==="undefined" ){
  3806. maxForce = Number.MAX_VALUE;
  3807. } else {
  3808. maxForce = options.maxForce;
  3809. }
  3810. var normal = new Equation(bodyA,bodyB,-maxForce,maxForce); // Just in the normal direction
  3811. this.equations = [ normal ];
  3812. /**
  3813. * Max force to apply.
  3814. * @property {number} maxForce
  3815. */
  3816. this.maxForce = maxForce;
  3817. // g = (xi - xj).dot(n)
  3818. // dg/dt = (vi - vj).dot(n) = G*W = [n 0 -n 0] * [vi wi vj wj]'
  3819. // ...and if we were to include offset points:
  3820. // g =
  3821. // (xj + rj - xi - ri).dot(n) - distance
  3822. //
  3823. // dg/dt =
  3824. // (vj + wj x rj - vi - wi x ri).dot(n) =
  3825. // { term 2 is near zero } =
  3826. // [-n -ri x n n rj x n] * [vi wi vj wj]' =
  3827. // G * W
  3828. //
  3829. // => G = [-n -rixn n rjxn]
  3830. var r = vec2.create();
  3831. var ri = vec2.create(); // worldAnchorA
  3832. var rj = vec2.create(); // worldAnchorB
  3833. var that = this;
  3834. normal.computeGq = function(){
  3835. var bodyA = this.bodyA,
  3836. bodyB = this.bodyB,
  3837. xi = bodyA.position,
  3838. xj = bodyB.position;
  3839. // Transform local anchors to world
  3840. vec2.rotate(ri, localAnchorA, bodyA.angle);
  3841. vec2.rotate(rj, localAnchorB, bodyB.angle);
  3842. vec2.add(r, xj, rj);
  3843. vec2.sub(r, r, ri);
  3844. vec2.sub(r, r, xi);
  3845. //vec2.sub(r, bodyB.position, bodyA.position);
  3846. return vec2.length(r) - that.distance;
  3847. };
  3848. // Make the contact constraint bilateral
  3849. this.setMaxForce(maxForce);
  3850. /**
  3851. * If the upper limit is enabled or not.
  3852. * @property {Boolean} upperLimitEnabled
  3853. */
  3854. this.upperLimitEnabled = false;
  3855. /**
  3856. * The upper constraint limit.
  3857. * @property {number} upperLimit
  3858. */
  3859. this.upperLimit = 1;
  3860. /**
  3861. * If the lower limit is enabled or not.
  3862. * @property {Boolean} lowerLimitEnabled
  3863. */
  3864. this.lowerLimitEnabled = false;
  3865. /**
  3866. * The lower constraint limit.
  3867. * @property {number} lowerLimit
  3868. */
  3869. this.lowerLimit = 0;
  3870. /**
  3871. * Current constraint position. This is equal to the current distance between the world anchor points.
  3872. * @property {number} position
  3873. */
  3874. this.position = 0;
  3875. }
  3876. DistanceConstraint.prototype = new Constraint();
  3877. DistanceConstraint.prototype.constructor = DistanceConstraint;
  3878. /**
  3879. * Update the constraint equations. Should be done if any of the bodies changed position, before solving.
  3880. * @method update
  3881. */
  3882. var n = vec2.create();
  3883. var ri = vec2.create(); // worldAnchorA
  3884. var rj = vec2.create(); // worldAnchorB
  3885. DistanceConstraint.prototype.update = function(){
  3886. var normal = this.equations[0],
  3887. bodyA = this.bodyA,
  3888. bodyB = this.bodyB,
  3889. distance = this.distance,
  3890. xi = bodyA.position,
  3891. xj = bodyB.position,
  3892. normalEquation = this.equations[0],
  3893. G = normal.G;
  3894. // Transform local anchors to world
  3895. vec2.rotate(ri, this.localAnchorA, bodyA.angle);
  3896. vec2.rotate(rj, this.localAnchorB, bodyB.angle);
  3897. // Get world anchor points and normal
  3898. vec2.add(n, xj, rj);
  3899. vec2.sub(n, n, ri);
  3900. vec2.sub(n, n, xi);
  3901. this.position = vec2.length(n);
  3902. var violating = false;
  3903. if(this.upperLimitEnabled){
  3904. if(this.position > this.upperLimit){
  3905. normalEquation.maxForce = 0;
  3906. normalEquation.minForce = -this.maxForce;
  3907. this.distance = this.upperLimit;
  3908. violating = true;
  3909. }
  3910. }
  3911. if(this.lowerLimitEnabled){
  3912. if(this.position < this.lowerLimit){
  3913. normalEquation.maxForce = this.maxForce;
  3914. normalEquation.minForce = 0;
  3915. this.distance = this.lowerLimit;
  3916. violating = true;
  3917. }
  3918. }
  3919. if((this.lowerLimitEnabled || this.upperLimitEnabled) && !violating){
  3920. // No constraint needed.
  3921. normalEquation.enabled = false;
  3922. return;
  3923. }
  3924. normalEquation.enabled = true;
  3925. vec2.normalize(n,n);
  3926. // Caluclate cross products
  3927. var rixn = vec2.crossLength(ri, n),
  3928. rjxn = vec2.crossLength(rj, n);
  3929. // G = [-n -rixn n rjxn]
  3930. G[0] = -n[0];
  3931. G[1] = -n[1];
  3932. G[2] = -rixn;
  3933. G[3] = n[0];
  3934. G[4] = n[1];
  3935. G[5] = rjxn;
  3936. };
  3937. /**
  3938. * Set the max force to be used
  3939. * @method setMaxForce
  3940. * @param {Number} maxForce
  3941. */
  3942. DistanceConstraint.prototype.setMaxForce = function(maxForce){
  3943. var normal = this.equations[0];
  3944. normal.minForce = -maxForce;
  3945. normal.maxForce = maxForce;
  3946. };
  3947. /**
  3948. * Get the max force
  3949. * @method getMaxForce
  3950. * @return {Number}
  3951. */
  3952. DistanceConstraint.prototype.getMaxForce = function(){
  3953. var normal = this.equations[0];
  3954. return normal.maxForce;
  3955. };
  3956. },{"../equations/Equation":22,"../math/vec2":30,"../utils/Utils":57,"./Constraint":14}],16:[function(_dereq_,module,exports){
  3957. var Constraint = _dereq_('./Constraint')
  3958. , Equation = _dereq_('../equations/Equation')
  3959. , AngleLockEquation = _dereq_('../equations/AngleLockEquation')
  3960. , vec2 = _dereq_('../math/vec2');
  3961. module.exports = GearConstraint;
  3962. /**
  3963. * Constrains the angle of two bodies to each other to be equal. If a gear ratio is not one, the angle of bodyA must be a multiple of the angle of bodyB.
  3964. * @class GearConstraint
  3965. * @constructor
  3966. * @author schteppe
  3967. * @param {Body} bodyA
  3968. * @param {Body} bodyB
  3969. * @param {Object} [options]
  3970. * @param {Number} [options.angle=0] Relative angle between the bodies. Will be set to the current angle between the bodies (the gear ratio is accounted for).
  3971. * @param {Number} [options.ratio=1] Gear ratio.
  3972. * @param {Number} [options.maxTorque] Maximum torque to apply.
  3973. * @extends Constraint
  3974. *
  3975. * @example
  3976. * var constraint = new GearConstraint(bodyA, bodyB);
  3977. * world.addConstraint(constraint);
  3978. *
  3979. * @example
  3980. * var constraint = new GearConstraint(bodyA, bodyB, {
  3981. * ratio: 2,
  3982. * maxTorque: 1000
  3983. * });
  3984. * world.addConstraint(constraint);
  3985. */
  3986. function GearConstraint(bodyA, bodyB, options){
  3987. options = options || {};
  3988. Constraint.call(this, bodyA, bodyB, Constraint.GEAR, options);
  3989. /**
  3990. * The gear ratio.
  3991. * @property ratio
  3992. * @type {Number}
  3993. */
  3994. this.ratio = options.ratio !== undefined ? options.ratio : 1;
  3995. /**
  3996. * The relative angle
  3997. * @property angle
  3998. * @type {Number}
  3999. */
  4000. this.angle = options.angle !== undefined ? options.angle : bodyB.angle - this.ratio * bodyA.angle;
  4001. // Send same parameters to the equation
  4002. options.angle = this.angle;
  4003. options.ratio = this.ratio;
  4004. this.equations = [
  4005. new AngleLockEquation(bodyA,bodyB,options),
  4006. ];
  4007. // Set max torque
  4008. if(options.maxTorque !== undefined){
  4009. this.setMaxTorque(options.maxTorque);
  4010. }
  4011. }
  4012. GearConstraint.prototype = new Constraint();
  4013. GearConstraint.prototype.constructor = GearConstraint;
  4014. GearConstraint.prototype.update = function(){
  4015. var eq = this.equations[0];
  4016. if(eq.ratio !== this.ratio){
  4017. eq.setRatio(this.ratio);
  4018. }
  4019. eq.angle = this.angle;
  4020. };
  4021. /**
  4022. * Set the max torque for the constraint.
  4023. * @method setMaxTorque
  4024. * @param {Number} torque
  4025. */
  4026. GearConstraint.prototype.setMaxTorque = function(torque){
  4027. this.equations[0].setMaxTorque(torque);
  4028. };
  4029. /**
  4030. * Get the max torque for the constraint.
  4031. * @method getMaxTorque
  4032. * @return {Number}
  4033. */
  4034. GearConstraint.prototype.getMaxTorque = function(torque){
  4035. return this.equations[0].maxForce;
  4036. };
  4037. },{"../equations/AngleLockEquation":20,"../equations/Equation":22,"../math/vec2":30,"./Constraint":14}],17:[function(_dereq_,module,exports){
  4038. var Constraint = _dereq_('./Constraint')
  4039. , vec2 = _dereq_('../math/vec2')
  4040. , Equation = _dereq_('../equations/Equation');
  4041. module.exports = LockConstraint;
  4042. /**
  4043. * Locks the relative position and rotation between two bodies.
  4044. *
  4045. * @class LockConstraint
  4046. * @constructor
  4047. * @author schteppe
  4048. * @param {Body} bodyA
  4049. * @param {Body} bodyB
  4050. * @param {Object} [options]
  4051. * @param {Array} [options.localOffsetB] The offset of bodyB in bodyA's frame. If not given the offset is computed from current positions.
  4052. * @param {number} [options.localAngleB] The angle of bodyB in bodyA's frame. If not given, the angle is computed from current angles.
  4053. * @param {number} [options.maxForce]
  4054. * @extends Constraint
  4055. *
  4056. * @example
  4057. * // Locks the relative position and rotation between bodyA and bodyB
  4058. * var constraint = new LockConstraint(bodyA, bodyB);
  4059. * world.addConstraint(constraint);
  4060. */
  4061. function LockConstraint(bodyA, bodyB, options){
  4062. options = options || {};
  4063. Constraint.call(this,bodyA,bodyB,Constraint.LOCK,options);
  4064. var maxForce = ( typeof(options.maxForce)==="undefined" ? Number.MAX_VALUE : options.maxForce );
  4065. var localAngleB = options.localAngleB || 0;
  4066. // Use 3 equations:
  4067. // gx = (xj - xi - l) * xhat = 0
  4068. // gy = (xj - xi - l) * yhat = 0
  4069. // gr = (xi - xj + r) * that = 0
  4070. //
  4071. // ...where:
  4072. // l is the localOffsetB vector rotated to world in bodyA frame
  4073. // r is the same vector but reversed and rotated from bodyB frame
  4074. // xhat, yhat are world axis vectors
  4075. // that is the tangent of r
  4076. //
  4077. // For the first two constraints, we get
  4078. // G*W = (vj - vi - ldot ) * xhat
  4079. // = (vj - vi - wi x l) * xhat
  4080. //
  4081. // Since (wi x l) * xhat = (l x xhat) * wi, we get
  4082. // G*W = [ -1 0 (-l x xhat) 1 0 0] * [vi wi vj wj]
  4083. //
  4084. // The last constraint gives
  4085. // GW = (vi - vj + wj x r) * that
  4086. // = [ that 0 -that (r x t) ]
  4087. var x = new Equation(bodyA,bodyB,-maxForce,maxForce),
  4088. y = new Equation(bodyA,bodyB,-maxForce,maxForce),
  4089. rot = new Equation(bodyA,bodyB,-maxForce,maxForce);
  4090. var l = vec2.create(),
  4091. g = vec2.create(),
  4092. that = this;
  4093. x.computeGq = function(){
  4094. vec2.rotate(l, that.localOffsetB, bodyA.angle);
  4095. vec2.sub(g, bodyB.position, bodyA.position);
  4096. vec2.sub(g, g, l);
  4097. return g[0];
  4098. };
  4099. y.computeGq = function(){
  4100. vec2.rotate(l, that.localOffsetB, bodyA.angle);
  4101. vec2.sub(g, bodyB.position, bodyA.position);
  4102. vec2.sub(g, g, l);
  4103. return g[1];
  4104. };
  4105. var r = vec2.create(),
  4106. t = vec2.create();
  4107. rot.computeGq = function(){
  4108. vec2.rotate(r, that.localOffsetB, bodyB.angle - that.localAngleB);
  4109. vec2.scale(r,r,-1);
  4110. vec2.sub(g,bodyA.position,bodyB.position);
  4111. vec2.add(g,g,r);
  4112. vec2.rotate(t,r,-Math.PI/2);
  4113. vec2.normalize(t,t);
  4114. return vec2.dot(g,t);
  4115. };
  4116. /**
  4117. * The offset of bodyB in bodyA's frame.
  4118. * @property {Array} localOffsetB
  4119. */
  4120. this.localOffsetB = vec2.create();
  4121. if(options.localOffsetB){
  4122. vec2.copy(this.localOffsetB, options.localOffsetB);
  4123. } else {
  4124. // Construct from current positions
  4125. vec2.sub(this.localOffsetB, bodyB.position, bodyA.position);
  4126. vec2.rotate(this.localOffsetB, this.localOffsetB, -bodyA.angle);
  4127. }
  4128. /**
  4129. * The offset angle of bodyB in bodyA's frame.
  4130. * @property {Number} localAngleB
  4131. */
  4132. this.localAngleB = 0;
  4133. if(typeof(options.localAngleB) === 'number'){
  4134. this.localAngleB = options.localAngleB;
  4135. } else {
  4136. // Construct
  4137. this.localAngleB = bodyB.angle - bodyA.angle;
  4138. }
  4139. this.equations.push(x, y, rot);
  4140. this.setMaxForce(maxForce);
  4141. }
  4142. LockConstraint.prototype = new Constraint();
  4143. LockConstraint.prototype.constructor = LockConstraint;
  4144. /**
  4145. * Set the maximum force to be applied.
  4146. * @method setMaxForce
  4147. * @param {Number} force
  4148. */
  4149. LockConstraint.prototype.setMaxForce = function(force){
  4150. var eqs = this.equations;
  4151. for(var i=0; i<this.equations.length; i++){
  4152. eqs[i].maxForce = force;
  4153. eqs[i].minForce = -force;
  4154. }
  4155. };
  4156. /**
  4157. * Get the max force.
  4158. * @method getMaxForce
  4159. * @return {Number}
  4160. */
  4161. LockConstraint.prototype.getMaxForce = function(){
  4162. return this.equations[0].maxForce;
  4163. };
  4164. var l = vec2.create();
  4165. var r = vec2.create();
  4166. var t = vec2.create();
  4167. var xAxis = vec2.fromValues(1,0);
  4168. var yAxis = vec2.fromValues(0,1);
  4169. LockConstraint.prototype.update = function(){
  4170. var x = this.equations[0],
  4171. y = this.equations[1],
  4172. rot = this.equations[2],
  4173. bodyA = this.bodyA,
  4174. bodyB = this.bodyB;
  4175. vec2.rotate(l,this.localOffsetB,bodyA.angle);
  4176. vec2.rotate(r,this.localOffsetB,bodyB.angle - this.localAngleB);
  4177. vec2.scale(r,r,-1);
  4178. vec2.rotate(t,r,Math.PI/2);
  4179. vec2.normalize(t,t);
  4180. x.G[0] = -1;
  4181. x.G[1] = 0;
  4182. x.G[2] = -vec2.crossLength(l,xAxis);
  4183. x.G[3] = 1;
  4184. y.G[0] = 0;
  4185. y.G[1] = -1;
  4186. y.G[2] = -vec2.crossLength(l,yAxis);
  4187. y.G[4] = 1;
  4188. rot.G[0] = -t[0];
  4189. rot.G[1] = -t[1];
  4190. rot.G[3] = t[0];
  4191. rot.G[4] = t[1];
  4192. rot.G[5] = vec2.crossLength(r,t);
  4193. };
  4194. },{"../equations/Equation":22,"../math/vec2":30,"./Constraint":14}],18:[function(_dereq_,module,exports){
  4195. var Constraint = _dereq_('./Constraint')
  4196. , ContactEquation = _dereq_('../equations/ContactEquation')
  4197. , Equation = _dereq_('../equations/Equation')
  4198. , vec2 = _dereq_('../math/vec2')
  4199. , RotationalLockEquation = _dereq_('../equations/RotationalLockEquation');
  4200. module.exports = PrismaticConstraint;
  4201. /**
  4202. * Constraint that only allows bodies to move along a line, relative to each other. See <a href="http://www.iforce2d.net/b2dtut/joints-prismatic">this tutorial</a>. Also called "slider constraint".
  4203. *
  4204. * @class PrismaticConstraint
  4205. * @constructor
  4206. * @extends Constraint
  4207. * @author schteppe
  4208. * @param {Body} bodyA
  4209. * @param {Body} bodyB
  4210. * @param {Object} [options]
  4211. * @param {Number} [options.maxForce] Max force to be applied by the constraint
  4212. * @param {Array} [options.localAnchorA] Body A's anchor point, defined in its own local frame.
  4213. * @param {Array} [options.localAnchorB] Body B's anchor point, defined in its own local frame.
  4214. * @param {Array} [options.localAxisA] An axis, defined in body A frame, that body B's anchor point may slide along.
  4215. * @param {Boolean} [options.disableRotationalLock] If set to true, bodyB will be free to rotate around its anchor point.
  4216. * @param {Number} [options.upperLimit]
  4217. * @param {Number} [options.lowerLimit]
  4218. * @todo Ability to create using only a point and a worldAxis
  4219. */
  4220. function PrismaticConstraint(bodyA, bodyB, options){
  4221. options = options || {};
  4222. Constraint.call(this,bodyA,bodyB,Constraint.PRISMATIC,options);
  4223. // Get anchors
  4224. var localAnchorA = vec2.fromValues(0,0),
  4225. localAxisA = vec2.fromValues(1,0),
  4226. localAnchorB = vec2.fromValues(0,0);
  4227. if(options.localAnchorA){ vec2.copy(localAnchorA, options.localAnchorA); }
  4228. if(options.localAxisA){ vec2.copy(localAxisA, options.localAxisA); }
  4229. if(options.localAnchorB){ vec2.copy(localAnchorB, options.localAnchorB); }
  4230. /**
  4231. * @property localAnchorA
  4232. * @type {Array}
  4233. */
  4234. this.localAnchorA = localAnchorA;
  4235. /**
  4236. * @property localAnchorB
  4237. * @type {Array}
  4238. */
  4239. this.localAnchorB = localAnchorB;
  4240. /**
  4241. * @property localAxisA
  4242. * @type {Array}
  4243. */
  4244. this.localAxisA = localAxisA;
  4245. /*
  4246. The constraint violation for the common axis point is
  4247. g = ( xj + rj - xi - ri ) * t := gg*t
  4248. where r are body-local anchor points, and t is a tangent to the constraint axis defined in body i frame.
  4249. gdot = ( vj + wj x rj - vi - wi x ri ) * t + ( xj + rj - xi - ri ) * ( wi x t )
  4250. Note the use of the chain rule. Now we identify the jacobian
  4251. G*W = [ -t -ri x t + t x gg t rj x t ] * [vi wi vj wj]
  4252. The rotational part is just a rotation lock.
  4253. */
  4254. var maxForce = this.maxForce = typeof(options.maxForce)!=="undefined" ? options.maxForce : Number.MAX_VALUE;
  4255. // Translational part
  4256. var trans = new Equation(bodyA,bodyB,-maxForce,maxForce);
  4257. var ri = new vec2.create(),
  4258. rj = new vec2.create(),
  4259. gg = new vec2.create(),
  4260. t = new vec2.create();
  4261. trans.computeGq = function(){
  4262. // g = ( xj + rj - xi - ri ) * t
  4263. return vec2.dot(gg,t);
  4264. };
  4265. trans.updateJacobian = function(){
  4266. var G = this.G,
  4267. xi = bodyA.position,
  4268. xj = bodyB.position;
  4269. vec2.rotate(ri,localAnchorA,bodyA.angle);
  4270. vec2.rotate(rj,localAnchorB,bodyB.angle);
  4271. vec2.add(gg,xj,rj);
  4272. vec2.sub(gg,gg,xi);
  4273. vec2.sub(gg,gg,ri);
  4274. vec2.rotate(t,localAxisA,bodyA.angle+Math.PI/2);
  4275. G[0] = -t[0];
  4276. G[1] = -t[1];
  4277. G[2] = -vec2.crossLength(ri,t) + vec2.crossLength(t,gg);
  4278. G[3] = t[0];
  4279. G[4] = t[1];
  4280. G[5] = vec2.crossLength(rj,t);
  4281. };
  4282. this.equations.push(trans);
  4283. // Rotational part
  4284. if(!options.disableRotationalLock){
  4285. var rot = new RotationalLockEquation(bodyA,bodyB,-maxForce,maxForce);
  4286. this.equations.push(rot);
  4287. }
  4288. /**
  4289. * The position of anchor A relative to anchor B, along the constraint axis.
  4290. * @property position
  4291. * @type {Number}
  4292. */
  4293. this.position = 0;
  4294. // Is this one used at all?
  4295. this.velocity = 0;
  4296. /**
  4297. * Set to true to enable lower limit.
  4298. * @property lowerLimitEnabled
  4299. * @type {Boolean}
  4300. */
  4301. this.lowerLimitEnabled = typeof(options.lowerLimit)!=="undefined" ? true : false;
  4302. /**
  4303. * Set to true to enable upper limit.
  4304. * @property upperLimitEnabled
  4305. * @type {Boolean}
  4306. */
  4307. this.upperLimitEnabled = typeof(options.upperLimit)!=="undefined" ? true : false;
  4308. /**
  4309. * Lower constraint limit. The constraint position is forced to be larger than this value.
  4310. * @property lowerLimit
  4311. * @type {Number}
  4312. */
  4313. this.lowerLimit = typeof(options.lowerLimit)!=="undefined" ? options.lowerLimit : 0;
  4314. /**
  4315. * Upper constraint limit. The constraint position is forced to be smaller than this value.
  4316. * @property upperLimit
  4317. * @type {Number}
  4318. */
  4319. this.upperLimit = typeof(options.upperLimit)!=="undefined" ? options.upperLimit : 1;
  4320. // Equations used for limits
  4321. this.upperLimitEquation = new ContactEquation(bodyA,bodyB);
  4322. this.lowerLimitEquation = new ContactEquation(bodyA,bodyB);
  4323. // Set max/min forces
  4324. this.upperLimitEquation.minForce = this.lowerLimitEquation.minForce = 0;
  4325. this.upperLimitEquation.maxForce = this.lowerLimitEquation.maxForce = maxForce;
  4326. /**
  4327. * Equation used for the motor.
  4328. * @property motorEquation
  4329. * @type {Equation}
  4330. */
  4331. this.motorEquation = new Equation(bodyA,bodyB);
  4332. /**
  4333. * The current motor state. Enable or disable the motor using .enableMotor
  4334. * @property motorEnabled
  4335. * @type {Boolean}
  4336. */
  4337. this.motorEnabled = false;
  4338. /**
  4339. * Set the target speed for the motor.
  4340. * @property motorSpeed
  4341. * @type {Number}
  4342. */
  4343. this.motorSpeed = 0;
  4344. var that = this;
  4345. var motorEquation = this.motorEquation;
  4346. var old = motorEquation.computeGW;
  4347. motorEquation.computeGq = function(){ return 0; };
  4348. motorEquation.computeGW = function(){
  4349. var G = this.G,
  4350. bi = this.bodyA,
  4351. bj = this.bodyB,
  4352. vi = bi.velocity,
  4353. vj = bj.velocity,
  4354. wi = bi.angularVelocity,
  4355. wj = bj.angularVelocity;
  4356. return this.gmult(G,vi,wi,vj,wj) + that.motorSpeed;
  4357. };
  4358. }
  4359. PrismaticConstraint.prototype = new Constraint();
  4360. PrismaticConstraint.prototype.constructor = PrismaticConstraint;
  4361. var worldAxisA = vec2.create(),
  4362. worldAnchorA = vec2.create(),
  4363. worldAnchorB = vec2.create(),
  4364. orientedAnchorA = vec2.create(),
  4365. orientedAnchorB = vec2.create(),
  4366. tmp = vec2.create();
  4367. /**
  4368. * Update the constraint equations. Should be done if any of the bodies changed position, before solving.
  4369. * @method update
  4370. */
  4371. PrismaticConstraint.prototype.update = function(){
  4372. var eqs = this.equations,
  4373. trans = eqs[0],
  4374. upperLimit = this.upperLimit,
  4375. lowerLimit = this.lowerLimit,
  4376. upperLimitEquation = this.upperLimitEquation,
  4377. lowerLimitEquation = this.lowerLimitEquation,
  4378. bodyA = this.bodyA,
  4379. bodyB = this.bodyB,
  4380. localAxisA = this.localAxisA,
  4381. localAnchorA = this.localAnchorA,
  4382. localAnchorB = this.localAnchorB;
  4383. trans.updateJacobian();
  4384. // Transform local things to world
  4385. vec2.rotate(worldAxisA, localAxisA, bodyA.angle);
  4386. vec2.rotate(orientedAnchorA, localAnchorA, bodyA.angle);
  4387. vec2.add(worldAnchorA, orientedAnchorA, bodyA.position);
  4388. vec2.rotate(orientedAnchorB, localAnchorB, bodyB.angle);
  4389. vec2.add(worldAnchorB, orientedAnchorB, bodyB.position);
  4390. var relPosition = this.position = vec2.dot(worldAnchorB,worldAxisA) - vec2.dot(worldAnchorA,worldAxisA);
  4391. // Motor
  4392. if(this.motorEnabled){
  4393. // G = [ a a x ri -a -a x rj ]
  4394. var G = this.motorEquation.G;
  4395. G[0] = worldAxisA[0];
  4396. G[1] = worldAxisA[1];
  4397. G[2] = vec2.crossLength(worldAxisA,orientedAnchorB);
  4398. G[3] = -worldAxisA[0];
  4399. G[4] = -worldAxisA[1];
  4400. G[5] = -vec2.crossLength(worldAxisA,orientedAnchorA);
  4401. }
  4402. /*
  4403. Limits strategy:
  4404. Add contact equation, with normal along the constraint axis.
  4405. min/maxForce is set so the constraint is repulsive in the correct direction.
  4406. Some offset is added to either equation.contactPointA or .contactPointB to get the correct upper/lower limit.
  4407. ^
  4408. |
  4409. upperLimit x
  4410. | ------
  4411. anchorB x<---| B |
  4412. | | |
  4413. ------ | ------
  4414. | | |
  4415. | A |-->x anchorA
  4416. ------ |
  4417. x lowerLimit
  4418. |
  4419. axis
  4420. */
  4421. if(this.upperLimitEnabled && relPosition > upperLimit){
  4422. // Update contact constraint normal, etc
  4423. vec2.scale(upperLimitEquation.normalA, worldAxisA, -1);
  4424. vec2.sub(upperLimitEquation.contactPointA, worldAnchorA, bodyA.position);
  4425. vec2.sub(upperLimitEquation.contactPointB, worldAnchorB, bodyB.position);
  4426. vec2.scale(tmp,worldAxisA,upperLimit);
  4427. vec2.add(upperLimitEquation.contactPointA,upperLimitEquation.contactPointA,tmp);
  4428. if(eqs.indexOf(upperLimitEquation) === -1){
  4429. eqs.push(upperLimitEquation);
  4430. }
  4431. } else {
  4432. var idx = eqs.indexOf(upperLimitEquation);
  4433. if(idx !== -1){
  4434. eqs.splice(idx,1);
  4435. }
  4436. }
  4437. if(this.lowerLimitEnabled && relPosition < lowerLimit){
  4438. // Update contact constraint normal, etc
  4439. vec2.scale(lowerLimitEquation.normalA, worldAxisA, 1);
  4440. vec2.sub(lowerLimitEquation.contactPointA, worldAnchorA, bodyA.position);
  4441. vec2.sub(lowerLimitEquation.contactPointB, worldAnchorB, bodyB.position);
  4442. vec2.scale(tmp,worldAxisA,lowerLimit);
  4443. vec2.sub(lowerLimitEquation.contactPointB,lowerLimitEquation.contactPointB,tmp);
  4444. if(eqs.indexOf(lowerLimitEquation) === -1){
  4445. eqs.push(lowerLimitEquation);
  4446. }
  4447. } else {
  4448. var idx = eqs.indexOf(lowerLimitEquation);
  4449. if(idx !== -1){
  4450. eqs.splice(idx,1);
  4451. }
  4452. }
  4453. };
  4454. /**
  4455. * Enable the motor
  4456. * @method enableMotor
  4457. */
  4458. PrismaticConstraint.prototype.enableMotor = function(){
  4459. if(this.motorEnabled){
  4460. return;
  4461. }
  4462. this.equations.push(this.motorEquation);
  4463. this.motorEnabled = true;
  4464. };
  4465. /**
  4466. * Disable the rotational motor
  4467. * @method disableMotor
  4468. */
  4469. PrismaticConstraint.prototype.disableMotor = function(){
  4470. if(!this.motorEnabled){
  4471. return;
  4472. }
  4473. var i = this.equations.indexOf(this.motorEquation);
  4474. this.equations.splice(i,1);
  4475. this.motorEnabled = false;
  4476. };
  4477. /**
  4478. * Set the constraint limits.
  4479. * @method setLimits
  4480. * @param {number} lower Lower limit.
  4481. * @param {number} upper Upper limit.
  4482. */
  4483. PrismaticConstraint.prototype.setLimits = function (lower, upper) {
  4484. if(typeof(lower) === 'number'){
  4485. this.lowerLimit = lower;
  4486. this.lowerLimitEnabled = true;
  4487. } else {
  4488. this.lowerLimit = lower;
  4489. this.lowerLimitEnabled = false;
  4490. }
  4491. if(typeof(upper) === 'number'){
  4492. this.upperLimit = upper;
  4493. this.upperLimitEnabled = true;
  4494. } else {
  4495. this.upperLimit = upper;
  4496. this.upperLimitEnabled = false;
  4497. }
  4498. };
  4499. },{"../equations/ContactEquation":21,"../equations/Equation":22,"../equations/RotationalLockEquation":24,"../math/vec2":30,"./Constraint":14}],19:[function(_dereq_,module,exports){
  4500. var Constraint = _dereq_('./Constraint')
  4501. , Equation = _dereq_('../equations/Equation')
  4502. , RotationalVelocityEquation = _dereq_('../equations/RotationalVelocityEquation')
  4503. , RotationalLockEquation = _dereq_('../equations/RotationalLockEquation')
  4504. , vec2 = _dereq_('../math/vec2');
  4505. module.exports = RevoluteConstraint;
  4506. var worldPivotA = vec2.create(),
  4507. worldPivotB = vec2.create(),
  4508. xAxis = vec2.fromValues(1,0),
  4509. yAxis = vec2.fromValues(0,1),
  4510. g = vec2.create();
  4511. /**
  4512. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  4513. * @class RevoluteConstraint
  4514. * @constructor
  4515. * @author schteppe
  4516. * @param {Body} bodyA
  4517. * @param {Body} bodyB
  4518. * @param {Object} [options]
  4519. * @param {Array} [options.worldPivot] A pivot point given in world coordinates. If specified, localPivotA and localPivotB are automatically computed from this value.
  4520. * @param {Array} [options.localPivotA] The point relative to the center of mass of bodyA which bodyA is constrained to.
  4521. * @param {Array} [options.localPivotB] See localPivotA.
  4522. * @param {Number} [options.maxForce] The maximum force that should be applied to constrain the bodies.
  4523. * @extends Constraint
  4524. *
  4525. * @example
  4526. * // This will create a revolute constraint between two bodies with pivot point in between them.
  4527. * var bodyA = new Body({ mass: 1, position: [-1, 0] });
  4528. * var bodyB = new Body({ mass: 1, position: [1, 0] });
  4529. * var constraint = new RevoluteConstraint(bodyA, bodyB, {
  4530. * worldPivot: [0, 0]
  4531. * });
  4532. * world.addConstraint(constraint);
  4533. *
  4534. * // Using body-local pivot points, the constraint could have been constructed like this:
  4535. * var constraint = new RevoluteConstraint(bodyA, bodyB, {
  4536. * localPivotA: [1, 0],
  4537. * localPivotB: [-1, 0]
  4538. * });
  4539. */
  4540. function RevoluteConstraint(bodyA, bodyB, options){
  4541. options = options || {};
  4542. Constraint.call(this,bodyA,bodyB,Constraint.REVOLUTE,options);
  4543. var maxForce = this.maxForce = typeof(options.maxForce) !== "undefined" ? options.maxForce : Number.MAX_VALUE;
  4544. /**
  4545. * @property {Array} pivotA
  4546. */
  4547. this.pivotA = vec2.create();
  4548. /**
  4549. * @property {Array} pivotB
  4550. */
  4551. this.pivotB = vec2.create();
  4552. if(options.worldPivot){
  4553. // Compute pivotA and pivotB
  4554. vec2.sub(this.pivotA, options.worldPivot, bodyA.position);
  4555. vec2.sub(this.pivotB, options.worldPivot, bodyB.position);
  4556. // Rotate to local coordinate system
  4557. vec2.rotate(this.pivotA, this.pivotA, -bodyA.angle);
  4558. vec2.rotate(this.pivotB, this.pivotB, -bodyB.angle);
  4559. } else {
  4560. // Get pivotA and pivotB
  4561. vec2.copy(this.pivotA, options.localPivotA);
  4562. vec2.copy(this.pivotB, options.localPivotB);
  4563. }
  4564. // Equations to be fed to the solver
  4565. var eqs = this.equations = [
  4566. new Equation(bodyA,bodyB,-maxForce,maxForce),
  4567. new Equation(bodyA,bodyB,-maxForce,maxForce),
  4568. ];
  4569. var x = eqs[0];
  4570. var y = eqs[1];
  4571. var that = this;
  4572. x.computeGq = function(){
  4573. vec2.rotate(worldPivotA, that.pivotA, bodyA.angle);
  4574. vec2.rotate(worldPivotB, that.pivotB, bodyB.angle);
  4575. vec2.add(g, bodyB.position, worldPivotB);
  4576. vec2.sub(g, g, bodyA.position);
  4577. vec2.sub(g, g, worldPivotA);
  4578. return vec2.dot(g,xAxis);
  4579. };
  4580. y.computeGq = function(){
  4581. vec2.rotate(worldPivotA, that.pivotA, bodyA.angle);
  4582. vec2.rotate(worldPivotB, that.pivotB, bodyB.angle);
  4583. vec2.add(g, bodyB.position, worldPivotB);
  4584. vec2.sub(g, g, bodyA.position);
  4585. vec2.sub(g, g, worldPivotA);
  4586. return vec2.dot(g,yAxis);
  4587. };
  4588. y.minForce = x.minForce = -maxForce;
  4589. y.maxForce = x.maxForce = maxForce;
  4590. this.motorEquation = new RotationalVelocityEquation(bodyA,bodyB);
  4591. /**
  4592. * Indicates whether the motor is enabled. Use .enableMotor() to enable the constraint motor.
  4593. * @property {Boolean} motorEnabled
  4594. * @readOnly
  4595. */
  4596. this.motorEnabled = false;
  4597. /**
  4598. * The constraint position.
  4599. * @property angle
  4600. * @type {Number}
  4601. * @readOnly
  4602. */
  4603. this.angle = 0;
  4604. /**
  4605. * Set to true to enable lower limit
  4606. * @property lowerLimitEnabled
  4607. * @type {Boolean}
  4608. */
  4609. this.lowerLimitEnabled = false;
  4610. /**
  4611. * Set to true to enable upper limit
  4612. * @property upperLimitEnabled
  4613. * @type {Boolean}
  4614. */
  4615. this.upperLimitEnabled = false;
  4616. /**
  4617. * The lower limit on the constraint angle.
  4618. * @property lowerLimit
  4619. * @type {Boolean}
  4620. */
  4621. this.lowerLimit = 0;
  4622. /**
  4623. * The upper limit on the constraint angle.
  4624. * @property upperLimit
  4625. * @type {Boolean}
  4626. */
  4627. this.upperLimit = 0;
  4628. this.upperLimitEquation = new RotationalLockEquation(bodyA,bodyB);
  4629. this.lowerLimitEquation = new RotationalLockEquation(bodyA,bodyB);
  4630. this.upperLimitEquation.minForce = 0;
  4631. this.lowerLimitEquation.maxForce = 0;
  4632. }
  4633. RevoluteConstraint.prototype = new Constraint();
  4634. RevoluteConstraint.prototype.constructor = RevoluteConstraint;
  4635. /**
  4636. * Set the constraint angle limits.
  4637. * @method setLimits
  4638. * @param {number} lower Lower angle limit.
  4639. * @param {number} upper Upper angle limit.
  4640. */
  4641. RevoluteConstraint.prototype.setLimits = function (lower, upper) {
  4642. if(typeof(lower) === 'number'){
  4643. this.lowerLimit = lower;
  4644. this.lowerLimitEnabled = true;
  4645. } else {
  4646. this.lowerLimit = lower;
  4647. this.lowerLimitEnabled = false;
  4648. }
  4649. if(typeof(upper) === 'number'){
  4650. this.upperLimit = upper;
  4651. this.upperLimitEnabled = true;
  4652. } else {
  4653. this.upperLimit = upper;
  4654. this.upperLimitEnabled = false;
  4655. }
  4656. };
  4657. RevoluteConstraint.prototype.update = function(){
  4658. var bodyA = this.bodyA,
  4659. bodyB = this.bodyB,
  4660. pivotA = this.pivotA,
  4661. pivotB = this.pivotB,
  4662. eqs = this.equations,
  4663. normal = eqs[0],
  4664. tangent= eqs[1],
  4665. x = eqs[0],
  4666. y = eqs[1],
  4667. upperLimit = this.upperLimit,
  4668. lowerLimit = this.lowerLimit,
  4669. upperLimitEquation = this.upperLimitEquation,
  4670. lowerLimitEquation = this.lowerLimitEquation;
  4671. var relAngle = this.angle = bodyB.angle - bodyA.angle;
  4672. if(this.upperLimitEnabled && relAngle > upperLimit){
  4673. upperLimitEquation.angle = upperLimit;
  4674. if(eqs.indexOf(upperLimitEquation) === -1){
  4675. eqs.push(upperLimitEquation);
  4676. }
  4677. } else {
  4678. var idx = eqs.indexOf(upperLimitEquation);
  4679. if(idx !== -1){
  4680. eqs.splice(idx,1);
  4681. }
  4682. }
  4683. if(this.lowerLimitEnabled && relAngle < lowerLimit){
  4684. lowerLimitEquation.angle = lowerLimit;
  4685. if(eqs.indexOf(lowerLimitEquation) === -1){
  4686. eqs.push(lowerLimitEquation);
  4687. }
  4688. } else {
  4689. var idx = eqs.indexOf(lowerLimitEquation);
  4690. if(idx !== -1){
  4691. eqs.splice(idx,1);
  4692. }
  4693. }
  4694. /*
  4695. The constraint violation is
  4696. g = xj + rj - xi - ri
  4697. ...where xi and xj are the body positions and ri and rj world-oriented offset vectors. Differentiate:
  4698. gdot = vj + wj x rj - vi - wi x ri
  4699. We split this into x and y directions. (let x and y be unit vectors along the respective axes)
  4700. gdot * x = ( vj + wj x rj - vi - wi x ri ) * x
  4701. = ( vj*x + (wj x rj)*x -vi*x -(wi x ri)*x
  4702. = ( vj*x + (rj x x)*wj -vi*x -(ri x x)*wi
  4703. = [ -x -(ri x x) x (rj x x)] * [vi wi vj wj]
  4704. = G*W
  4705. ...and similar for y. We have then identified the jacobian entries for x and y directions:
  4706. Gx = [ x (rj x x) -x -(ri x x)]
  4707. Gy = [ y (rj x y) -y -(ri x y)]
  4708. */
  4709. vec2.rotate(worldPivotA, pivotA, bodyA.angle);
  4710. vec2.rotate(worldPivotB, pivotB, bodyB.angle);
  4711. // todo: these are a bit sparse. We could save some computations on making custom eq.computeGW functions, etc
  4712. x.G[0] = -1;
  4713. x.G[1] = 0;
  4714. x.G[2] = -vec2.crossLength(worldPivotA,xAxis);
  4715. x.G[3] = 1;
  4716. x.G[4] = 0;
  4717. x.G[5] = vec2.crossLength(worldPivotB,xAxis);
  4718. y.G[0] = 0;
  4719. y.G[1] = -1;
  4720. y.G[2] = -vec2.crossLength(worldPivotA,yAxis);
  4721. y.G[3] = 0;
  4722. y.G[4] = 1;
  4723. y.G[5] = vec2.crossLength(worldPivotB,yAxis);
  4724. };
  4725. /**
  4726. * Enable the rotational motor
  4727. * @method enableMotor
  4728. */
  4729. RevoluteConstraint.prototype.enableMotor = function(){
  4730. if(this.motorEnabled){
  4731. return;
  4732. }
  4733. this.equations.push(this.motorEquation);
  4734. this.motorEnabled = true;
  4735. };
  4736. /**
  4737. * Disable the rotational motor
  4738. * @method disableMotor
  4739. */
  4740. RevoluteConstraint.prototype.disableMotor = function(){
  4741. if(!this.motorEnabled){
  4742. return;
  4743. }
  4744. var i = this.equations.indexOf(this.motorEquation);
  4745. this.equations.splice(i,1);
  4746. this.motorEnabled = false;
  4747. };
  4748. /**
  4749. * Check if the motor is enabled.
  4750. * @method motorIsEnabled
  4751. * @deprecated use property motorEnabled instead.
  4752. * @return {Boolean}
  4753. */
  4754. RevoluteConstraint.prototype.motorIsEnabled = function(){
  4755. return !!this.motorEnabled;
  4756. };
  4757. /**
  4758. * Set the speed of the rotational constraint motor
  4759. * @method setMotorSpeed
  4760. * @param {Number} speed
  4761. */
  4762. RevoluteConstraint.prototype.setMotorSpeed = function(speed){
  4763. if(!this.motorEnabled){
  4764. return;
  4765. }
  4766. var i = this.equations.indexOf(this.motorEquation);
  4767. this.equations[i].relativeVelocity = speed;
  4768. };
  4769. /**
  4770. * Get the speed of the rotational constraint motor
  4771. * @method getMotorSpeed
  4772. * @return {Number} The current speed, or false if the motor is not enabled.
  4773. */
  4774. RevoluteConstraint.prototype.getMotorSpeed = function(){
  4775. if(!this.motorEnabled){
  4776. return false;
  4777. }
  4778. return this.motorEquation.relativeVelocity;
  4779. };
  4780. },{"../equations/Equation":22,"../equations/RotationalLockEquation":24,"../equations/RotationalVelocityEquation":25,"../math/vec2":30,"./Constraint":14}],20:[function(_dereq_,module,exports){
  4781. var Equation = _dereq_("./Equation"),
  4782. vec2 = _dereq_('../math/vec2');
  4783. module.exports = AngleLockEquation;
  4784. /**
  4785. * Locks the relative angle between two bodies. The constraint tries to keep the dot product between two vectors, local in each body, to zero. The local angle in body i is a parameter.
  4786. *
  4787. * @class AngleLockEquation
  4788. * @constructor
  4789. * @extends Equation
  4790. * @param {Body} bodyA
  4791. * @param {Body} bodyB
  4792. * @param {Object} [options]
  4793. * @param {Number} [options.angle] Angle to add to the local vector in body A.
  4794. * @param {Number} [options.ratio] Gear ratio
  4795. */
  4796. function AngleLockEquation(bodyA, bodyB, options){
  4797. options = options || {};
  4798. Equation.call(this,bodyA,bodyB,-Number.MAX_VALUE,Number.MAX_VALUE);
  4799. this.angle = options.angle || 0;
  4800. /**
  4801. * The gear ratio.
  4802. * @property {Number} ratio
  4803. * @private
  4804. * @see setRatio
  4805. */
  4806. this.ratio = typeof(options.ratio)==="number" ? options.ratio : 1;
  4807. this.setRatio(this.ratio);
  4808. }
  4809. AngleLockEquation.prototype = new Equation();
  4810. AngleLockEquation.prototype.constructor = AngleLockEquation;
  4811. AngleLockEquation.prototype.computeGq = function(){
  4812. return this.ratio * this.bodyA.angle - this.bodyB.angle + this.angle;
  4813. };
  4814. /**
  4815. * Set the gear ratio for this equation
  4816. * @method setRatio
  4817. * @param {Number} ratio
  4818. */
  4819. AngleLockEquation.prototype.setRatio = function(ratio){
  4820. var G = this.G;
  4821. G[2] = ratio;
  4822. G[5] = -1;
  4823. this.ratio = ratio;
  4824. };
  4825. /**
  4826. * Set the max force for the equation.
  4827. * @method setMaxTorque
  4828. * @param {Number} torque
  4829. */
  4830. AngleLockEquation.prototype.setMaxTorque = function(torque){
  4831. this.maxForce = torque;
  4832. this.minForce = -torque;
  4833. };
  4834. },{"../math/vec2":30,"./Equation":22}],21:[function(_dereq_,module,exports){
  4835. var Equation = _dereq_("./Equation"),
  4836. vec2 = _dereq_('../math/vec2');
  4837. module.exports = ContactEquation;
  4838. /**
  4839. * Non-penetration constraint equation. Tries to make the contactPointA and contactPointB vectors coincide, while keeping the applied force repulsive.
  4840. *
  4841. * @class ContactEquation
  4842. * @constructor
  4843. * @extends Equation
  4844. * @param {Body} bodyA
  4845. * @param {Body} bodyB
  4846. */
  4847. function ContactEquation(bodyA, bodyB){
  4848. Equation.call(this, bodyA, bodyB, 0, Number.MAX_VALUE);
  4849. /**
  4850. * Vector from body i center of mass to the contact point.
  4851. * @property contactPointA
  4852. * @type {Array}
  4853. */
  4854. this.contactPointA = vec2.create();
  4855. this.penetrationVec = vec2.create();
  4856. /**
  4857. * World-oriented vector from body A center of mass to the contact point.
  4858. * @property contactPointB
  4859. * @type {Array}
  4860. */
  4861. this.contactPointB = vec2.create();
  4862. /**
  4863. * The normal vector, pointing out of body i
  4864. * @property normalA
  4865. * @type {Array}
  4866. */
  4867. this.normalA = vec2.create();
  4868. /**
  4869. * The restitution to use (0=no bounciness, 1=max bounciness).
  4870. * @property restitution
  4871. * @type {Number}
  4872. */
  4873. this.restitution = 0;
  4874. /**
  4875. * This property is set to true if this is the first impact between the bodies (not persistant contact).
  4876. * @property firstImpact
  4877. * @type {Boolean}
  4878. * @readOnly
  4879. */
  4880. this.firstImpact = false;
  4881. /**
  4882. * The shape in body i that triggered this contact.
  4883. * @property shapeA
  4884. * @type {Shape}
  4885. */
  4886. this.shapeA = null;
  4887. /**
  4888. * The shape in body j that triggered this contact.
  4889. * @property shapeB
  4890. * @type {Shape}
  4891. */
  4892. this.shapeB = null;
  4893. }
  4894. ContactEquation.prototype = new Equation();
  4895. ContactEquation.prototype.constructor = ContactEquation;
  4896. ContactEquation.prototype.computeB = function(a,b,h){
  4897. var bi = this.bodyA,
  4898. bj = this.bodyB,
  4899. ri = this.contactPointA,
  4900. rj = this.contactPointB,
  4901. xi = bi.position,
  4902. xj = bj.position;
  4903. var penetrationVec = this.penetrationVec,
  4904. n = this.normalA,
  4905. G = this.G;
  4906. // Caluclate cross products
  4907. var rixn = vec2.crossLength(ri,n),
  4908. rjxn = vec2.crossLength(rj,n);
  4909. // G = [-n -rixn n rjxn]
  4910. G[0] = -n[0];
  4911. G[1] = -n[1];
  4912. G[2] = -rixn;
  4913. G[3] = n[0];
  4914. G[4] = n[1];
  4915. G[5] = rjxn;
  4916. // Calculate q = xj+rj -(xi+ri) i.e. the penetration vector
  4917. vec2.add(penetrationVec,xj,rj);
  4918. vec2.sub(penetrationVec,penetrationVec,xi);
  4919. vec2.sub(penetrationVec,penetrationVec,ri);
  4920. // Compute iteration
  4921. var GW, Gq;
  4922. if(this.firstImpact && this.restitution !== 0){
  4923. Gq = 0;
  4924. GW = (1/b)*(1+this.restitution) * this.computeGW();
  4925. } else {
  4926. Gq = vec2.dot(n,penetrationVec) + this.offset;
  4927. GW = this.computeGW();
  4928. }
  4929. var GiMf = this.computeGiMf();
  4930. var B = - Gq * a - GW * b - h*GiMf;
  4931. return B;
  4932. };
  4933. var vi = vec2.create();
  4934. var vj = vec2.create();
  4935. var relVel = vec2.create();
  4936. /**
  4937. * Get the relative velocity along the normal vector.
  4938. * @return {number}
  4939. */
  4940. ContactEquation.prototype.getVelocityAlongNormal = function(){
  4941. this.bodyA.getVelocityAtPoint(vi, this.contactPointA);
  4942. this.bodyB.getVelocityAtPoint(vj, this.contactPointB);
  4943. vec2.subtract(relVel, vi, vj);
  4944. return vec2.dot(this.normalA, relVel);
  4945. };
  4946. },{"../math/vec2":30,"./Equation":22}],22:[function(_dereq_,module,exports){
  4947. module.exports = Equation;
  4948. var vec2 = _dereq_('../math/vec2'),
  4949. Utils = _dereq_('../utils/Utils'),
  4950. Body = _dereq_('../objects/Body');
  4951. /**
  4952. * Base class for constraint equations.
  4953. * @class Equation
  4954. * @constructor
  4955. * @param {Body} bodyA First body participating in the equation
  4956. * @param {Body} bodyB Second body participating in the equation
  4957. * @param {number} minForce Minimum force to apply. Default: -Number.MAX_VALUE
  4958. * @param {number} maxForce Maximum force to apply. Default: Number.MAX_VALUE
  4959. */
  4960. function Equation(bodyA, bodyB, minForce, maxForce){
  4961. /**
  4962. * Minimum force to apply when solving.
  4963. * @property minForce
  4964. * @type {Number}
  4965. */
  4966. this.minForce = typeof(minForce)==="undefined" ? -Number.MAX_VALUE : minForce;
  4967. /**
  4968. * Max force to apply when solving.
  4969. * @property maxForce
  4970. * @type {Number}
  4971. */
  4972. this.maxForce = typeof(maxForce)==="undefined" ? Number.MAX_VALUE : maxForce;
  4973. /**
  4974. * First body participating in the constraint
  4975. * @property bodyA
  4976. * @type {Body}
  4977. */
  4978. this.bodyA = bodyA;
  4979. /**
  4980. * Second body participating in the constraint
  4981. * @property bodyB
  4982. * @type {Body}
  4983. */
  4984. this.bodyB = bodyB;
  4985. /**
  4986. * The stiffness of this equation. Typically chosen to a large number (~1e7), but can be chosen somewhat freely to get a stable simulation.
  4987. * @property stiffness
  4988. * @type {Number}
  4989. */
  4990. this.stiffness = Equation.DEFAULT_STIFFNESS;
  4991. /**
  4992. * The number of time steps needed to stabilize the constraint equation. Typically between 3 and 5 time steps.
  4993. * @property relaxation
  4994. * @type {Number}
  4995. */
  4996. this.relaxation = Equation.DEFAULT_RELAXATION;
  4997. /**
  4998. * The Jacobian entry of this equation. 6 numbers, 3 per body (x,y,angle).
  4999. * @property G
  5000. * @type {Array}
  5001. */
  5002. this.G = new Utils.ARRAY_TYPE(6);
  5003. for(var i=0; i<6; i++){
  5004. this.G[i]=0;
  5005. }
  5006. this.offset = 0;
  5007. this.a = 0;
  5008. this.b = 0;
  5009. this.epsilon = 0;
  5010. this.timeStep = 1/60;
  5011. /**
  5012. * Indicates if stiffness or relaxation was changed.
  5013. * @property {Boolean} needsUpdate
  5014. */
  5015. this.needsUpdate = true;
  5016. /**
  5017. * The resulting constraint multiplier from the last solve. This is mostly equivalent to the force produced by the constraint.
  5018. * @property multiplier
  5019. * @type {Number}
  5020. */
  5021. this.multiplier = 0;
  5022. /**
  5023. * Relative velocity.
  5024. * @property {Number} relativeVelocity
  5025. */
  5026. this.relativeVelocity = 0;
  5027. /**
  5028. * Whether this equation is enabled or not. If true, it will be added to the solver.
  5029. * @property {Boolean} enabled
  5030. */
  5031. this.enabled = true;
  5032. }
  5033. Equation.prototype.constructor = Equation;
  5034. /**
  5035. * The default stiffness when creating a new Equation.
  5036. * @static
  5037. * @property {Number} DEFAULT_STIFFNESS
  5038. * @default 1e6
  5039. */
  5040. Equation.DEFAULT_STIFFNESS = 1e6;
  5041. /**
  5042. * The default relaxation when creating a new Equation.
  5043. * @static
  5044. * @property {Number} DEFAULT_RELAXATION
  5045. * @default 4
  5046. */
  5047. Equation.DEFAULT_RELAXATION = 4;
  5048. /**
  5049. * Compute SPOOK parameters .a, .b and .epsilon according to the current parameters. See equations 9, 10 and 11 in the <a href="http://www8.cs.umu.se/kurser/5DV058/VT09/lectures/spooknotes.pdf">SPOOK notes</a>.
  5050. * @method update
  5051. */
  5052. Equation.prototype.update = function(){
  5053. var k = this.stiffness,
  5054. d = this.relaxation,
  5055. h = this.timeStep;
  5056. this.a = 4.0 / (h * (1 + 4 * d));
  5057. this.b = (4.0 * d) / (1 + 4 * d);
  5058. this.epsilon = 4.0 / (h * h * k * (1 + 4 * d));
  5059. this.needsUpdate = false;
  5060. };
  5061. /**
  5062. * Multiply a jacobian entry with corresponding positions or velocities
  5063. * @method gmult
  5064. * @return {Number}
  5065. */
  5066. Equation.prototype.gmult = function(G,vi,wi,vj,wj){
  5067. return G[0] * vi[0] +
  5068. G[1] * vi[1] +
  5069. G[2] * wi +
  5070. G[3] * vj[0] +
  5071. G[4] * vj[1] +
  5072. G[5] * wj;
  5073. };
  5074. /**
  5075. * Computes the RHS of the SPOOK equation
  5076. * @method computeB
  5077. * @return {Number}
  5078. */
  5079. Equation.prototype.computeB = function(a,b,h){
  5080. var GW = this.computeGW();
  5081. var Gq = this.computeGq();
  5082. var GiMf = this.computeGiMf();
  5083. return - Gq * a - GW * b - GiMf*h;
  5084. };
  5085. /**
  5086. * Computes G\*q, where q are the generalized body coordinates
  5087. * @method computeGq
  5088. * @return {Number}
  5089. */
  5090. var qi = vec2.create(),
  5091. qj = vec2.create();
  5092. Equation.prototype.computeGq = function(){
  5093. var G = this.G,
  5094. bi = this.bodyA,
  5095. bj = this.bodyB,
  5096. xi = bi.position,
  5097. xj = bj.position,
  5098. ai = bi.angle,
  5099. aj = bj.angle;
  5100. return this.gmult(G, qi, ai, qj, aj) + this.offset;
  5101. };
  5102. /**
  5103. * Computes G\*W, where W are the body velocities
  5104. * @method computeGW
  5105. * @return {Number}
  5106. */
  5107. Equation.prototype.computeGW = function(){
  5108. var G = this.G,
  5109. bi = this.bodyA,
  5110. bj = this.bodyB,
  5111. vi = bi.velocity,
  5112. vj = bj.velocity,
  5113. wi = bi.angularVelocity,
  5114. wj = bj.angularVelocity;
  5115. return this.gmult(G,vi,wi,vj,wj) + this.relativeVelocity;
  5116. };
  5117. /**
  5118. * Computes G\*Wlambda, where W are the body velocities
  5119. * @method computeGWlambda
  5120. * @return {Number}
  5121. */
  5122. Equation.prototype.computeGWlambda = function(){
  5123. var G = this.G,
  5124. bi = this.bodyA,
  5125. bj = this.bodyB,
  5126. vi = bi.vlambda,
  5127. vj = bj.vlambda,
  5128. wi = bi.wlambda,
  5129. wj = bj.wlambda;
  5130. return this.gmult(G,vi,wi,vj,wj);
  5131. };
  5132. /**
  5133. * Computes G\*inv(M)\*f, where M is the mass matrix with diagonal blocks for each body, and f are the forces on the bodies.
  5134. * @method computeGiMf
  5135. * @return {Number}
  5136. */
  5137. var iMfi = vec2.create(),
  5138. iMfj = vec2.create();
  5139. Equation.prototype.computeGiMf = function(){
  5140. var bi = this.bodyA,
  5141. bj = this.bodyB,
  5142. fi = bi.force,
  5143. ti = bi.angularForce,
  5144. fj = bj.force,
  5145. tj = bj.angularForce,
  5146. invMassi = bi.invMassSolve,
  5147. invMassj = bj.invMassSolve,
  5148. invIi = bi.invInertiaSolve,
  5149. invIj = bj.invInertiaSolve,
  5150. G = this.G;
  5151. vec2.scale(iMfi, fi, invMassi);
  5152. vec2.multiply(iMfi, bi.massMultiplier, iMfi);
  5153. vec2.scale(iMfj, fj,invMassj);
  5154. vec2.multiply(iMfj, bj.massMultiplier, iMfj);
  5155. return this.gmult(G,iMfi,ti*invIi,iMfj,tj*invIj);
  5156. };
  5157. /**
  5158. * Computes G\*inv(M)\*G'
  5159. * @method computeGiMGt
  5160. * @return {Number}
  5161. */
  5162. Equation.prototype.computeGiMGt = function(){
  5163. var bi = this.bodyA,
  5164. bj = this.bodyB,
  5165. invMassi = bi.invMassSolve,
  5166. invMassj = bj.invMassSolve,
  5167. invIi = bi.invInertiaSolve,
  5168. invIj = bj.invInertiaSolve,
  5169. G = this.G;
  5170. return G[0] * G[0] * invMassi * bi.massMultiplier[0] +
  5171. G[1] * G[1] * invMassi * bi.massMultiplier[1] +
  5172. G[2] * G[2] * invIi +
  5173. G[3] * G[3] * invMassj * bj.massMultiplier[0] +
  5174. G[4] * G[4] * invMassj * bj.massMultiplier[1] +
  5175. G[5] * G[5] * invIj;
  5176. };
  5177. var addToWlambda_temp = vec2.create(),
  5178. addToWlambda_Gi = vec2.create(),
  5179. addToWlambda_Gj = vec2.create(),
  5180. addToWlambda_ri = vec2.create(),
  5181. addToWlambda_rj = vec2.create(),
  5182. addToWlambda_Mdiag = vec2.create();
  5183. /**
  5184. * Add constraint velocity to the bodies.
  5185. * @method addToWlambda
  5186. * @param {Number} deltalambda
  5187. */
  5188. Equation.prototype.addToWlambda = function(deltalambda){
  5189. var bi = this.bodyA,
  5190. bj = this.bodyB,
  5191. temp = addToWlambda_temp,
  5192. Gi = addToWlambda_Gi,
  5193. Gj = addToWlambda_Gj,
  5194. ri = addToWlambda_ri,
  5195. rj = addToWlambda_rj,
  5196. invMassi = bi.invMassSolve,
  5197. invMassj = bj.invMassSolve,
  5198. invIi = bi.invInertiaSolve,
  5199. invIj = bj.invInertiaSolve,
  5200. Mdiag = addToWlambda_Mdiag,
  5201. G = this.G;
  5202. Gi[0] = G[0];
  5203. Gi[1] = G[1];
  5204. Gj[0] = G[3];
  5205. Gj[1] = G[4];
  5206. // Add to linear velocity
  5207. // v_lambda += inv(M) * delta_lamba * G
  5208. vec2.scale(temp, Gi, invMassi*deltalambda);
  5209. vec2.multiply(temp, temp, bi.massMultiplier);
  5210. vec2.add( bi.vlambda, bi.vlambda, temp);
  5211. // This impulse is in the offset frame
  5212. // Also add contribution to angular
  5213. //bi.wlambda -= vec2.crossLength(temp,ri);
  5214. bi.wlambda += invIi * G[2] * deltalambda;
  5215. vec2.scale(temp, Gj, invMassj*deltalambda);
  5216. vec2.multiply(temp, temp, bj.massMultiplier);
  5217. vec2.add( bj.vlambda, bj.vlambda, temp);
  5218. //bj.wlambda -= vec2.crossLength(temp,rj);
  5219. bj.wlambda += invIj * G[5] * deltalambda;
  5220. };
  5221. /**
  5222. * Compute the denominator part of the SPOOK equation: C = G\*inv(M)\*G' + eps
  5223. * @method computeInvC
  5224. * @param {Number} eps
  5225. * @return {Number}
  5226. */
  5227. Equation.prototype.computeInvC = function(eps){
  5228. return 1.0 / (this.computeGiMGt() + eps);
  5229. };
  5230. },{"../math/vec2":30,"../objects/Body":31,"../utils/Utils":57}],23:[function(_dereq_,module,exports){
  5231. var vec2 = _dereq_('../math/vec2')
  5232. , Equation = _dereq_('./Equation')
  5233. , Utils = _dereq_('../utils/Utils');
  5234. module.exports = FrictionEquation;
  5235. /**
  5236. * Constrains the slipping in a contact along a tangent
  5237. *
  5238. * @class FrictionEquation
  5239. * @constructor
  5240. * @param {Body} bodyA
  5241. * @param {Body} bodyB
  5242. * @param {Number} slipForce
  5243. * @extends Equation
  5244. */
  5245. function FrictionEquation(bodyA, bodyB, slipForce){
  5246. Equation.call(this, bodyA, bodyB, -slipForce, slipForce);
  5247. /**
  5248. * Relative vector from center of body A to the contact point, world oriented.
  5249. * @property contactPointA
  5250. * @type {Array}
  5251. */
  5252. this.contactPointA = vec2.create();
  5253. /**
  5254. * Relative vector from center of body B to the contact point, world oriented.
  5255. * @property contactPointB
  5256. * @type {Array}
  5257. */
  5258. this.contactPointB = vec2.create();
  5259. /**
  5260. * Tangent vector that the friction force will act along. World oriented.
  5261. * @property t
  5262. * @type {Array}
  5263. */
  5264. this.t = vec2.create();
  5265. /**
  5266. * ContactEquations connected to this friction equation. The contact equations can be used to rescale the max force for the friction. If more than one contact equation is given, then the max force can be set to the average.
  5267. * @property contactEquations
  5268. * @type {ContactEquation}
  5269. */
  5270. this.contactEquations = [];
  5271. /**
  5272. * The shape in body i that triggered this friction.
  5273. * @property shapeA
  5274. * @type {Shape}
  5275. * @todo Needed? The shape can be looked up via contactEquation.shapeA...
  5276. */
  5277. this.shapeA = null;
  5278. /**
  5279. * The shape in body j that triggered this friction.
  5280. * @property shapeB
  5281. * @type {Shape}
  5282. * @todo Needed? The shape can be looked up via contactEquation.shapeB...
  5283. */
  5284. this.shapeB = null;
  5285. /**
  5286. * The friction coefficient to use.
  5287. * @property frictionCoefficient
  5288. * @type {Number}
  5289. */
  5290. this.frictionCoefficient = 0.3;
  5291. }
  5292. FrictionEquation.prototype = new Equation();
  5293. FrictionEquation.prototype.constructor = FrictionEquation;
  5294. /**
  5295. * Set the slipping condition for the constraint. The friction force cannot be
  5296. * larger than this value.
  5297. * @method setSlipForce
  5298. * @param {Number} slipForce
  5299. */
  5300. FrictionEquation.prototype.setSlipForce = function(slipForce){
  5301. this.maxForce = slipForce;
  5302. this.minForce = -slipForce;
  5303. };
  5304. /**
  5305. * Get the max force for the constraint.
  5306. * @method getSlipForce
  5307. * @return {Number}
  5308. */
  5309. FrictionEquation.prototype.getSlipForce = function(){
  5310. return this.maxForce;
  5311. };
  5312. FrictionEquation.prototype.computeB = function(a,b,h){
  5313. var bi = this.bodyA,
  5314. bj = this.bodyB,
  5315. ri = this.contactPointA,
  5316. rj = this.contactPointB,
  5317. t = this.t,
  5318. G = this.G;
  5319. // G = [-t -rixt t rjxt]
  5320. // And remember, this is a pure velocity constraint, g is always zero!
  5321. G[0] = -t[0];
  5322. G[1] = -t[1];
  5323. G[2] = -vec2.crossLength(ri,t);
  5324. G[3] = t[0];
  5325. G[4] = t[1];
  5326. G[5] = vec2.crossLength(rj,t);
  5327. var GW = this.computeGW(),
  5328. GiMf = this.computeGiMf();
  5329. var B = /* - g * a */ - GW * b - h*GiMf;
  5330. return B;
  5331. };
  5332. },{"../math/vec2":30,"../utils/Utils":57,"./Equation":22}],24:[function(_dereq_,module,exports){
  5333. var Equation = _dereq_("./Equation"),
  5334. vec2 = _dereq_('../math/vec2');
  5335. module.exports = RotationalLockEquation;
  5336. /**
  5337. * Locks the relative angle between two bodies. The constraint tries to keep the dot product between two vectors, local in each body, to zero. The local angle in body i is a parameter.
  5338. *
  5339. * @class RotationalLockEquation
  5340. * @constructor
  5341. * @extends Equation
  5342. * @param {Body} bodyA
  5343. * @param {Body} bodyB
  5344. * @param {Object} [options]
  5345. * @param {Number} [options.angle] Angle to add to the local vector in bodyA.
  5346. */
  5347. function RotationalLockEquation(bodyA, bodyB, options){
  5348. options = options || {};
  5349. Equation.call(this, bodyA, bodyB, -Number.MAX_VALUE, Number.MAX_VALUE);
  5350. /**
  5351. * @property {number} angle
  5352. */
  5353. this.angle = options.angle || 0;
  5354. var G = this.G;
  5355. G[2] = 1;
  5356. G[5] = -1;
  5357. }
  5358. RotationalLockEquation.prototype = new Equation();
  5359. RotationalLockEquation.prototype.constructor = RotationalLockEquation;
  5360. var worldVectorA = vec2.create(),
  5361. worldVectorB = vec2.create(),
  5362. xAxis = vec2.fromValues(1,0),
  5363. yAxis = vec2.fromValues(0,1);
  5364. RotationalLockEquation.prototype.computeGq = function(){
  5365. vec2.rotate(worldVectorA,xAxis,this.bodyA.angle+this.angle);
  5366. vec2.rotate(worldVectorB,yAxis,this.bodyB.angle);
  5367. return vec2.dot(worldVectorA,worldVectorB);
  5368. };
  5369. },{"../math/vec2":30,"./Equation":22}],25:[function(_dereq_,module,exports){
  5370. var Equation = _dereq_("./Equation"),
  5371. vec2 = _dereq_('../math/vec2');
  5372. module.exports = RotationalVelocityEquation;
  5373. /**
  5374. * Syncs rotational velocity of two bodies, or sets a relative velocity (motor).
  5375. *
  5376. * @class RotationalVelocityEquation
  5377. * @constructor
  5378. * @extends Equation
  5379. * @param {Body} bodyA
  5380. * @param {Body} bodyB
  5381. */
  5382. function RotationalVelocityEquation(bodyA, bodyB){
  5383. Equation.call(this, bodyA, bodyB, -Number.MAX_VALUE, Number.MAX_VALUE);
  5384. this.relativeVelocity = 1;
  5385. this.ratio = 1;
  5386. }
  5387. RotationalVelocityEquation.prototype = new Equation();
  5388. RotationalVelocityEquation.prototype.constructor = RotationalVelocityEquation;
  5389. RotationalVelocityEquation.prototype.computeB = function(a,b,h){
  5390. var G = this.G;
  5391. G[2] = -1;
  5392. G[5] = this.ratio;
  5393. var GiMf = this.computeGiMf();
  5394. var GW = this.computeGW();
  5395. var B = - GW * b - h*GiMf;
  5396. return B;
  5397. };
  5398. },{"../math/vec2":30,"./Equation":22}],26:[function(_dereq_,module,exports){
  5399. /**
  5400. * Base class for objects that dispatches events.
  5401. * @class EventEmitter
  5402. * @constructor
  5403. */
  5404. var EventEmitter = function () {};
  5405. module.exports = EventEmitter;
  5406. EventEmitter.prototype = {
  5407. constructor: EventEmitter,
  5408. /**
  5409. * Add an event listener
  5410. * @method on
  5411. * @param {String} type
  5412. * @param {Function} listener
  5413. * @return {EventEmitter} The self object, for chainability.
  5414. */
  5415. on: function ( type, listener, context ) {
  5416. listener.context = context || this;
  5417. if ( this._listeners === undefined ){
  5418. this._listeners = {};
  5419. }
  5420. var listeners = this._listeners;
  5421. if ( listeners[ type ] === undefined ) {
  5422. listeners[ type ] = [];
  5423. }
  5424. if ( listeners[ type ].indexOf( listener ) === - 1 ) {
  5425. listeners[ type ].push( listener );
  5426. }
  5427. return this;
  5428. },
  5429. /**
  5430. * Check if an event listener is added
  5431. * @method has
  5432. * @param {String} type
  5433. * @param {Function} listener
  5434. * @return {Boolean}
  5435. */
  5436. has: function ( type, listener ) {
  5437. if ( this._listeners === undefined ){
  5438. return false;
  5439. }
  5440. var listeners = this._listeners;
  5441. if(listener){
  5442. if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {
  5443. return true;
  5444. }
  5445. } else {
  5446. if ( listeners[ type ] !== undefined ) {
  5447. return true;
  5448. }
  5449. }
  5450. return false;
  5451. },
  5452. /**
  5453. * Remove an event listener
  5454. * @method off
  5455. * @param {String} type
  5456. * @param {Function} listener
  5457. * @return {EventEmitter} The self object, for chainability.
  5458. */
  5459. off: function ( type, listener ) {
  5460. if ( this._listeners === undefined ){
  5461. return this;
  5462. }
  5463. var listeners = this._listeners;
  5464. var index = listeners[ type ].indexOf( listener );
  5465. if ( index !== - 1 ) {
  5466. listeners[ type ].splice( index, 1 );
  5467. }
  5468. return this;
  5469. },
  5470. /**
  5471. * Emit an event.
  5472. * @method emit
  5473. * @param {Object} event
  5474. * @param {String} event.type
  5475. * @return {EventEmitter} The self object, for chainability.
  5476. */
  5477. emit: function ( event ) {
  5478. if ( this._listeners === undefined ){
  5479. return this;
  5480. }
  5481. var listeners = this._listeners;
  5482. var listenerArray = listeners[ event.type ];
  5483. if ( listenerArray !== undefined ) {
  5484. event.target = this;
  5485. for ( var i = 0, l = listenerArray.length; i < l; i ++ ) {
  5486. var listener = listenerArray[ i ];
  5487. listener.call( listener.context, event );
  5488. }
  5489. }
  5490. return this;
  5491. }
  5492. };
  5493. },{}],27:[function(_dereq_,module,exports){
  5494. var Material = _dereq_('./Material');
  5495. var Equation = _dereq_('../equations/Equation');
  5496. module.exports = ContactMaterial;
  5497. /**
  5498. * Defines what happens when two materials meet, such as what friction coefficient to use. You can also set other things such as restitution, surface velocity and constraint parameters.
  5499. * @class ContactMaterial
  5500. * @constructor
  5501. * @param {Material} materialA
  5502. * @param {Material} materialB
  5503. * @param {Object} [options]
  5504. * @param {Number} [options.friction=0.3] Friction coefficient.
  5505. * @param {Number} [options.restitution=0] Restitution coefficient aka "bounciness".
  5506. * @param {Number} [options.stiffness] ContactEquation stiffness.
  5507. * @param {Number} [options.relaxation] ContactEquation relaxation.
  5508. * @param {Number} [options.frictionStiffness] FrictionEquation stiffness.
  5509. * @param {Number} [options.frictionRelaxation] FrictionEquation relaxation.
  5510. * @param {Number} [options.surfaceVelocity=0] Surface velocity.
  5511. * @author schteppe
  5512. */
  5513. function ContactMaterial(materialA, materialB, options){
  5514. options = options || {};
  5515. if(!(materialA instanceof Material) || !(materialB instanceof Material)){
  5516. throw new Error("First two arguments must be Material instances.");
  5517. }
  5518. /**
  5519. * The contact material identifier
  5520. * @property id
  5521. * @type {Number}
  5522. */
  5523. this.id = ContactMaterial.idCounter++;
  5524. /**
  5525. * First material participating in the contact material
  5526. * @property materialA
  5527. * @type {Material}
  5528. */
  5529. this.materialA = materialA;
  5530. /**
  5531. * Second material participating in the contact material
  5532. * @property materialB
  5533. * @type {Material}
  5534. */
  5535. this.materialB = materialB;
  5536. /**
  5537. * Friction coefficient to use in the contact of these two materials. Friction = 0 will make the involved objects super slippery, and friction = 1 will make it much less slippery. A friction coefficient larger than 1 will allow for very large friction forces, which can be convenient for preventing car tires not slip on the ground.
  5538. * @property friction
  5539. * @type {Number}
  5540. * @default 0.3
  5541. */
  5542. this.friction = typeof(options.friction) !== "undefined" ? Number(options.friction) : 0.3;
  5543. /**
  5544. * Restitution, or "bounciness" to use in the contact of these two materials. A restitution of 0 will make no bounce, while restitution=1 will approximately bounce back with the same velocity the object came with.
  5545. * @property restitution
  5546. * @type {Number}
  5547. * @default 0
  5548. */
  5549. this.restitution = typeof(options.restitution) !== "undefined" ? Number(options.restitution) : 0;
  5550. /**
  5551. * Hardness of the contact. Less stiffness will make the objects penetrate more, and will make the contact act more like a spring than a contact force. Default value is {{#crossLink "Equation/DEFAULT_STIFFNESS:property"}}Equation.DEFAULT_STIFFNESS{{/crossLink}}.
  5552. * @property stiffness
  5553. * @type {Number}
  5554. */
  5555. this.stiffness = typeof(options.stiffness) !== "undefined" ? Number(options.stiffness) : Equation.DEFAULT_STIFFNESS;
  5556. /**
  5557. * Relaxation of the resulting ContactEquation that this ContactMaterial generate. Default value is {{#crossLink "Equation/DEFAULT_RELAXATION:property"}}Equation.DEFAULT_RELAXATION{{/crossLink}}.
  5558. * @property relaxation
  5559. * @type {Number}
  5560. */
  5561. this.relaxation = typeof(options.relaxation) !== "undefined" ? Number(options.relaxation) : Equation.DEFAULT_RELAXATION;
  5562. /**
  5563. * Stiffness of the resulting friction force. For most cases, the value of this property should be a large number. I cannot think of any case where you would want less frictionStiffness. Default value is {{#crossLink "Equation/DEFAULT_STIFFNESS:property"}}Equation.DEFAULT_STIFFNESS{{/crossLink}}.
  5564. * @property frictionStiffness
  5565. * @type {Number}
  5566. */
  5567. this.frictionStiffness = typeof(options.frictionStiffness) !== "undefined" ? Number(options.frictionStiffness) : Equation.DEFAULT_STIFFNESS;
  5568. /**
  5569. * Relaxation of the resulting friction force. The default value should be good for most simulations. Default value is {{#crossLink "Equation/DEFAULT_RELAXATION:property"}}Equation.DEFAULT_RELAXATION{{/crossLink}}.
  5570. * @property frictionRelaxation
  5571. * @type {Number}
  5572. */
  5573. this.frictionRelaxation = typeof(options.frictionRelaxation) !== "undefined" ? Number(options.frictionRelaxation) : Equation.DEFAULT_RELAXATION;
  5574. /**
  5575. * Will add surface velocity to this material. If bodyA rests on top if bodyB, and the surface velocity is positive, bodyA will slide to the right.
  5576. * @property {Number} surfaceVelocity
  5577. * @default 0
  5578. */
  5579. this.surfaceVelocity = typeof(options.surfaceVelocity) !== "undefined" ? Number(options.surfaceVelocity) : 0;
  5580. /**
  5581. * Offset to be set on ContactEquations. A positive value will make the bodies penetrate more into each other. Can be useful in scenes where contacts need to be more persistent, for example when stacking. Aka "cure for nervous contacts".
  5582. * @property contactSkinSize
  5583. * @type {Number}
  5584. */
  5585. this.contactSkinSize = 0.005;
  5586. }
  5587. ContactMaterial.idCounter = 0;
  5588. },{"../equations/Equation":22,"./Material":28}],28:[function(_dereq_,module,exports){
  5589. module.exports = Material;
  5590. /**
  5591. * Defines a physics material.
  5592. * @class Material
  5593. * @constructor
  5594. * @param {number} id Material identifier
  5595. * @author schteppe
  5596. */
  5597. function Material(id){
  5598. /**
  5599. * The material identifier
  5600. * @property id
  5601. * @type {Number}
  5602. */
  5603. this.id = id || Material.idCounter++;
  5604. }
  5605. Material.idCounter = 0;
  5606. },{}],29:[function(_dereq_,module,exports){
  5607. /*
  5608. PolyK library
  5609. url: http://polyk.ivank.net
  5610. Released under MIT licence.
  5611. Copyright (c) 2012 Ivan Kuckir
  5612. Permission is hereby granted, free of charge, to any person
  5613. obtaining a copy of this software and associated documentation
  5614. files (the "Software"), to deal in the Software without
  5615. restriction, including without limitation the rights to use,
  5616. copy, modify, merge, publish, distribute, sublicense, and/or sell
  5617. copies of the Software, and to permit persons to whom the
  5618. Software is furnished to do so, subject to the following
  5619. conditions:
  5620. The above copyright notice and this permission notice shall be
  5621. included in all copies or substantial portions of the Software.
  5622. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  5623. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  5624. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  5625. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  5626. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  5627. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  5628. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  5629. OTHER DEALINGS IN THE SOFTWARE.
  5630. */
  5631. var PolyK = {};
  5632. /*
  5633. Is Polygon self-intersecting?
  5634. O(n^2)
  5635. */
  5636. /*
  5637. PolyK.IsSimple = function(p)
  5638. {
  5639. var n = p.length>>1;
  5640. if(n<4) return true;
  5641. var a1 = new PolyK._P(), a2 = new PolyK._P();
  5642. var b1 = new PolyK._P(), b2 = new PolyK._P();
  5643. var c = new PolyK._P();
  5644. for(var i=0; i<n; i++)
  5645. {
  5646. a1.x = p[2*i ];
  5647. a1.y = p[2*i+1];
  5648. if(i==n-1) { a2.x = p[0 ]; a2.y = p[1 ]; }
  5649. else { a2.x = p[2*i+2]; a2.y = p[2*i+3]; }
  5650. for(var j=0; j<n; j++)
  5651. {
  5652. if(Math.abs(i-j) < 2) continue;
  5653. if(j==n-1 && i==0) continue;
  5654. if(i==n-1 && j==0) continue;
  5655. b1.x = p[2*j ];
  5656. b1.y = p[2*j+1];
  5657. if(j==n-1) { b2.x = p[0 ]; b2.y = p[1 ]; }
  5658. else { b2.x = p[2*j+2]; b2.y = p[2*j+3]; }
  5659. if(PolyK._GetLineIntersection(a1,a2,b1,b2,c) != null) return false;
  5660. }
  5661. }
  5662. return true;
  5663. }
  5664. PolyK.IsConvex = function(p)
  5665. {
  5666. if(p.length<6) return true;
  5667. var l = p.length - 4;
  5668. for(var i=0; i<l; i+=2)
  5669. if(!PolyK._convex(p[i], p[i+1], p[i+2], p[i+3], p[i+4], p[i+5])) return false;
  5670. if(!PolyK._convex(p[l ], p[l+1], p[l+2], p[l+3], p[0], p[1])) return false;
  5671. if(!PolyK._convex(p[l+2], p[l+3], p[0 ], p[1 ], p[2], p[3])) return false;
  5672. return true;
  5673. }
  5674. */
  5675. PolyK.GetArea = function(p)
  5676. {
  5677. if(p.length <6) return 0;
  5678. var l = p.length - 2;
  5679. var sum = 0;
  5680. for(var i=0; i<l; i+=2)
  5681. sum += (p[i+2]-p[i]) * (p[i+1]+p[i+3]);
  5682. sum += (p[0]-p[l]) * (p[l+1]+p[1]);
  5683. return - sum * 0.5;
  5684. }
  5685. /*
  5686. PolyK.GetAABB = function(p)
  5687. {
  5688. var minx = Infinity;
  5689. var miny = Infinity;
  5690. var maxx = -minx;
  5691. var maxy = -miny;
  5692. for(var i=0; i<p.length; i+=2)
  5693. {
  5694. minx = Math.min(minx, p[i ]);
  5695. maxx = Math.max(maxx, p[i ]);
  5696. miny = Math.min(miny, p[i+1]);
  5697. maxy = Math.max(maxy, p[i+1]);
  5698. }
  5699. return {x:minx, y:miny, width:maxx-minx, height:maxy-miny};
  5700. }
  5701. */
  5702. PolyK.Triangulate = function(p)
  5703. {
  5704. var n = p.length>>1;
  5705. if(n<3) return [];
  5706. var tgs = [];
  5707. var avl = [];
  5708. for(var i=0; i<n; i++) avl.push(i);
  5709. var i = 0;
  5710. var al = n;
  5711. while(al > 3)
  5712. {
  5713. var i0 = avl[(i+0)%al];
  5714. var i1 = avl[(i+1)%al];
  5715. var i2 = avl[(i+2)%al];
  5716. var ax = p[2*i0], ay = p[2*i0+1];
  5717. var bx = p[2*i1], by = p[2*i1+1];
  5718. var cx = p[2*i2], cy = p[2*i2+1];
  5719. var earFound = false;
  5720. if(PolyK._convex(ax, ay, bx, by, cx, cy))
  5721. {
  5722. earFound = true;
  5723. for(var j=0; j<al; j++)
  5724. {
  5725. var vi = avl[j];
  5726. if(vi==i0 || vi==i1 || vi==i2) continue;
  5727. if(PolyK._PointInTriangle(p[2*vi], p[2*vi+1], ax, ay, bx, by, cx, cy)) {earFound = false; break;}
  5728. }
  5729. }
  5730. if(earFound)
  5731. {
  5732. tgs.push(i0, i1, i2);
  5733. avl.splice((i+1)%al, 1);
  5734. al--;
  5735. i= 0;
  5736. }
  5737. else if(i++ > 3*al) break; // no convex angles :(
  5738. }
  5739. tgs.push(avl[0], avl[1], avl[2]);
  5740. return tgs;
  5741. }
  5742. /*
  5743. PolyK.ContainsPoint = function(p, px, py)
  5744. {
  5745. var n = p.length>>1;
  5746. var ax, ay, bx = p[2*n-2]-px, by = p[2*n-1]-py;
  5747. var depth = 0;
  5748. for(var i=0; i<n; i++)
  5749. {
  5750. ax = bx; ay = by;
  5751. bx = p[2*i ] - px;
  5752. by = p[2*i+1] - py;
  5753. if(ay< 0 && by< 0) continue; // both "up" or both "donw"
  5754. if(ay>=0 && by>=0) continue; // both "up" or both "donw"
  5755. if(ax< 0 && bx< 0) continue;
  5756. var lx = ax + (bx-ax)*(-ay)/(by-ay);
  5757. if(lx>0) depth++;
  5758. }
  5759. return (depth & 1) == 1;
  5760. }
  5761. PolyK.Slice = function(p, ax, ay, bx, by)
  5762. {
  5763. if(PolyK.ContainsPoint(p, ax, ay) || PolyK.ContainsPoint(p, bx, by)) return [p.slice(0)];
  5764. var a = new PolyK._P(ax, ay);
  5765. var b = new PolyK._P(bx, by);
  5766. var iscs = []; // intersections
  5767. var ps = []; // points
  5768. for(var i=0; i<p.length; i+=2) ps.push(new PolyK._P(p[i], p[i+1]));
  5769. for(var i=0; i<ps.length; i++)
  5770. {
  5771. var isc = new PolyK._P(0,0);
  5772. isc = PolyK._GetLineIntersection(a, b, ps[i], ps[(i+1)%ps.length], isc);
  5773. if(isc)
  5774. {
  5775. isc.flag = true;
  5776. iscs.push(isc);
  5777. ps.splice(i+1,0,isc);
  5778. i++;
  5779. }
  5780. }
  5781. if(iscs.length == 0) return [p.slice(0)];
  5782. var comp = function(u,v) {return PolyK._P.dist(a,u) - PolyK._P.dist(a,v); }
  5783. iscs.sort(comp);
  5784. var pgs = [];
  5785. var dir = 0;
  5786. while(iscs.length > 0)
  5787. {
  5788. var n = ps.length;
  5789. var i0 = iscs[0];
  5790. var i1 = iscs[1];
  5791. var ind0 = ps.indexOf(i0);
  5792. var ind1 = ps.indexOf(i1);
  5793. var solved = false;
  5794. if(PolyK._firstWithFlag(ps, ind0) == ind1) solved = true;
  5795. else
  5796. {
  5797. i0 = iscs[1];
  5798. i1 = iscs[0];
  5799. ind0 = ps.indexOf(i0);
  5800. ind1 = ps.indexOf(i1);
  5801. if(PolyK._firstWithFlag(ps, ind0) == ind1) solved = true;
  5802. }
  5803. if(solved)
  5804. {
  5805. dir--;
  5806. var pgn = PolyK._getPoints(ps, ind0, ind1);
  5807. pgs.push(pgn);
  5808. ps = PolyK._getPoints(ps, ind1, ind0);
  5809. i0.flag = i1.flag = false;
  5810. iscs.splice(0,2);
  5811. if(iscs.length == 0) pgs.push(ps);
  5812. }
  5813. else { dir++; iscs.reverse(); }
  5814. if(dir>1) break;
  5815. }
  5816. var result = [];
  5817. for(var i=0; i<pgs.length; i++)
  5818. {
  5819. var pg = pgs[i];
  5820. var npg = [];
  5821. for(var j=0; j<pg.length; j++) npg.push(pg[j].x, pg[j].y);
  5822. result.push(npg);
  5823. }
  5824. return result;
  5825. }
  5826. PolyK.Raycast = function(p, x, y, dx, dy, isc)
  5827. {
  5828. var l = p.length - 2;
  5829. var tp = PolyK._tp;
  5830. var a1 = tp[0], a2 = tp[1],
  5831. b1 = tp[2], b2 = tp[3], c = tp[4];
  5832. a1.x = x; a1.y = y;
  5833. a2.x = x+dx; a2.y = y+dy;
  5834. if(isc==null) isc = {dist:0, edge:0, norm:{x:0, y:0}, refl:{x:0, y:0}};
  5835. isc.dist = Infinity;
  5836. for(var i=0; i<l; i+=2)
  5837. {
  5838. b1.x = p[i ]; b1.y = p[i+1];
  5839. b2.x = p[i+2]; b2.y = p[i+3];
  5840. var nisc = PolyK._RayLineIntersection(a1, a2, b1, b2, c);
  5841. if(nisc) PolyK._updateISC(dx, dy, a1, b1, b2, c, i/2, isc);
  5842. }
  5843. b1.x = b2.x; b1.y = b2.y;
  5844. b2.x = p[0]; b2.y = p[1];
  5845. var nisc = PolyK._RayLineIntersection(a1, a2, b1, b2, c);
  5846. if(nisc) PolyK._updateISC(dx, dy, a1, b1, b2, c, p.length/2, isc);
  5847. return (isc.dist != Infinity) ? isc : null;
  5848. }
  5849. PolyK.ClosestEdge = function(p, x, y, isc)
  5850. {
  5851. var l = p.length - 2;
  5852. var tp = PolyK._tp;
  5853. var a1 = tp[0],
  5854. b1 = tp[2], b2 = tp[3], c = tp[4];
  5855. a1.x = x; a1.y = y;
  5856. if(isc==null) isc = {dist:0, edge:0, point:{x:0, y:0}, norm:{x:0, y:0}};
  5857. isc.dist = Infinity;
  5858. for(var i=0; i<l; i+=2)
  5859. {
  5860. b1.x = p[i ]; b1.y = p[i+1];
  5861. b2.x = p[i+2]; b2.y = p[i+3];
  5862. PolyK._pointLineDist(a1, b1, b2, i>>1, isc);
  5863. }
  5864. b1.x = b2.x; b1.y = b2.y;
  5865. b2.x = p[0]; b2.y = p[1];
  5866. PolyK._pointLineDist(a1, b1, b2, l>>1, isc);
  5867. var idst = 1/isc.dist;
  5868. isc.norm.x = (x-isc.point.x)*idst;
  5869. isc.norm.y = (y-isc.point.y)*idst;
  5870. return isc;
  5871. }
  5872. PolyK._pointLineDist = function(p, a, b, edge, isc)
  5873. {
  5874. var x = p.x, y = p.y, x1 = a.x, y1 = a.y, x2 = b.x, y2 = b.y;
  5875. var A = x - x1;
  5876. var B = y - y1;
  5877. var C = x2 - x1;
  5878. var D = y2 - y1;
  5879. var dot = A * C + B * D;
  5880. var len_sq = C * C + D * D;
  5881. var param = dot / len_sq;
  5882. var xx, yy;
  5883. if (param < 0 || (x1 == x2 && y1 == y2)) {
  5884. xx = x1;
  5885. yy = y1;
  5886. }
  5887. else if (param > 1) {
  5888. xx = x2;
  5889. yy = y2;
  5890. }
  5891. else {
  5892. xx = x1 + param * C;
  5893. yy = y1 + param * D;
  5894. }
  5895. var dx = x - xx;
  5896. var dy = y - yy;
  5897. var dst = Math.sqrt(dx * dx + dy * dy);
  5898. if(dst<isc.dist)
  5899. {
  5900. isc.dist = dst;
  5901. isc.edge = edge;
  5902. isc.point.x = xx;
  5903. isc.point.y = yy;
  5904. }
  5905. }
  5906. PolyK._updateISC = function(dx, dy, a1, b1, b2, c, edge, isc)
  5907. {
  5908. var nrl = PolyK._P.dist(a1, c);
  5909. if(nrl<isc.dist)
  5910. {
  5911. var ibl = 1/PolyK._P.dist(b1, b2);
  5912. var nx = -(b2.y-b1.y)*ibl;
  5913. var ny = (b2.x-b1.x)*ibl;
  5914. var ddot = 2*(dx*nx+dy*ny);
  5915. isc.dist = nrl;
  5916. isc.norm.x = nx;
  5917. isc.norm.y = ny;
  5918. isc.refl.x = -ddot*nx+dx;
  5919. isc.refl.y = -ddot*ny+dy;
  5920. isc.edge = edge;
  5921. }
  5922. }
  5923. PolyK._getPoints = function(ps, ind0, ind1)
  5924. {
  5925. var n = ps.length;
  5926. var nps = [];
  5927. if(ind1<ind0) ind1 += n;
  5928. for(var i=ind0; i<= ind1; i++) nps.push(ps[i%n]);
  5929. return nps;
  5930. }
  5931. PolyK._firstWithFlag = function(ps, ind)
  5932. {
  5933. var n = ps.length;
  5934. while(true)
  5935. {
  5936. ind = (ind+1)%n;
  5937. if(ps[ind].flag) return ind;
  5938. }
  5939. }
  5940. */
  5941. PolyK._PointInTriangle = function(px, py, ax, ay, bx, by, cx, cy)
  5942. {
  5943. var v0x = cx-ax;
  5944. var v0y = cy-ay;
  5945. var v1x = bx-ax;
  5946. var v1y = by-ay;
  5947. var v2x = px-ax;
  5948. var v2y = py-ay;
  5949. var dot00 = v0x*v0x+v0y*v0y;
  5950. var dot01 = v0x*v1x+v0y*v1y;
  5951. var dot02 = v0x*v2x+v0y*v2y;
  5952. var dot11 = v1x*v1x+v1y*v1y;
  5953. var dot12 = v1x*v2x+v1y*v2y;
  5954. var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
  5955. var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  5956. var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  5957. // Check if point is in triangle
  5958. return (u >= 0) && (v >= 0) && (u + v < 1);
  5959. }
  5960. /*
  5961. PolyK._RayLineIntersection = function(a1, a2, b1, b2, c)
  5962. {
  5963. var dax = (a1.x-a2.x), dbx = (b1.x-b2.x);
  5964. var day = (a1.y-a2.y), dby = (b1.y-b2.y);
  5965. var Den = dax*dby - day*dbx;
  5966. if (Den == 0) return null; // parallel
  5967. var A = (a1.x * a2.y - a1.y * a2.x);
  5968. var B = (b1.x * b2.y - b1.y * b2.x);
  5969. var I = c;
  5970. var iDen = 1/Den;
  5971. I.x = ( A*dbx - dax*B ) * iDen;
  5972. I.y = ( A*dby - day*B ) * iDen;
  5973. if(!PolyK._InRect(I, b1, b2)) return null;
  5974. if((day>0 && I.y>a1.y) || (day<0 && I.y<a1.y)) return null;
  5975. if((dax>0 && I.x>a1.x) || (dax<0 && I.x<a1.x)) return null;
  5976. return I;
  5977. }
  5978. PolyK._GetLineIntersection = function(a1, a2, b1, b2, c)
  5979. {
  5980. var dax = (a1.x-a2.x), dbx = (b1.x-b2.x);
  5981. var day = (a1.y-a2.y), dby = (b1.y-b2.y);
  5982. var Den = dax*dby - day*dbx;
  5983. if (Den == 0) return null; // parallel
  5984. var A = (a1.x * a2.y - a1.y * a2.x);
  5985. var B = (b1.x * b2.y - b1.y * b2.x);
  5986. var I = c;
  5987. I.x = ( A*dbx - dax*B ) / Den;
  5988. I.y = ( A*dby - day*B ) / Den;
  5989. if(PolyK._InRect(I, a1, a2) && PolyK._InRect(I, b1, b2)) return I;
  5990. return null;
  5991. }
  5992. PolyK._InRect = function(a, b, c)
  5993. {
  5994. if (b.x == c.x) return (a.y>=Math.min(b.y, c.y) && a.y<=Math.max(b.y, c.y));
  5995. if (b.y == c.y) return (a.x>=Math.min(b.x, c.x) && a.x<=Math.max(b.x, c.x));
  5996. if(a.x >= Math.min(b.x, c.x) && a.x <= Math.max(b.x, c.x)
  5997. && a.y >= Math.min(b.y, c.y) && a.y <= Math.max(b.y, c.y))
  5998. return true;
  5999. return false;
  6000. }
  6001. */
  6002. PolyK._convex = function(ax, ay, bx, by, cx, cy)
  6003. {
  6004. return (ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0;
  6005. }
  6006. /*
  6007. PolyK._P = function(x,y)
  6008. {
  6009. this.x = x;
  6010. this.y = y;
  6011. this.flag = false;
  6012. }
  6013. PolyK._P.prototype.toString = function()
  6014. {
  6015. return "Point ["+this.x+", "+this.y+"]";
  6016. }
  6017. PolyK._P.dist = function(a,b)
  6018. {
  6019. var dx = b.x-a.x;
  6020. var dy = b.y-a.y;
  6021. return Math.sqrt(dx*dx + dy*dy);
  6022. }
  6023. PolyK._tp = [];
  6024. for(var i=0; i<10; i++) PolyK._tp.push(new PolyK._P(0,0));
  6025. */
  6026. module.exports = PolyK;
  6027. },{}],30:[function(_dereq_,module,exports){
  6028. /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
  6029. Redistribution and use in source and binary forms, with or without modification,
  6030. are permitted provided that the following conditions are met:
  6031. * Redistributions of source code must retain the above copyright notice, this
  6032. list of conditions and the following disclaimer.
  6033. * Redistributions in binary form must reproduce the above copyright notice,
  6034. this list of conditions and the following disclaimer in the documentation
  6035. and/or other materials provided with the distribution.
  6036. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  6037. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  6038. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  6039. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  6040. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  6041. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  6042. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  6043. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  6044. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  6045. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  6046. /**
  6047. * The vec2 object from glMatrix, with some extensions and some removed methods. See http://glmatrix.net.
  6048. * @class vec2
  6049. */
  6050. var vec2 = module.exports = {};
  6051. var Utils = _dereq_('../utils/Utils');
  6052. /**
  6053. * Make a cross product and only return the z component
  6054. * @method crossLength
  6055. * @static
  6056. * @param {Array} a
  6057. * @param {Array} b
  6058. * @return {Number}
  6059. */
  6060. vec2.crossLength = function(a,b){
  6061. return a[0] * b[1] - a[1] * b[0];
  6062. };
  6063. /**
  6064. * Cross product between a vector and the Z component of a vector
  6065. * @method crossVZ
  6066. * @static
  6067. * @param {Array} out
  6068. * @param {Array} vec
  6069. * @param {Number} zcomp
  6070. * @return {Number}
  6071. */
  6072. vec2.crossVZ = function(out, vec, zcomp){
  6073. vec2.rotate(out,vec,-Math.PI/2);// Rotate according to the right hand rule
  6074. vec2.scale(out,out,zcomp); // Scale with z
  6075. return out;
  6076. };
  6077. /**
  6078. * Cross product between a vector and the Z component of a vector
  6079. * @method crossZV
  6080. * @static
  6081. * @param {Array} out
  6082. * @param {Number} zcomp
  6083. * @param {Array} vec
  6084. * @return {Number}
  6085. */
  6086. vec2.crossZV = function(out, zcomp, vec){
  6087. vec2.rotate(out,vec,Math.PI/2); // Rotate according to the right hand rule
  6088. vec2.scale(out,out,zcomp); // Scale with z
  6089. return out;
  6090. };
  6091. /**
  6092. * Rotate a vector by an angle
  6093. * @method rotate
  6094. * @static
  6095. * @param {Array} out
  6096. * @param {Array} a
  6097. * @param {Number} angle
  6098. */
  6099. vec2.rotate = function(out,a,angle){
  6100. if(angle !== 0){
  6101. var c = Math.cos(angle),
  6102. s = Math.sin(angle),
  6103. x = a[0],
  6104. y = a[1];
  6105. out[0] = c*x -s*y;
  6106. out[1] = s*x +c*y;
  6107. } else {
  6108. out[0] = a[0];
  6109. out[1] = a[1];
  6110. }
  6111. };
  6112. /**
  6113. * Rotate a vector 90 degrees clockwise
  6114. * @method rotate90cw
  6115. * @static
  6116. * @param {Array} out
  6117. * @param {Array} a
  6118. * @param {Number} angle
  6119. */
  6120. vec2.rotate90cw = function(out, a) {
  6121. var x = a[0];
  6122. var y = a[1];
  6123. out[0] = y;
  6124. out[1] = -x;
  6125. };
  6126. /**
  6127. * Transform a point position to local frame.
  6128. * @method toLocalFrame
  6129. * @param {Array} out
  6130. * @param {Array} worldPoint
  6131. * @param {Array} framePosition
  6132. * @param {Number} frameAngle
  6133. */
  6134. vec2.toLocalFrame = function(out, worldPoint, framePosition, frameAngle){
  6135. vec2.copy(out, worldPoint);
  6136. vec2.sub(out, out, framePosition);
  6137. vec2.rotate(out, out, -frameAngle);
  6138. };
  6139. /**
  6140. * Transform a point position to global frame.
  6141. * @method toGlobalFrame
  6142. * @param {Array} out
  6143. * @param {Array} localPoint
  6144. * @param {Array} framePosition
  6145. * @param {Number} frameAngle
  6146. */
  6147. vec2.toGlobalFrame = function(out, localPoint, framePosition, frameAngle){
  6148. vec2.copy(out, localPoint);
  6149. vec2.rotate(out, out, frameAngle);
  6150. vec2.add(out, out, framePosition);
  6151. };
  6152. /**
  6153. * Transform a vector to local frame.
  6154. * @method vectorToLocalFrame
  6155. * @param {Array} out
  6156. * @param {Array} worldVector
  6157. * @param {Number} frameAngle
  6158. */
  6159. vec2.vectorToLocalFrame = function(out, worldVector, frameAngle){
  6160. vec2.rotate(out, worldVector, -frameAngle);
  6161. };
  6162. /**
  6163. * Transform a point position to global frame.
  6164. * @method toGlobalFrame
  6165. * @param {Array} out
  6166. * @param {Array} localVector
  6167. * @param {Number} frameAngle
  6168. */
  6169. vec2.vectorToGlobalFrame = function(out, localVector, frameAngle){
  6170. vec2.rotate(out, localVector, frameAngle);
  6171. };
  6172. /**
  6173. * Compute centroid of a triangle spanned by vectors a,b,c. See http://easycalculation.com/analytical/learn-centroid.php
  6174. * @method centroid
  6175. * @static
  6176. * @param {Array} out
  6177. * @param {Array} a
  6178. * @param {Array} b
  6179. * @param {Array} c
  6180. * @return {Array} The out object
  6181. */
  6182. vec2.centroid = function(out, a, b, c){
  6183. vec2.add(out, a, b);
  6184. vec2.add(out, out, c);
  6185. vec2.scale(out, out, 1/3);
  6186. return out;
  6187. };
  6188. /**
  6189. * Creates a new, empty vec2
  6190. * @static
  6191. * @method create
  6192. * @return {Array} a new 2D vector
  6193. */
  6194. vec2.create = function() {
  6195. var out = new Utils.ARRAY_TYPE(2);
  6196. out[0] = 0;
  6197. out[1] = 0;
  6198. return out;
  6199. };
  6200. /**
  6201. * Creates a new vec2 initialized with values from an existing vector
  6202. * @static
  6203. * @method clone
  6204. * @param {Array} a vector to clone
  6205. * @return {Array} a new 2D vector
  6206. */
  6207. vec2.clone = function(a) {
  6208. var out = new Utils.ARRAY_TYPE(2);
  6209. out[0] = a[0];
  6210. out[1] = a[1];
  6211. return out;
  6212. };
  6213. /**
  6214. * Creates a new vec2 initialized with the given values
  6215. * @static
  6216. * @method fromValues
  6217. * @param {Number} x X component
  6218. * @param {Number} y Y component
  6219. * @return {Array} a new 2D vector
  6220. */
  6221. vec2.fromValues = function(x, y) {
  6222. var out = new Utils.ARRAY_TYPE(2);
  6223. out[0] = x;
  6224. out[1] = y;
  6225. return out;
  6226. };
  6227. /**
  6228. * Copy the values from one vec2 to another
  6229. * @static
  6230. * @method copy
  6231. * @param {Array} out the receiving vector
  6232. * @param {Array} a the source vector
  6233. * @return {Array} out
  6234. */
  6235. vec2.copy = function(out, a) {
  6236. out[0] = a[0];
  6237. out[1] = a[1];
  6238. return out;
  6239. };
  6240. /**
  6241. * Set the components of a vec2 to the given values
  6242. * @static
  6243. * @method set
  6244. * @param {Array} out the receiving vector
  6245. * @param {Number} x X component
  6246. * @param {Number} y Y component
  6247. * @return {Array} out
  6248. */
  6249. vec2.set = function(out, x, y) {
  6250. out[0] = x;
  6251. out[1] = y;
  6252. return out;
  6253. };
  6254. /**
  6255. * Adds two vec2's
  6256. * @static
  6257. * @method add
  6258. * @param {Array} out the receiving vector
  6259. * @param {Array} a the first operand
  6260. * @param {Array} b the second operand
  6261. * @return {Array} out
  6262. */
  6263. vec2.add = function(out, a, b) {
  6264. out[0] = a[0] + b[0];
  6265. out[1] = a[1] + b[1];
  6266. return out;
  6267. };
  6268. /**
  6269. * Subtracts two vec2's
  6270. * @static
  6271. * @method subtract
  6272. * @param {Array} out the receiving vector
  6273. * @param {Array} a the first operand
  6274. * @param {Array} b the second operand
  6275. * @return {Array} out
  6276. */
  6277. vec2.subtract = function(out, a, b) {
  6278. out[0] = a[0] - b[0];
  6279. out[1] = a[1] - b[1];
  6280. return out;
  6281. };
  6282. /**
  6283. * Alias for vec2.subtract
  6284. * @static
  6285. * @method sub
  6286. */
  6287. vec2.sub = vec2.subtract;
  6288. /**
  6289. * Multiplies two vec2's
  6290. * @static
  6291. * @method multiply
  6292. * @param {Array} out the receiving vector
  6293. * @param {Array} a the first operand
  6294. * @param {Array} b the second operand
  6295. * @return {Array} out
  6296. */
  6297. vec2.multiply = function(out, a, b) {
  6298. out[0] = a[0] * b[0];
  6299. out[1] = a[1] * b[1];
  6300. return out;
  6301. };
  6302. /**
  6303. * Alias for vec2.multiply
  6304. * @static
  6305. * @method mul
  6306. */
  6307. vec2.mul = vec2.multiply;
  6308. /**
  6309. * Divides two vec2's
  6310. * @static
  6311. * @method divide
  6312. * @param {Array} out the receiving vector
  6313. * @param {Array} a the first operand
  6314. * @param {Array} b the second operand
  6315. * @return {Array} out
  6316. */
  6317. vec2.divide = function(out, a, b) {
  6318. out[0] = a[0] / b[0];
  6319. out[1] = a[1] / b[1];
  6320. return out;
  6321. };
  6322. /**
  6323. * Alias for vec2.divide
  6324. * @static
  6325. * @method div
  6326. */
  6327. vec2.div = vec2.divide;
  6328. /**
  6329. * Scales a vec2 by a scalar number
  6330. * @static
  6331. * @method scale
  6332. * @param {Array} out the receiving vector
  6333. * @param {Array} a the vector to scale
  6334. * @param {Number} b amount to scale the vector by
  6335. * @return {Array} out
  6336. */
  6337. vec2.scale = function(out, a, b) {
  6338. out[0] = a[0] * b;
  6339. out[1] = a[1] * b;
  6340. return out;
  6341. };
  6342. /**
  6343. * Calculates the euclidian distance between two vec2's
  6344. * @static
  6345. * @method distance
  6346. * @param {Array} a the first operand
  6347. * @param {Array} b the second operand
  6348. * @return {Number} distance between a and b
  6349. */
  6350. vec2.distance = function(a, b) {
  6351. var x = b[0] - a[0],
  6352. y = b[1] - a[1];
  6353. return Math.sqrt(x*x + y*y);
  6354. };
  6355. /**
  6356. * Alias for vec2.distance
  6357. * @static
  6358. * @method dist
  6359. */
  6360. vec2.dist = vec2.distance;
  6361. /**
  6362. * Calculates the squared euclidian distance between two vec2's
  6363. * @static
  6364. * @method squaredDistance
  6365. * @param {Array} a the first operand
  6366. * @param {Array} b the second operand
  6367. * @return {Number} squared distance between a and b
  6368. */
  6369. vec2.squaredDistance = function(a, b) {
  6370. var x = b[0] - a[0],
  6371. y = b[1] - a[1];
  6372. return x*x + y*y;
  6373. };
  6374. /**
  6375. * Alias for vec2.squaredDistance
  6376. * @static
  6377. * @method sqrDist
  6378. */
  6379. vec2.sqrDist = vec2.squaredDistance;
  6380. /**
  6381. * Calculates the length of a vec2
  6382. * @static
  6383. * @method length
  6384. * @param {Array} a vector to calculate length of
  6385. * @return {Number} length of a
  6386. */
  6387. vec2.length = function (a) {
  6388. var x = a[0],
  6389. y = a[1];
  6390. return Math.sqrt(x*x + y*y);
  6391. };
  6392. /**
  6393. * Alias for vec2.length
  6394. * @method len
  6395. * @static
  6396. */
  6397. vec2.len = vec2.length;
  6398. /**
  6399. * Calculates the squared length of a vec2
  6400. * @static
  6401. * @method squaredLength
  6402. * @param {Array} a vector to calculate squared length of
  6403. * @return {Number} squared length of a
  6404. */
  6405. vec2.squaredLength = function (a) {
  6406. var x = a[0],
  6407. y = a[1];
  6408. return x*x + y*y;
  6409. };
  6410. /**
  6411. * Alias for vec2.squaredLength
  6412. * @static
  6413. * @method sqrLen
  6414. */
  6415. vec2.sqrLen = vec2.squaredLength;
  6416. /**
  6417. * Negates the components of a vec2
  6418. * @static
  6419. * @method negate
  6420. * @param {Array} out the receiving vector
  6421. * @param {Array} a vector to negate
  6422. * @return {Array} out
  6423. */
  6424. vec2.negate = function(out, a) {
  6425. out[0] = -a[0];
  6426. out[1] = -a[1];
  6427. return out;
  6428. };
  6429. /**
  6430. * Normalize a vec2
  6431. * @static
  6432. * @method normalize
  6433. * @param {Array} out the receiving vector
  6434. * @param {Array} a vector to normalize
  6435. * @return {Array} out
  6436. */
  6437. vec2.normalize = function(out, a) {
  6438. var x = a[0],
  6439. y = a[1];
  6440. var len = x*x + y*y;
  6441. if (len > 0) {
  6442. //TODO: evaluate use of glm_invsqrt here?
  6443. len = 1 / Math.sqrt(len);
  6444. out[0] = a[0] * len;
  6445. out[1] = a[1] * len;
  6446. }
  6447. return out;
  6448. };
  6449. /**
  6450. * Calculates the dot product of two vec2's
  6451. * @static
  6452. * @method dot
  6453. * @param {Array} a the first operand
  6454. * @param {Array} b the second operand
  6455. * @return {Number} dot product of a and b
  6456. */
  6457. vec2.dot = function (a, b) {
  6458. return a[0] * b[0] + a[1] * b[1];
  6459. };
  6460. /**
  6461. * Returns a string representation of a vector
  6462. * @static
  6463. * @method str
  6464. * @param {Array} vec vector to represent as a string
  6465. * @return {String} string representation of the vector
  6466. */
  6467. vec2.str = function (a) {
  6468. return 'vec2(' + a[0] + ', ' + a[1] + ')';
  6469. };
  6470. /**
  6471. * Linearly interpolate/mix two vectors.
  6472. * @static
  6473. * @method lerp
  6474. * @param {Array} out
  6475. * @param {Array} a First vector
  6476. * @param {Array} b Second vector
  6477. * @param {number} t Lerp factor
  6478. */
  6479. vec2.lerp = function (out, a, b, t) {
  6480. var ax = a[0],
  6481. ay = a[1];
  6482. out[0] = ax + t * (b[0] - ax);
  6483. out[1] = ay + t * (b[1] - ay);
  6484. return out;
  6485. };
  6486. /**
  6487. * Reflect a vector along a normal.
  6488. * @static
  6489. * @method reflect
  6490. * @param {Array} out
  6491. * @param {Array} vector
  6492. * @param {Array} normal
  6493. */
  6494. vec2.reflect = function(out, vector, normal){
  6495. var dot = vector[0] * normal[0] + vector[1] * normal[1];
  6496. out[0] = vector[0] - 2 * normal[0] * dot;
  6497. out[1] = vector[1] - 2 * normal[1] * dot;
  6498. };
  6499. /**
  6500. * Get the intersection point between two line segments.
  6501. * @static
  6502. * @method getLineSegmentsIntersection
  6503. * @param {Array} out
  6504. * @param {Array} p0
  6505. * @param {Array} p1
  6506. * @param {Array} p2
  6507. * @param {Array} p3
  6508. * @return {boolean} True if there was an intersection, otherwise false.
  6509. */
  6510. vec2.getLineSegmentsIntersection = function(out, p0, p1, p2, p3) {
  6511. var t = vec2.getLineSegmentsIntersectionFraction(p0, p1, p2, p3);
  6512. if(t < 0){
  6513. return false;
  6514. } else {
  6515. out[0] = p0[0] + (t * (p1[0] - p0[0]));
  6516. out[1] = p0[1] + (t * (p1[1] - p0[1]));
  6517. return true;
  6518. }
  6519. };
  6520. /**
  6521. * Get the intersection fraction between two line segments. If successful, the intersection is at p0 + t * (p1 - p0)
  6522. * @static
  6523. * @method getLineSegmentsIntersectionFraction
  6524. * @param {Array} p0
  6525. * @param {Array} p1
  6526. * @param {Array} p2
  6527. * @param {Array} p3
  6528. * @return {number} A number between 0 and 1 if there was an intersection, otherwise -1.
  6529. */
  6530. vec2.getLineSegmentsIntersectionFraction = function(p0, p1, p2, p3) {
  6531. var s1_x = p1[0] - p0[0];
  6532. var s1_y = p1[1] - p0[1];
  6533. var s2_x = p3[0] - p2[0];
  6534. var s2_y = p3[1] - p2[1];
  6535. var s, t;
  6536. s = (-s1_y * (p0[0] - p2[0]) + s1_x * (p0[1] - p2[1])) / (-s2_x * s1_y + s1_x * s2_y);
  6537. t = ( s2_x * (p0[1] - p2[1]) - s2_y * (p0[0] - p2[0])) / (-s2_x * s1_y + s1_x * s2_y);
  6538. if (s >= 0 && s <= 1 && t >= 0 && t <= 1) { // Collision detected
  6539. return t;
  6540. }
  6541. return -1; // No collision
  6542. };
  6543. },{"../utils/Utils":57}],31:[function(_dereq_,module,exports){
  6544. var vec2 = _dereq_('../math/vec2')
  6545. , decomp = _dereq_('poly-decomp')
  6546. , Convex = _dereq_('../shapes/Convex')
  6547. , RaycastResult = _dereq_('../collision/RaycastResult')
  6548. , Ray = _dereq_('../collision/Ray')
  6549. , AABB = _dereq_('../collision/AABB')
  6550. , EventEmitter = _dereq_('../events/EventEmitter');
  6551. module.exports = Body;
  6552. /**
  6553. * A rigid body. Has got a center of mass, position, velocity and a number of
  6554. * shapes that are used for collisions.
  6555. *
  6556. * @class Body
  6557. * @constructor
  6558. * @extends EventEmitter
  6559. * @param {Array} [options.force]
  6560. * @param {Array} [options.position]
  6561. * @param {Array} [options.velocity]
  6562. * @param {Boolean} [options.allowSleep]
  6563. * @param {Boolean} [options.collisionResponse]
  6564. * @param {Number} [options.angle=0]
  6565. * @param {Number} [options.angularForce=0]
  6566. * @param {Number} [options.angularVelocity=0]
  6567. * @param {Number} [options.ccdIterations=10]
  6568. * @param {Number} [options.ccdSpeedThreshold=-1]
  6569. * @param {Number} [options.fixedRotation=false]
  6570. * @param {Number} [options.gravityScale]
  6571. * @param {Number} [options.id]
  6572. * @param {Number} [options.mass=0] A number >= 0. If zero, the .type will be set to Body.STATIC.
  6573. * @param {Number} [options.sleepSpeedLimit]
  6574. * @param {Number} [options.sleepTimeLimit]
  6575. * @param {Object} [options]
  6576. *
  6577. * @example
  6578. *
  6579. * // Create a typical dynamic body
  6580. * var body = new Body({
  6581. * mass: 1,
  6582. * position: [0, 0],
  6583. * angle: 0,
  6584. * velocity: [0, 0],
  6585. * angularVelocity: 0
  6586. * });
  6587. *
  6588. * // Add a circular shape to the body
  6589. * body.addShape(new Circle({ radius: 1 }));
  6590. *
  6591. * // Add the body to the world
  6592. * world.addBody(body);
  6593. */
  6594. function Body(options){
  6595. options = options || {};
  6596. EventEmitter.call(this);
  6597. /**
  6598. * The body identifyer
  6599. * @property id
  6600. * @type {Number}
  6601. */
  6602. this.id = options.id || ++Body._idCounter;
  6603. /**
  6604. * The world that this body is added to. This property is set to NULL if the body is not added to any world.
  6605. * @property world
  6606. * @type {World}
  6607. */
  6608. this.world = null;
  6609. /**
  6610. * The shapes of the body.
  6611. *
  6612. * @property shapes
  6613. * @type {Array}
  6614. */
  6615. this.shapes = [];
  6616. /**
  6617. * The mass of the body.
  6618. * @property mass
  6619. * @type {number}
  6620. */
  6621. this.mass = options.mass || 0;
  6622. /**
  6623. * The inverse mass of the body.
  6624. * @property invMass
  6625. * @type {number}
  6626. */
  6627. this.invMass = 0;
  6628. /**
  6629. * The inertia of the body around the Z axis.
  6630. * @property inertia
  6631. * @type {number}
  6632. */
  6633. this.inertia = 0;
  6634. /**
  6635. * The inverse inertia of the body.
  6636. * @property invInertia
  6637. * @type {number}
  6638. */
  6639. this.invInertia = 0;
  6640. this.invMassSolve = 0;
  6641. this.invInertiaSolve = 0;
  6642. /**
  6643. * Set to true if you want to fix the rotation of the body.
  6644. * @property fixedRotation
  6645. * @type {Boolean}
  6646. */
  6647. this.fixedRotation = !!options.fixedRotation;
  6648. /**
  6649. * Set to true if you want to fix the body movement along the X axis. The body will still be able to move along Y.
  6650. * @property {Boolean} fixedX
  6651. */
  6652. this.fixedX = !!options.fixedX;
  6653. /**
  6654. * Set to true if you want to fix the body movement along the Y axis. The body will still be able to move along X.
  6655. * @property {Boolean} fixedY
  6656. */
  6657. this.fixedY = !!options.fixedY;
  6658. /**
  6659. * @private
  6660. * @property {array} massMultiplier
  6661. */
  6662. this.massMultiplier = vec2.create();
  6663. /**
  6664. * The position of the body
  6665. * @property position
  6666. * @type {Array}
  6667. */
  6668. this.position = vec2.fromValues(0,0);
  6669. if(options.position){
  6670. vec2.copy(this.position, options.position);
  6671. }
  6672. /**
  6673. * The interpolated position of the body. Use this for rendering.
  6674. * @property interpolatedPosition
  6675. * @type {Array}
  6676. */
  6677. this.interpolatedPosition = vec2.fromValues(0,0);
  6678. /**
  6679. * The interpolated angle of the body. Use this for rendering.
  6680. * @property interpolatedAngle
  6681. * @type {Number}
  6682. */
  6683. this.interpolatedAngle = 0;
  6684. /**
  6685. * The previous position of the body.
  6686. * @property previousPosition
  6687. * @type {Array}
  6688. */
  6689. this.previousPosition = vec2.fromValues(0,0);
  6690. /**
  6691. * The previous angle of the body.
  6692. * @property previousAngle
  6693. * @type {Number}
  6694. */
  6695. this.previousAngle = 0;
  6696. /**
  6697. * The current velocity of the body.
  6698. * @property velocity
  6699. * @type {Array}
  6700. */
  6701. this.velocity = vec2.fromValues(0,0);
  6702. if(options.velocity){
  6703. vec2.copy(this.velocity, options.velocity);
  6704. }
  6705. /**
  6706. * Constraint velocity that was added to the body during the last step.
  6707. * @property vlambda
  6708. * @type {Array}
  6709. */
  6710. this.vlambda = vec2.fromValues(0,0);
  6711. /**
  6712. * Angular constraint velocity that was added to the body during last step.
  6713. * @property wlambda
  6714. * @type {Array}
  6715. */
  6716. this.wlambda = 0;
  6717. /**
  6718. * The angle of the body, in radians.
  6719. * @property angle
  6720. * @type {number}
  6721. * @example
  6722. * // The angle property is not normalized to the interval 0 to 2*pi, it can be any value.
  6723. * // If you need a value between 0 and 2*pi, use the following function to normalize it.
  6724. * function normalizeAngle(angle){
  6725. * angle = angle % (2*Math.PI);
  6726. * if(angle < 0){
  6727. * angle += (2*Math.PI);
  6728. * }
  6729. * return angle;
  6730. * }
  6731. */
  6732. this.angle = options.angle || 0;
  6733. /**
  6734. * The angular velocity of the body, in radians per second.
  6735. * @property angularVelocity
  6736. * @type {number}
  6737. */
  6738. this.angularVelocity = options.angularVelocity || 0;
  6739. /**
  6740. * The force acting on the body. Since the body force (and {{#crossLink "Body/angularForce:property"}}{{/crossLink}}) will be zeroed after each step, so you need to set the force before each step.
  6741. * @property force
  6742. * @type {Array}
  6743. *
  6744. * @example
  6745. * // This produces a forcefield of 1 Newton in the positive x direction.
  6746. * for(var i=0; i<numSteps; i++){
  6747. * body.force[0] = 1;
  6748. * world.step(1/60);
  6749. * }
  6750. *
  6751. * @example
  6752. * // This will apply a rotational force on the body
  6753. * for(var i=0; i<numSteps; i++){
  6754. * body.angularForce = -3;
  6755. * world.step(1/60);
  6756. * }
  6757. */
  6758. this.force = vec2.create();
  6759. if(options.force){
  6760. vec2.copy(this.force, options.force);
  6761. }
  6762. /**
  6763. * The angular force acting on the body. See {{#crossLink "Body/force:property"}}{{/crossLink}}.
  6764. * @property angularForce
  6765. * @type {number}
  6766. */
  6767. this.angularForce = options.angularForce || 0;
  6768. /**
  6769. * The linear damping acting on the body in the velocity direction. Should be a value between 0 and 1.
  6770. * @property damping
  6771. * @type {Number}
  6772. * @default 0.1
  6773. */
  6774. this.damping = typeof(options.damping) === "number" ? options.damping : 0.1;
  6775. /**
  6776. * The angular force acting on the body. Should be a value between 0 and 1.
  6777. * @property angularDamping
  6778. * @type {Number}
  6779. * @default 0.1
  6780. */
  6781. this.angularDamping = typeof(options.angularDamping) === "number" ? options.angularDamping : 0.1;
  6782. /**
  6783. * The type of motion this body has. Should be one of: {{#crossLink "Body/STATIC:property"}}Body.STATIC{{/crossLink}}, {{#crossLink "Body/DYNAMIC:property"}}Body.DYNAMIC{{/crossLink}} and {{#crossLink "Body/KINEMATIC:property"}}Body.KINEMATIC{{/crossLink}}.
  6784. *
  6785. * * Static bodies do not move, and they do not respond to forces or collision.
  6786. * * Dynamic bodies body can move and respond to collisions and forces.
  6787. * * Kinematic bodies only moves according to its .velocity, and does not respond to collisions or force.
  6788. *
  6789. * @property type
  6790. * @type {number}
  6791. *
  6792. * @example
  6793. * // Bodies are static by default. Static bodies will never move.
  6794. * var body = new Body();
  6795. * console.log(body.type == Body.STATIC); // true
  6796. *
  6797. * @example
  6798. * // By setting the mass of a body to a nonzero number, the body
  6799. * // will become dynamic and will move and interact with other bodies.
  6800. * var dynamicBody = new Body({
  6801. * mass : 1
  6802. * });
  6803. * console.log(dynamicBody.type == Body.DYNAMIC); // true
  6804. *
  6805. * @example
  6806. * // Kinematic bodies will only move if you change their velocity.
  6807. * var kinematicBody = new Body({
  6808. * type: Body.KINEMATIC // Type can be set via the options object.
  6809. * });
  6810. */
  6811. this.type = Body.STATIC;
  6812. if(typeof(options.type) !== 'undefined'){
  6813. this.type = options.type;
  6814. } else if(!options.mass){
  6815. this.type = Body.STATIC;
  6816. } else {
  6817. this.type = Body.DYNAMIC;
  6818. }
  6819. /**
  6820. * Bounding circle radius.
  6821. * @property boundingRadius
  6822. * @type {Number}
  6823. */
  6824. this.boundingRadius = 0;
  6825. /**
  6826. * Bounding box of this body.
  6827. * @property aabb
  6828. * @type {AABB}
  6829. */
  6830. this.aabb = new AABB();
  6831. /**
  6832. * Indicates if the AABB needs update. Update it with {{#crossLink "Body/updateAABB:method"}}.updateAABB(){{/crossLink}}.
  6833. * @property aabbNeedsUpdate
  6834. * @type {Boolean}
  6835. * @see updateAABB
  6836. *
  6837. * @example
  6838. * // Force update the AABB
  6839. * body.aabbNeedsUpdate = true;
  6840. * body.updateAABB();
  6841. * console.log(body.aabbNeedsUpdate); // false
  6842. */
  6843. this.aabbNeedsUpdate = true;
  6844. /**
  6845. * If true, the body will automatically fall to sleep. Note that you need to enable sleeping in the {{#crossLink "World"}}{{/crossLink}} before anything will happen.
  6846. * @property allowSleep
  6847. * @type {Boolean}
  6848. * @default true
  6849. */
  6850. this.allowSleep = options.allowSleep !== undefined ? options.allowSleep : true;
  6851. this.wantsToSleep = false;
  6852. /**
  6853. * One of {{#crossLink "Body/AWAKE:property"}}Body.AWAKE{{/crossLink}}, {{#crossLink "Body/SLEEPY:property"}}Body.SLEEPY{{/crossLink}} and {{#crossLink "Body/SLEEPING:property"}}Body.SLEEPING{{/crossLink}}.
  6854. *
  6855. * The body is initially Body.AWAKE. If its velocity norm is below .sleepSpeedLimit, the sleepState will become Body.SLEEPY. If the body continues to be Body.SLEEPY for .sleepTimeLimit seconds, it will fall asleep (Body.SLEEPY).
  6856. *
  6857. * @property sleepState
  6858. * @type {Number}
  6859. * @default Body.AWAKE
  6860. */
  6861. this.sleepState = Body.AWAKE;
  6862. /**
  6863. * If the speed (the norm of the velocity) is smaller than this value, the body is considered sleepy.
  6864. * @property sleepSpeedLimit
  6865. * @type {Number}
  6866. * @default 0.2
  6867. */
  6868. this.sleepSpeedLimit = options.sleepSpeedLimit !== undefined ? options.sleepSpeedLimit : 0.2;
  6869. /**
  6870. * If the body has been sleepy for this sleepTimeLimit seconds, it is considered sleeping.
  6871. * @property sleepTimeLimit
  6872. * @type {Number}
  6873. * @default 1
  6874. */
  6875. this.sleepTimeLimit = options.sleepTimeLimit !== undefined ? options.sleepTimeLimit : 1;
  6876. /**
  6877. * Gravity scaling factor. If you want the body to ignore gravity, set this to zero. If you want to reverse gravity, set it to -1.
  6878. * @property {Number} gravityScale
  6879. * @default 1
  6880. */
  6881. this.gravityScale = options.gravityScale !== undefined ? options.gravityScale : 1;
  6882. /**
  6883. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled. That means that this body will move through other bodies, but it will still trigger contact events, etc.
  6884. * @property {Boolean} collisionResponse
  6885. */
  6886. this.collisionResponse = options.collisionResponse !== undefined ? options.collisionResponse : true;
  6887. /**
  6888. * How long the body has been sleeping.
  6889. * @property {Number} idleTime
  6890. */
  6891. this.idleTime = 0;
  6892. /**
  6893. * The last time when the body went to SLEEPY state.
  6894. * @property {Number} timeLastSleepy
  6895. * @private
  6896. */
  6897. this.timeLastSleepy = 0;
  6898. /**
  6899. * If the body speed exceeds this threshold, CCD (continuous collision detection) will be enabled. Set it to a negative number to disable CCD completely for this body.
  6900. * @property {number} ccdSpeedThreshold
  6901. * @default -1
  6902. */
  6903. this.ccdSpeedThreshold = options.ccdSpeedThreshold !== undefined ? options.ccdSpeedThreshold : -1;
  6904. /**
  6905. * The number of iterations that should be used when searching for the time of impact during CCD. A larger number will assure that there's a small penetration on CCD collision, but a small number will give more performance.
  6906. * @property {number} ccdIterations
  6907. * @default 10
  6908. */
  6909. this.ccdIterations = options.ccdIterations !== undefined ? options.ccdIterations : 10;
  6910. this.concavePath = null;
  6911. this._wakeUpAfterNarrowphase = false;
  6912. this.updateMassProperties();
  6913. }
  6914. Body.prototype = new EventEmitter();
  6915. Body.prototype.constructor = Body;
  6916. Body._idCounter = 0;
  6917. /**
  6918. * @private
  6919. * @method updateSolveMassProperties
  6920. */
  6921. Body.prototype.updateSolveMassProperties = function(){
  6922. if(this.sleepState === Body.SLEEPING || this.type === Body.KINEMATIC){
  6923. this.invMassSolve = 0;
  6924. this.invInertiaSolve = 0;
  6925. } else {
  6926. this.invMassSolve = this.invMass;
  6927. this.invInertiaSolve = this.invInertia;
  6928. }
  6929. };
  6930. /**
  6931. * Set the total density of the body
  6932. * @method setDensity
  6933. * @param {number} density
  6934. */
  6935. Body.prototype.setDensity = function(density) {
  6936. var totalArea = this.getArea();
  6937. this.mass = totalArea * density;
  6938. this.updateMassProperties();
  6939. };
  6940. /**
  6941. * Get the total area of all shapes in the body
  6942. * @method getArea
  6943. * @return {Number}
  6944. */
  6945. Body.prototype.getArea = function() {
  6946. var totalArea = 0;
  6947. for(var i=0; i<this.shapes.length; i++){
  6948. totalArea += this.shapes[i].area;
  6949. }
  6950. return totalArea;
  6951. };
  6952. /**
  6953. * Get the AABB from the body. The AABB is updated if necessary.
  6954. * @method getAABB
  6955. * @return {AABB} The AABB instance (this.aabb)
  6956. */
  6957. Body.prototype.getAABB = function(){
  6958. if(this.aabbNeedsUpdate){
  6959. this.updateAABB();
  6960. }
  6961. return this.aabb;
  6962. };
  6963. var shapeAABB = new AABB(),
  6964. tmp = vec2.create();
  6965. /**
  6966. * Updates the AABB of the Body, and set .aabbNeedsUpdate = false.
  6967. * @method updateAABB
  6968. */
  6969. Body.prototype.updateAABB = function() {
  6970. var shapes = this.shapes,
  6971. N = shapes.length,
  6972. offset = tmp,
  6973. bodyAngle = this.angle;
  6974. for(var i=0; i!==N; i++){
  6975. var shape = shapes[i],
  6976. angle = shape.angle + bodyAngle;
  6977. // Get shape world offset
  6978. vec2.rotate(offset, shape.position, bodyAngle);
  6979. vec2.add(offset, offset, this.position);
  6980. // Get shape AABB
  6981. shape.computeAABB(shapeAABB, offset, angle);
  6982. if(i===0){
  6983. this.aabb.copy(shapeAABB);
  6984. } else {
  6985. this.aabb.extend(shapeAABB);
  6986. }
  6987. }
  6988. this.aabbNeedsUpdate = false;
  6989. };
  6990. /**
  6991. * Update the bounding radius of the body (this.boundingRadius). Should be done if any of the shape dimensions or positions are changed.
  6992. * @method updateBoundingRadius
  6993. */
  6994. Body.prototype.updateBoundingRadius = function(){
  6995. var shapes = this.shapes,
  6996. N = shapes.length,
  6997. radius = 0;
  6998. for(var i=0; i!==N; i++){
  6999. var shape = shapes[i],
  7000. offset = vec2.length(shape.position),
  7001. r = shape.boundingRadius;
  7002. if(offset + r > radius){
  7003. radius = offset + r;
  7004. }
  7005. }
  7006. this.boundingRadius = radius;
  7007. };
  7008. /**
  7009. * Add a shape to the body. You can pass a local transform when adding a shape,
  7010. * so that the shape gets an offset and angle relative to the body center of mass.
  7011. * Will automatically update the mass properties and bounding radius.
  7012. *
  7013. * @method addShape
  7014. * @param {Shape} shape
  7015. * @param {Array} [offset] Local body offset of the shape.
  7016. * @param {Number} [angle] Local body angle.
  7017. *
  7018. * @example
  7019. * var body = new Body(),
  7020. * shape = new Circle({ radius: 1 });
  7021. *
  7022. * // Add the shape to the body, positioned in the center
  7023. * body.addShape(shape);
  7024. *
  7025. * // Add another shape to the body, positioned 1 unit length from the body center of mass along the local x-axis.
  7026. * body.addShape(shape,[1,0]);
  7027. *
  7028. * // Add another shape to the body, positioned 1 unit length from the body center of mass along the local y-axis, and rotated 90 degrees CCW.
  7029. * body.addShape(shape,[0,1],Math.PI/2);
  7030. */
  7031. Body.prototype.addShape = function(shape, offset, angle){
  7032. if(shape.body){
  7033. throw new Error('A shape can only be added to one body.');
  7034. }
  7035. shape.body = this;
  7036. // Copy the offset vector
  7037. if(offset){
  7038. vec2.copy(shape.position, offset);
  7039. } else {
  7040. vec2.set(shape.position, 0, 0);
  7041. }
  7042. shape.angle = angle || 0;
  7043. this.shapes.push(shape);
  7044. this.updateMassProperties();
  7045. this.updateBoundingRadius();
  7046. this.aabbNeedsUpdate = true;
  7047. };
  7048. /**
  7049. * Remove a shape
  7050. * @method removeShape
  7051. * @param {Shape} shape
  7052. * @return {Boolean} True if the shape was found and removed, else false.
  7053. */
  7054. Body.prototype.removeShape = function(shape){
  7055. var idx = this.shapes.indexOf(shape);
  7056. if(idx !== -1){
  7057. this.shapes.splice(idx,1);
  7058. this.aabbNeedsUpdate = true;
  7059. shape.body = null;
  7060. return true;
  7061. } else {
  7062. return false;
  7063. }
  7064. };
  7065. /**
  7066. * Updates .inertia, .invMass, .invInertia for this Body. Should be called when
  7067. * changing the structure or mass of the Body.
  7068. *
  7069. * @method updateMassProperties
  7070. *
  7071. * @example
  7072. * body.mass += 1;
  7073. * body.updateMassProperties();
  7074. */
  7075. Body.prototype.updateMassProperties = function(){
  7076. if(this.type === Body.STATIC || this.type === Body.KINEMATIC){
  7077. this.mass = Number.MAX_VALUE;
  7078. this.invMass = 0;
  7079. this.inertia = Number.MAX_VALUE;
  7080. this.invInertia = 0;
  7081. } else {
  7082. var shapes = this.shapes,
  7083. N = shapes.length,
  7084. m = this.mass / N,
  7085. I = 0;
  7086. if(!this.fixedRotation){
  7087. for(var i=0; i<N; i++){
  7088. var shape = shapes[i],
  7089. r2 = vec2.squaredLength(shape.position),
  7090. Icm = shape.computeMomentOfInertia(m);
  7091. I += Icm + m*r2;
  7092. }
  7093. this.inertia = I;
  7094. this.invInertia = I>0 ? 1/I : 0;
  7095. } else {
  7096. this.inertia = Number.MAX_VALUE;
  7097. this.invInertia = 0;
  7098. }
  7099. // Inverse mass properties are easy
  7100. this.invMass = 1 / this.mass;
  7101. vec2.set(
  7102. this.massMultiplier,
  7103. this.fixedX ? 0 : 1,
  7104. this.fixedY ? 0 : 1
  7105. );
  7106. }
  7107. };
  7108. var Body_applyForce_r = vec2.create();
  7109. /**
  7110. * Apply force to a point relative to the center of mass of the body. This could for example be a point on the RigidBody surface. Applying force this way will add to Body.force and Body.angularForce. If relativePoint is zero, the force will be applied directly on the center of mass, and the torque produced will be zero.
  7111. * @method applyForce
  7112. * @param {Array} force The force to add.
  7113. * @param {Array} [relativePoint] A world point to apply the force on.
  7114. */
  7115. Body.prototype.applyForce = function(force, relativePoint){
  7116. // Add linear force
  7117. vec2.add(this.force, this.force, force);
  7118. if(relativePoint){
  7119. // Compute produced rotational force
  7120. var rotForce = vec2.crossLength(relativePoint,force);
  7121. // Add rotational force
  7122. this.angularForce += rotForce;
  7123. }
  7124. };
  7125. /**
  7126. * Apply force to a body-local point.
  7127. * @method applyForceLocal
  7128. * @param {Array} localForce The force vector to add, oriented in local body space.
  7129. * @param {Array} [localPoint] A point relative to the body in world space. If not given, it is set to zero and all of the impulse will be excerted on the center of mass.
  7130. */
  7131. var Body_applyForce_forceWorld = vec2.create();
  7132. var Body_applyForce_pointWorld = vec2.create();
  7133. var Body_applyForce_pointLocal = vec2.create();
  7134. Body.prototype.applyForceLocal = function(localForce, localPoint){
  7135. localPoint = localPoint || Body_applyForce_pointLocal;
  7136. var worldForce = Body_applyForce_forceWorld;
  7137. var worldPoint = Body_applyForce_pointWorld;
  7138. this.vectorToWorldFrame(worldForce, localForce);
  7139. this.vectorToWorldFrame(worldPoint, localPoint);
  7140. this.applyForce(worldForce, worldPoint);
  7141. };
  7142. /**
  7143. * Apply impulse to a point relative to the body. This could for example be a point on the Body surface. An impulse is a force added to a body during a short period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
  7144. * @method applyImpulse
  7145. * @param {Array} impulse The impulse vector to add, oriented in world space.
  7146. * @param {Array} [relativePoint] A point relative to the body in world space. If not given, it is set to zero and all of the impulse will be excerted on the center of mass.
  7147. */
  7148. var Body_applyImpulse_velo = vec2.create();
  7149. Body.prototype.applyImpulse = function(impulseVector, relativePoint){
  7150. if(this.type !== Body.DYNAMIC){
  7151. return;
  7152. }
  7153. // Compute produced central impulse velocity
  7154. var velo = Body_applyImpulse_velo;
  7155. vec2.scale(velo, impulseVector, this.invMass);
  7156. vec2.multiply(velo, this.massMultiplier, velo);
  7157. // Add linear impulse
  7158. vec2.add(this.velocity, velo, this.velocity);
  7159. if(relativePoint){
  7160. // Compute produced rotational impulse velocity
  7161. var rotVelo = vec2.crossLength(relativePoint, impulseVector);
  7162. rotVelo *= this.invInertia;
  7163. // Add rotational Impulse
  7164. this.angularVelocity += rotVelo;
  7165. }
  7166. };
  7167. /**
  7168. * Apply impulse to a point relative to the body. This could for example be a point on the Body surface. An impulse is a force added to a body during a short period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
  7169. * @method applyImpulseLocal
  7170. * @param {Array} impulse The impulse vector to add, oriented in world space.
  7171. * @param {Array} [relativePoint] A point relative to the body in world space. If not given, it is set to zero and all of the impulse will be excerted on the center of mass.
  7172. */
  7173. var Body_applyImpulse_impulseWorld = vec2.create();
  7174. var Body_applyImpulse_pointWorld = vec2.create();
  7175. var Body_applyImpulse_pointLocal = vec2.create();
  7176. Body.prototype.applyImpulseLocal = function(localImpulse, localPoint){
  7177. localPoint = localPoint || Body_applyImpulse_pointLocal;
  7178. var worldImpulse = Body_applyImpulse_impulseWorld;
  7179. var worldPoint = Body_applyImpulse_pointWorld;
  7180. this.vectorToWorldFrame(worldImpulse, localImpulse);
  7181. this.vectorToWorldFrame(worldPoint, localPoint);
  7182. this.applyImpulse(worldImpulse, worldPoint);
  7183. };
  7184. /**
  7185. * Transform a world point to local body frame.
  7186. * @method toLocalFrame
  7187. * @param {Array} out The vector to store the result in
  7188. * @param {Array} worldPoint The input world point
  7189. */
  7190. Body.prototype.toLocalFrame = function(out, worldPoint){
  7191. vec2.toLocalFrame(out, worldPoint, this.position, this.angle);
  7192. };
  7193. /**
  7194. * Transform a local point to world frame.
  7195. * @method toWorldFrame
  7196. * @param {Array} out The vector to store the result in
  7197. * @param {Array} localPoint The input local point
  7198. */
  7199. Body.prototype.toWorldFrame = function(out, localPoint){
  7200. vec2.toGlobalFrame(out, localPoint, this.position, this.angle);
  7201. };
  7202. /**
  7203. * Transform a world point to local body frame.
  7204. * @method vectorToLocalFrame
  7205. * @param {Array} out The vector to store the result in
  7206. * @param {Array} worldVector The input world vector
  7207. */
  7208. Body.prototype.vectorToLocalFrame = function(out, worldVector){
  7209. vec2.vectorToLocalFrame(out, worldVector, this.angle);
  7210. };
  7211. /**
  7212. * Transform a local point to world frame.
  7213. * @method vectorToWorldFrame
  7214. * @param {Array} out The vector to store the result in
  7215. * @param {Array} localVector The input local vector
  7216. */
  7217. Body.prototype.vectorToWorldFrame = function(out, localVector){
  7218. vec2.vectorToGlobalFrame(out, localVector, this.angle);
  7219. };
  7220. /**
  7221. * Reads a polygon shape path, and assembles convex shapes from that and puts them at proper offset points.
  7222. * @method fromPolygon
  7223. * @param {Array} path An array of 2d vectors, e.g. [[0,0],[0,1],...] that resembles a concave or convex polygon. The shape must be simple and without holes.
  7224. * @param {Object} [options]
  7225. * @param {Boolean} [options.optimalDecomp=false] Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  7226. * @param {Boolean} [options.skipSimpleCheck=false] Set to true if you already know that the path is not intersecting itself.
  7227. * @param {Boolean|Number} [options.removeCollinearPoints=false] Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  7228. * @return {Boolean} True on success, else false.
  7229. */
  7230. Body.prototype.fromPolygon = function(path,options){
  7231. options = options || {};
  7232. // Remove all shapes
  7233. for(var i=this.shapes.length; i>=0; --i){
  7234. this.removeShape(this.shapes[i]);
  7235. }
  7236. var p = new decomp.Polygon();
  7237. p.vertices = path;
  7238. // Make it counter-clockwise
  7239. p.makeCCW();
  7240. if(typeof(options.removeCollinearPoints) === "number"){
  7241. p.removeCollinearPoints(options.removeCollinearPoints);
  7242. }
  7243. // Check if any line segment intersects the path itself
  7244. if(typeof(options.skipSimpleCheck) === "undefined"){
  7245. if(!p.isSimple()){
  7246. return false;
  7247. }
  7248. }
  7249. // Save this path for later
  7250. this.concavePath = p.vertices.slice(0);
  7251. for(var i=0; i<this.concavePath.length; i++){
  7252. var v = [0,0];
  7253. vec2.copy(v,this.concavePath[i]);
  7254. this.concavePath[i] = v;
  7255. }
  7256. // Slow or fast decomp?
  7257. var convexes;
  7258. if(options.optimalDecomp){
  7259. convexes = p.decomp();
  7260. } else {
  7261. convexes = p.quickDecomp();
  7262. }
  7263. var cm = vec2.create();
  7264. // Add convexes
  7265. for(var i=0; i!==convexes.length; i++){
  7266. // Create convex
  7267. var c = new Convex({ vertices: convexes[i].vertices });
  7268. // Move all vertices so its center of mass is in the local center of the convex
  7269. for(var j=0; j!==c.vertices.length; j++){
  7270. var v = c.vertices[j];
  7271. vec2.sub(v,v,c.centerOfMass);
  7272. }
  7273. vec2.scale(cm,c.centerOfMass,1);
  7274. c.updateTriangles();
  7275. c.updateCenterOfMass();
  7276. c.updateBoundingRadius();
  7277. // Add the shape
  7278. this.addShape(c,cm);
  7279. }
  7280. this.adjustCenterOfMass();
  7281. this.aabbNeedsUpdate = true;
  7282. return true;
  7283. };
  7284. var adjustCenterOfMass_tmp1 = vec2.fromValues(0,0),
  7285. adjustCenterOfMass_tmp2 = vec2.fromValues(0,0),
  7286. adjustCenterOfMass_tmp3 = vec2.fromValues(0,0),
  7287. adjustCenterOfMass_tmp4 = vec2.fromValues(0,0);
  7288. /**
  7289. * Moves the shape offsets so their center of mass becomes the body center of mass.
  7290. * @method adjustCenterOfMass
  7291. */
  7292. Body.prototype.adjustCenterOfMass = function(){
  7293. var offset_times_area = adjustCenterOfMass_tmp2,
  7294. sum = adjustCenterOfMass_tmp3,
  7295. cm = adjustCenterOfMass_tmp4,
  7296. totalArea = 0;
  7297. vec2.set(sum,0,0);
  7298. for(var i=0; i!==this.shapes.length; i++){
  7299. var s = this.shapes[i];
  7300. vec2.scale(offset_times_area, s.position, s.area);
  7301. vec2.add(sum, sum, offset_times_area);
  7302. totalArea += s.area;
  7303. }
  7304. vec2.scale(cm,sum,1/totalArea);
  7305. // Now move all shapes
  7306. for(var i=0; i!==this.shapes.length; i++){
  7307. var s = this.shapes[i];
  7308. vec2.sub(s.position, s.position, cm);
  7309. }
  7310. // Move the body position too
  7311. vec2.add(this.position,this.position,cm);
  7312. // And concave path
  7313. for(var i=0; this.concavePath && i<this.concavePath.length; i++){
  7314. vec2.sub(this.concavePath[i], this.concavePath[i], cm);
  7315. }
  7316. this.updateMassProperties();
  7317. this.updateBoundingRadius();
  7318. };
  7319. /**
  7320. * Sets the force on the body to zero.
  7321. * @method setZeroForce
  7322. */
  7323. Body.prototype.setZeroForce = function(){
  7324. vec2.set(this.force,0.0,0.0);
  7325. this.angularForce = 0.0;
  7326. };
  7327. Body.prototype.resetConstraintVelocity = function(){
  7328. var b = this,
  7329. vlambda = b.vlambda;
  7330. vec2.set(vlambda,0,0);
  7331. b.wlambda = 0;
  7332. };
  7333. Body.prototype.addConstraintVelocity = function(){
  7334. var b = this,
  7335. v = b.velocity;
  7336. vec2.add( v, v, b.vlambda);
  7337. b.angularVelocity += b.wlambda;
  7338. };
  7339. /**
  7340. * Apply damping, see <a href="http://code.google.com/p/bullet/issues/detail?id=74">this</a> for details.
  7341. * @method applyDamping
  7342. * @param {number} dt Current time step
  7343. */
  7344. Body.prototype.applyDamping = function(dt){
  7345. if(this.type === Body.DYNAMIC){ // Only for dynamic bodies
  7346. var v = this.velocity;
  7347. vec2.scale(v, v, Math.pow(1.0 - this.damping,dt));
  7348. this.angularVelocity *= Math.pow(1.0 - this.angularDamping,dt);
  7349. }
  7350. };
  7351. /**
  7352. * Wake the body up. Normally you should not need this, as the body is automatically awoken at events such as collisions.
  7353. * Sets the sleepState to {{#crossLink "Body/AWAKE:property"}}Body.AWAKE{{/crossLink}} and emits the wakeUp event if the body wasn't awake before.
  7354. * @method wakeUp
  7355. */
  7356. Body.prototype.wakeUp = function(){
  7357. var s = this.sleepState;
  7358. this.sleepState = Body.AWAKE;
  7359. this.idleTime = 0;
  7360. if(s !== Body.AWAKE){
  7361. this.emit(Body.wakeUpEvent);
  7362. }
  7363. };
  7364. /**
  7365. * Force body sleep
  7366. * @method sleep
  7367. */
  7368. Body.prototype.sleep = function(){
  7369. this.sleepState = Body.SLEEPING;
  7370. this.angularVelocity = 0;
  7371. this.angularForce = 0;
  7372. vec2.set(this.velocity,0,0);
  7373. vec2.set(this.force,0,0);
  7374. this.emit(Body.sleepEvent);
  7375. };
  7376. /**
  7377. * Called every timestep to update internal sleep timer and change sleep state if needed.
  7378. * @method sleepTick
  7379. * @param {number} time The world time in seconds
  7380. * @param {boolean} dontSleep
  7381. * @param {number} dt
  7382. */
  7383. Body.prototype.sleepTick = function(time, dontSleep, dt){
  7384. if(!this.allowSleep || this.type === Body.SLEEPING){
  7385. return;
  7386. }
  7387. this.wantsToSleep = false;
  7388. var sleepState = this.sleepState,
  7389. speedSquared = vec2.squaredLength(this.velocity) + Math.pow(this.angularVelocity,2),
  7390. speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
  7391. // Add to idle time
  7392. if(speedSquared >= speedLimitSquared){
  7393. this.idleTime = 0;
  7394. this.sleepState = Body.AWAKE;
  7395. } else {
  7396. this.idleTime += dt;
  7397. this.sleepState = Body.SLEEPY;
  7398. }
  7399. if(this.idleTime > this.sleepTimeLimit){
  7400. if(!dontSleep){
  7401. this.sleep();
  7402. } else {
  7403. this.wantsToSleep = true;
  7404. }
  7405. }
  7406. };
  7407. /**
  7408. * Check if the body is overlapping another body. Note that this method only works if the body was added to a World and if at least one step was taken.
  7409. * @method overlaps
  7410. * @param {Body} body
  7411. * @return {boolean}
  7412. */
  7413. Body.prototype.overlaps = function(body){
  7414. return this.world.overlapKeeper.bodiesAreOverlapping(this, body);
  7415. };
  7416. var integrate_fhMinv = vec2.create();
  7417. var integrate_velodt = vec2.create();
  7418. /**
  7419. * Move the body forward in time given its current velocity.
  7420. * @method integrate
  7421. * @param {Number} dt
  7422. */
  7423. Body.prototype.integrate = function(dt){
  7424. var minv = this.invMass,
  7425. f = this.force,
  7426. pos = this.position,
  7427. velo = this.velocity;
  7428. // Save old position
  7429. vec2.copy(this.previousPosition, this.position);
  7430. this.previousAngle = this.angle;
  7431. // Velocity update
  7432. if(!this.fixedRotation){
  7433. this.angularVelocity += this.angularForce * this.invInertia * dt;
  7434. }
  7435. vec2.scale(integrate_fhMinv, f, dt * minv);
  7436. vec2.multiply(integrate_fhMinv, this.massMultiplier, integrate_fhMinv);
  7437. vec2.add(velo, integrate_fhMinv, velo);
  7438. // CCD
  7439. if(!this.integrateToTimeOfImpact(dt)){
  7440. // Regular position update
  7441. vec2.scale(integrate_velodt, velo, dt);
  7442. vec2.add(pos, pos, integrate_velodt);
  7443. if(!this.fixedRotation){
  7444. this.angle += this.angularVelocity * dt;
  7445. }
  7446. }
  7447. this.aabbNeedsUpdate = true;
  7448. };
  7449. var result = new RaycastResult();
  7450. var ray = new Ray({
  7451. mode: Ray.ALL
  7452. });
  7453. var direction = vec2.create();
  7454. var end = vec2.create();
  7455. var startToEnd = vec2.create();
  7456. var rememberPosition = vec2.create();
  7457. Body.prototype.integrateToTimeOfImpact = function(dt){
  7458. if(this.ccdSpeedThreshold < 0 || vec2.squaredLength(this.velocity) < Math.pow(this.ccdSpeedThreshold, 2)){
  7459. return false;
  7460. }
  7461. vec2.normalize(direction, this.velocity);
  7462. vec2.scale(end, this.velocity, dt);
  7463. vec2.add(end, end, this.position);
  7464. vec2.sub(startToEnd, end, this.position);
  7465. var startToEndAngle = this.angularVelocity * dt;
  7466. var len = vec2.length(startToEnd);
  7467. var timeOfImpact = 1;
  7468. var hit;
  7469. var that = this;
  7470. result.reset();
  7471. ray.callback = function (result) {
  7472. if(result.body === that){
  7473. return;
  7474. }
  7475. hit = result.body;
  7476. result.getHitPoint(end, ray);
  7477. vec2.sub(startToEnd, end, that.position);
  7478. timeOfImpact = vec2.length(startToEnd) / len;
  7479. result.stop();
  7480. };
  7481. vec2.copy(ray.from, this.position);
  7482. vec2.copy(ray.to, end);
  7483. ray.update();
  7484. this.world.raycast(result, ray);
  7485. if(!hit){
  7486. return false;
  7487. }
  7488. var rememberAngle = this.angle;
  7489. vec2.copy(rememberPosition, this.position);
  7490. // Got a start and end point. Approximate time of impact using binary search
  7491. var iter = 0;
  7492. var tmin = 0;
  7493. var tmid = 0;
  7494. var tmax = timeOfImpact;
  7495. while (tmax >= tmin && iter < this.ccdIterations) {
  7496. iter++;
  7497. // calculate the midpoint
  7498. tmid = (tmax - tmin) / 2;
  7499. // Move the body to that point
  7500. vec2.scale(integrate_velodt, startToEnd, timeOfImpact);
  7501. vec2.add(this.position, rememberPosition, integrate_velodt);
  7502. this.angle = rememberAngle + startToEndAngle * timeOfImpact;
  7503. this.updateAABB();
  7504. // check overlap
  7505. var overlaps = this.aabb.overlaps(hit.aabb) && this.world.narrowphase.bodiesOverlap(this, hit);
  7506. if (overlaps) {
  7507. // change min to search upper interval
  7508. tmin = tmid;
  7509. } else {
  7510. // change max to search lower interval
  7511. tmax = tmid;
  7512. }
  7513. }
  7514. timeOfImpact = tmid;
  7515. vec2.copy(this.position, rememberPosition);
  7516. this.angle = rememberAngle;
  7517. // move to TOI
  7518. vec2.scale(integrate_velodt, startToEnd, timeOfImpact);
  7519. vec2.add(this.position, this.position, integrate_velodt);
  7520. if(!this.fixedRotation){
  7521. this.angle += startToEndAngle * timeOfImpact;
  7522. }
  7523. return true;
  7524. };
  7525. /**
  7526. * Get velocity of a point in the body.
  7527. * @method getVelocityAtPoint
  7528. * @param {Array} result A vector to store the result in
  7529. * @param {Array} relativePoint A world oriented vector, indicating the position of the point to get the velocity from
  7530. * @return {Array} The result vector
  7531. */
  7532. Body.prototype.getVelocityAtPoint = function(result, relativePoint){
  7533. vec2.crossVZ(result, relativePoint, this.angularVelocity);
  7534. vec2.subtract(result, this.velocity, result);
  7535. return result;
  7536. };
  7537. /**
  7538. * @event sleepy
  7539. */
  7540. Body.sleepyEvent = {
  7541. type: "sleepy"
  7542. };
  7543. /**
  7544. * @event sleep
  7545. */
  7546. Body.sleepEvent = {
  7547. type: "sleep"
  7548. };
  7549. /**
  7550. * @event wakeup
  7551. */
  7552. Body.wakeUpEvent = {
  7553. type: "wakeup"
  7554. };
  7555. /**
  7556. * Dynamic body.
  7557. * @property DYNAMIC
  7558. * @type {Number}
  7559. * @static
  7560. */
  7561. Body.DYNAMIC = 1;
  7562. /**
  7563. * Static body.
  7564. * @property STATIC
  7565. * @type {Number}
  7566. * @static
  7567. */
  7568. Body.STATIC = 2;
  7569. /**
  7570. * Kinematic body.
  7571. * @property KINEMATIC
  7572. * @type {Number}
  7573. * @static
  7574. */
  7575. Body.KINEMATIC = 4;
  7576. /**
  7577. * @property AWAKE
  7578. * @type {Number}
  7579. * @static
  7580. */
  7581. Body.AWAKE = 0;
  7582. /**
  7583. * @property SLEEPY
  7584. * @type {Number}
  7585. * @static
  7586. */
  7587. Body.SLEEPY = 1;
  7588. /**
  7589. * @property SLEEPING
  7590. * @type {Number}
  7591. * @static
  7592. */
  7593. Body.SLEEPING = 2;
  7594. },{"../collision/AABB":7,"../collision/Ray":11,"../collision/RaycastResult":12,"../events/EventEmitter":26,"../math/vec2":30,"../shapes/Convex":40,"poly-decomp":5}],32:[function(_dereq_,module,exports){
  7595. var vec2 = _dereq_('../math/vec2');
  7596. var Spring = _dereq_('./Spring');
  7597. var Utils = _dereq_('../utils/Utils');
  7598. module.exports = LinearSpring;
  7599. /**
  7600. * A spring, connecting two bodies.
  7601. *
  7602. * The Spring explicitly adds force and angularForce to the bodies.
  7603. *
  7604. * @class LinearSpring
  7605. * @extends Spring
  7606. * @constructor
  7607. * @param {Body} bodyA
  7608. * @param {Body} bodyB
  7609. * @param {Object} [options]
  7610. * @param {number} [options.restLength] A number > 0. Default is the current distance between the world anchor points.
  7611. * @param {number} [options.stiffness=100] Spring constant (see Hookes Law). A number >= 0.
  7612. * @param {number} [options.damping=1] A number >= 0. Default: 1
  7613. * @param {Array} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates. Overrides the option "localAnchorA" if given.
  7614. * @param {Array} [options.worldAnchorB]
  7615. * @param {Array} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates. Defaults to the body center.
  7616. * @param {Array} [options.localAnchorB]
  7617. */
  7618. function LinearSpring(bodyA,bodyB,options){
  7619. options = options || {};
  7620. Spring.call(this, bodyA, bodyB, options);
  7621. /**
  7622. * Anchor for bodyA in local bodyA coordinates.
  7623. * @property localAnchorA
  7624. * @type {Array}
  7625. */
  7626. this.localAnchorA = vec2.fromValues(0,0);
  7627. /**
  7628. * Anchor for bodyB in local bodyB coordinates.
  7629. * @property localAnchorB
  7630. * @type {Array}
  7631. */
  7632. this.localAnchorB = vec2.fromValues(0,0);
  7633. if(options.localAnchorA){ vec2.copy(this.localAnchorA, options.localAnchorA); }
  7634. if(options.localAnchorB){ vec2.copy(this.localAnchorB, options.localAnchorB); }
  7635. if(options.worldAnchorA){ this.setWorldAnchorA(options.worldAnchorA); }
  7636. if(options.worldAnchorB){ this.setWorldAnchorB(options.worldAnchorB); }
  7637. var worldAnchorA = vec2.create();
  7638. var worldAnchorB = vec2.create();
  7639. this.getWorldAnchorA(worldAnchorA);
  7640. this.getWorldAnchorB(worldAnchorB);
  7641. var worldDistance = vec2.distance(worldAnchorA, worldAnchorB);
  7642. /**
  7643. * Rest length of the spring.
  7644. * @property restLength
  7645. * @type {number}
  7646. */
  7647. this.restLength = typeof(options.restLength) === "number" ? options.restLength : worldDistance;
  7648. }
  7649. LinearSpring.prototype = new Spring();
  7650. LinearSpring.prototype.constructor = LinearSpring;
  7651. /**
  7652. * Set the anchor point on body A, using world coordinates.
  7653. * @method setWorldAnchorA
  7654. * @param {Array} worldAnchorA
  7655. */
  7656. LinearSpring.prototype.setWorldAnchorA = function(worldAnchorA){
  7657. this.bodyA.toLocalFrame(this.localAnchorA, worldAnchorA);
  7658. };
  7659. /**
  7660. * Set the anchor point on body B, using world coordinates.
  7661. * @method setWorldAnchorB
  7662. * @param {Array} worldAnchorB
  7663. */
  7664. LinearSpring.prototype.setWorldAnchorB = function(worldAnchorB){
  7665. this.bodyB.toLocalFrame(this.localAnchorB, worldAnchorB);
  7666. };
  7667. /**
  7668. * Get the anchor point on body A, in world coordinates.
  7669. * @method getWorldAnchorA
  7670. * @param {Array} result The vector to store the result in.
  7671. */
  7672. LinearSpring.prototype.getWorldAnchorA = function(result){
  7673. this.bodyA.toWorldFrame(result, this.localAnchorA);
  7674. };
  7675. /**
  7676. * Get the anchor point on body B, in world coordinates.
  7677. * @method getWorldAnchorB
  7678. * @param {Array} result The vector to store the result in.
  7679. */
  7680. LinearSpring.prototype.getWorldAnchorB = function(result){
  7681. this.bodyB.toWorldFrame(result, this.localAnchorB);
  7682. };
  7683. var applyForce_r = vec2.create(),
  7684. applyForce_r_unit = vec2.create(),
  7685. applyForce_u = vec2.create(),
  7686. applyForce_f = vec2.create(),
  7687. applyForce_worldAnchorA = vec2.create(),
  7688. applyForce_worldAnchorB = vec2.create(),
  7689. applyForce_ri = vec2.create(),
  7690. applyForce_rj = vec2.create(),
  7691. applyForce_tmp = vec2.create();
  7692. /**
  7693. * Apply the spring force to the connected bodies.
  7694. * @method applyForce
  7695. */
  7696. LinearSpring.prototype.applyForce = function(){
  7697. var k = this.stiffness,
  7698. d = this.damping,
  7699. l = this.restLength,
  7700. bodyA = this.bodyA,
  7701. bodyB = this.bodyB,
  7702. r = applyForce_r,
  7703. r_unit = applyForce_r_unit,
  7704. u = applyForce_u,
  7705. f = applyForce_f,
  7706. tmp = applyForce_tmp;
  7707. var worldAnchorA = applyForce_worldAnchorA,
  7708. worldAnchorB = applyForce_worldAnchorB,
  7709. ri = applyForce_ri,
  7710. rj = applyForce_rj;
  7711. // Get world anchors
  7712. this.getWorldAnchorA(worldAnchorA);
  7713. this.getWorldAnchorB(worldAnchorB);
  7714. // Get offset points
  7715. vec2.sub(ri, worldAnchorA, bodyA.position);
  7716. vec2.sub(rj, worldAnchorB, bodyB.position);
  7717. // Compute distance vector between world anchor points
  7718. vec2.sub(r, worldAnchorB, worldAnchorA);
  7719. var rlen = vec2.len(r);
  7720. vec2.normalize(r_unit,r);
  7721. //console.log(rlen)
  7722. //console.log("A",vec2.str(worldAnchorA),"B",vec2.str(worldAnchorB))
  7723. // Compute relative velocity of the anchor points, u
  7724. vec2.sub(u, bodyB.velocity, bodyA.velocity);
  7725. vec2.crossZV(tmp, bodyB.angularVelocity, rj);
  7726. vec2.add(u, u, tmp);
  7727. vec2.crossZV(tmp, bodyA.angularVelocity, ri);
  7728. vec2.sub(u, u, tmp);
  7729. // F = - k * ( x - L ) - D * ( u )
  7730. vec2.scale(f, r_unit, -k*(rlen-l) - d*vec2.dot(u,r_unit));
  7731. // Add forces to bodies
  7732. vec2.sub( bodyA.force, bodyA.force, f);
  7733. vec2.add( bodyB.force, bodyB.force, f);
  7734. // Angular force
  7735. var ri_x_f = vec2.crossLength(ri, f);
  7736. var rj_x_f = vec2.crossLength(rj, f);
  7737. bodyA.angularForce -= ri_x_f;
  7738. bodyB.angularForce += rj_x_f;
  7739. };
  7740. },{"../math/vec2":30,"../utils/Utils":57,"./Spring":34}],33:[function(_dereq_,module,exports){
  7741. var vec2 = _dereq_('../math/vec2');
  7742. var Spring = _dereq_('./Spring');
  7743. module.exports = RotationalSpring;
  7744. /**
  7745. * A rotational spring, connecting two bodies rotation. This spring explicitly adds angularForce (torque) to the bodies.
  7746. *
  7747. * The spring can be combined with a {{#crossLink "RevoluteConstraint"}}{{/crossLink}} to make, for example, a mouse trap.
  7748. *
  7749. * @class RotationalSpring
  7750. * @extends Spring
  7751. * @constructor
  7752. * @param {Body} bodyA
  7753. * @param {Body} bodyB
  7754. * @param {Object} [options]
  7755. * @param {number} [options.restAngle] The relative angle of bodies at which the spring is at rest. If not given, it's set to the current relative angle between the bodies.
  7756. * @param {number} [options.stiffness=100] Spring constant (see Hookes Law). A number >= 0.
  7757. * @param {number} [options.damping=1] A number >= 0.
  7758. */
  7759. function RotationalSpring(bodyA, bodyB, options){
  7760. options = options || {};
  7761. Spring.call(this, bodyA, bodyB, options);
  7762. /**
  7763. * Rest angle of the spring.
  7764. * @property restAngle
  7765. * @type {number}
  7766. */
  7767. this.restAngle = typeof(options.restAngle) === "number" ? options.restAngle : bodyB.angle - bodyA.angle;
  7768. }
  7769. RotationalSpring.prototype = new Spring();
  7770. RotationalSpring.prototype.constructor = RotationalSpring;
  7771. /**
  7772. * Apply the spring force to the connected bodies.
  7773. * @method applyForce
  7774. */
  7775. RotationalSpring.prototype.applyForce = function(){
  7776. var k = this.stiffness,
  7777. d = this.damping,
  7778. l = this.restAngle,
  7779. bodyA = this.bodyA,
  7780. bodyB = this.bodyB,
  7781. x = bodyB.angle - bodyA.angle,
  7782. u = bodyB.angularVelocity - bodyA.angularVelocity;
  7783. var torque = - k * (x - l) - d * u * 0;
  7784. bodyA.angularForce -= torque;
  7785. bodyB.angularForce += torque;
  7786. };
  7787. },{"../math/vec2":30,"./Spring":34}],34:[function(_dereq_,module,exports){
  7788. var vec2 = _dereq_('../math/vec2');
  7789. var Utils = _dereq_('../utils/Utils');
  7790. module.exports = Spring;
  7791. /**
  7792. * A spring, connecting two bodies. The Spring explicitly adds force and angularForce to the bodies and does therefore not put load on the constraint solver.
  7793. *
  7794. * @class Spring
  7795. * @constructor
  7796. * @param {Body} bodyA
  7797. * @param {Body} bodyB
  7798. * @param {Object} [options]
  7799. * @param {number} [options.stiffness=100] Spring constant (see Hookes Law). A number >= 0.
  7800. * @param {number} [options.damping=1] A number >= 0. Default: 1
  7801. * @param {Array} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates. Defaults to the body center.
  7802. * @param {Array} [options.localAnchorB]
  7803. * @param {Array} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates. Overrides the option "localAnchorA" if given.
  7804. * @param {Array} [options.worldAnchorB]
  7805. */
  7806. function Spring(bodyA, bodyB, options){
  7807. options = Utils.defaults(options,{
  7808. stiffness: 100,
  7809. damping: 1,
  7810. });
  7811. /**
  7812. * Stiffness of the spring.
  7813. * @property stiffness
  7814. * @type {number}
  7815. */
  7816. this.stiffness = options.stiffness;
  7817. /**
  7818. * Damping of the spring.
  7819. * @property damping
  7820. * @type {number}
  7821. */
  7822. this.damping = options.damping;
  7823. /**
  7824. * First connected body.
  7825. * @property bodyA
  7826. * @type {Body}
  7827. */
  7828. this.bodyA = bodyA;
  7829. /**
  7830. * Second connected body.
  7831. * @property bodyB
  7832. * @type {Body}
  7833. */
  7834. this.bodyB = bodyB;
  7835. }
  7836. /**
  7837. * Apply the spring force to the connected bodies.
  7838. * @method applyForce
  7839. */
  7840. Spring.prototype.applyForce = function(){
  7841. // To be implemented by subclasses
  7842. };
  7843. },{"../math/vec2":30,"../utils/Utils":57}],35:[function(_dereq_,module,exports){
  7844. var vec2 = _dereq_('../math/vec2');
  7845. var Utils = _dereq_('../utils/Utils');
  7846. var Constraint = _dereq_('../constraints/Constraint');
  7847. var FrictionEquation = _dereq_('../equations/FrictionEquation');
  7848. var Body = _dereq_('../objects/Body');
  7849. module.exports = TopDownVehicle;
  7850. /**
  7851. * @class TopDownVehicle
  7852. * @constructor
  7853. * @param {Body} chassisBody A dynamic body, already added to the world.
  7854. * @param {Object} [options]
  7855. *
  7856. * @example
  7857. *
  7858. * // Create a dynamic body for the chassis
  7859. * var chassisBody = new Body({
  7860. * mass: 1
  7861. * });
  7862. * var boxShape = new Box({ width: 0.5, height: 1 });
  7863. * chassisBody.addShape(boxShape);
  7864. * world.addBody(chassisBody);
  7865. *
  7866. * // Create the vehicle
  7867. * var vehicle = new TopDownVehicle(chassisBody);
  7868. *
  7869. * // Add one front wheel and one back wheel - we don't actually need four :)
  7870. * var frontWheel = vehicle.addWheel({
  7871. * localPosition: [0, 0.5] // front
  7872. * });
  7873. * frontWheel.setSideFriction(4);
  7874. *
  7875. * // Back wheel
  7876. * var backWheel = vehicle.addWheel({
  7877. * localPosition: [0, -0.5] // back
  7878. * });
  7879. * backWheel.setSideFriction(3); // Less side friction on back wheel makes it easier to drift
  7880. * vehicle.addToWorld(world);
  7881. *
  7882. * // Steer value zero means straight forward. Positive is left and negative right.
  7883. * frontWheel.steerValue = Math.PI / 16;
  7884. *
  7885. * // Engine force forward
  7886. * backWheel.engineForce = 10;
  7887. * backWheel.setBrakeForce(0);
  7888. */
  7889. function TopDownVehicle(chassisBody, options){
  7890. options = options || {};
  7891. /**
  7892. * @property {Body} chassisBody
  7893. */
  7894. this.chassisBody = chassisBody;
  7895. /**
  7896. * @property {Array} wheels
  7897. */
  7898. this.wheels = [];
  7899. // A dummy body to constrain the chassis to
  7900. this.groundBody = new Body({ mass: 0 });
  7901. this.world = null;
  7902. var that = this;
  7903. this.preStepCallback = function(){
  7904. that.update();
  7905. };
  7906. }
  7907. /**
  7908. * @method addToWorld
  7909. * @param {World} world
  7910. */
  7911. TopDownVehicle.prototype.addToWorld = function(world){
  7912. this.world = world;
  7913. world.addBody(this.groundBody);
  7914. world.on('preStep', this.preStepCallback);
  7915. for (var i = 0; i < this.wheels.length; i++) {
  7916. var wheel = this.wheels[i];
  7917. world.addConstraint(wheel);
  7918. }
  7919. };
  7920. /**
  7921. * @method removeFromWorld
  7922. * @param {World} world
  7923. */
  7924. TopDownVehicle.prototype.removeFromWorld = function(){
  7925. var world = this.world;
  7926. world.removeBody(this.groundBody);
  7927. world.off('preStep', this.preStepCallback);
  7928. for (var i = 0; i < this.wheels.length; i++) {
  7929. var wheel = this.wheels[i];
  7930. world.removeConstraint(wheel);
  7931. }
  7932. this.world = null;
  7933. };
  7934. /**
  7935. * @method addWheel
  7936. * @param {object} [wheelOptions]
  7937. * @return {WheelConstraint}
  7938. */
  7939. TopDownVehicle.prototype.addWheel = function(wheelOptions){
  7940. var wheel = new WheelConstraint(this,wheelOptions);
  7941. this.wheels.push(wheel);
  7942. return wheel;
  7943. };
  7944. /**
  7945. * @method update
  7946. */
  7947. TopDownVehicle.prototype.update = function(){
  7948. for (var i = 0; i < this.wheels.length; i++) {
  7949. this.wheels[i].update();
  7950. }
  7951. };
  7952. /**
  7953. * @class WheelConstraint
  7954. * @constructor
  7955. * @extends {Constraint}
  7956. * @param {Vehicle} vehicle
  7957. * @param {object} [options]
  7958. * @param {Array} [options.localForwardVector]The local wheel forward vector in local body space. Default is zero.
  7959. * @param {Array} [options.localPosition] The local position of the wheen in the chassis body. Default is zero - the center of the body.
  7960. * @param {Array} [options.sideFriction=5] The max friction force in the sideways direction.
  7961. */
  7962. function WheelConstraint(vehicle, options){
  7963. options = options || {};
  7964. this.vehicle = vehicle;
  7965. this.forwardEquation = new FrictionEquation(vehicle.chassisBody, vehicle.groundBody);
  7966. this.sideEquation = new FrictionEquation(vehicle.chassisBody, vehicle.groundBody);
  7967. /**
  7968. * @property {number} steerValue
  7969. */
  7970. this.steerValue = 0;
  7971. /**
  7972. * @property {number} engineForce
  7973. */
  7974. this.engineForce = 0;
  7975. this.setSideFriction(options.sideFriction !== undefined ? options.sideFriction : 5);
  7976. /**
  7977. * @property {Array} localForwardVector
  7978. */
  7979. this.localForwardVector = vec2.fromValues(0, 1);
  7980. if(options.localForwardVector){
  7981. vec2.copy(this.localForwardVector, options.localForwardVector);
  7982. }
  7983. /**
  7984. * @property {Array} localPosition
  7985. */
  7986. this.localPosition = vec2.fromValues(0, 0);
  7987. if(options.localPosition){
  7988. vec2.copy(this.localPosition, options.localPosition);
  7989. }
  7990. Constraint.apply(this, vehicle.chassisBody, vehicle.groundBody);
  7991. this.equations.push(
  7992. this.forwardEquation,
  7993. this.sideEquation
  7994. );
  7995. this.setBrakeForce(0);
  7996. }
  7997. WheelConstraint.prototype = new Constraint();
  7998. /**
  7999. * @method setForwardFriction
  8000. */
  8001. WheelConstraint.prototype.setBrakeForce = function(force){
  8002. this.forwardEquation.setSlipForce(force);
  8003. };
  8004. /**
  8005. * @method setSideFriction
  8006. */
  8007. WheelConstraint.prototype.setSideFriction = function(force){
  8008. this.sideEquation.setSlipForce(force);
  8009. };
  8010. var worldVelocity = vec2.create();
  8011. var relativePoint = vec2.create();
  8012. /**
  8013. * @method getSpeed
  8014. */
  8015. WheelConstraint.prototype.getSpeed = function(){
  8016. this.vehicle.chassisBody.vectorToWorldFrame(relativePoint, this.localForwardVector);
  8017. this.vehicle.chassisBody.getVelocityAtPoint(worldVelocity, relativePoint);
  8018. return vec2.dot(worldVelocity, relativePoint);
  8019. };
  8020. var tmpVec = vec2.create();
  8021. /**
  8022. * @method update
  8023. */
  8024. WheelConstraint.prototype.update = function(){
  8025. // Directional
  8026. this.vehicle.chassisBody.vectorToWorldFrame(this.forwardEquation.t, this.localForwardVector);
  8027. vec2.rotate(this.sideEquation.t, this.localForwardVector, Math.PI / 2);
  8028. this.vehicle.chassisBody.vectorToWorldFrame(this.sideEquation.t, this.sideEquation.t);
  8029. vec2.rotate(this.forwardEquation.t, this.forwardEquation.t, this.steerValue);
  8030. vec2.rotate(this.sideEquation.t, this.sideEquation.t, this.steerValue);
  8031. // Attachment point
  8032. this.vehicle.chassisBody.toWorldFrame(this.forwardEquation.contactPointB, this.localPosition);
  8033. vec2.copy(this.sideEquation.contactPointB, this.forwardEquation.contactPointB);
  8034. this.vehicle.chassisBody.vectorToWorldFrame(this.forwardEquation.contactPointA, this.localPosition);
  8035. vec2.copy(this.sideEquation.contactPointA, this.forwardEquation.contactPointA);
  8036. // Add engine force
  8037. vec2.normalize(tmpVec, this.forwardEquation.t);
  8038. vec2.scale(tmpVec, tmpVec, this.engineForce);
  8039. this.vehicle.chassisBody.applyForce(tmpVec, this.forwardEquation.contactPointA);
  8040. };
  8041. },{"../constraints/Constraint":14,"../equations/FrictionEquation":23,"../math/vec2":30,"../objects/Body":31,"../utils/Utils":57}],36:[function(_dereq_,module,exports){
  8042. // Export p2 classes
  8043. var p2 = module.exports = {
  8044. AABB : _dereq_('./collision/AABB'),
  8045. AngleLockEquation : _dereq_('./equations/AngleLockEquation'),
  8046. Body : _dereq_('./objects/Body'),
  8047. Broadphase : _dereq_('./collision/Broadphase'),
  8048. Capsule : _dereq_('./shapes/Capsule'),
  8049. Circle : _dereq_('./shapes/Circle'),
  8050. Constraint : _dereq_('./constraints/Constraint'),
  8051. ContactEquation : _dereq_('./equations/ContactEquation'),
  8052. ContactEquationPool : _dereq_('./utils/ContactEquationPool'),
  8053. ContactMaterial : _dereq_('./material/ContactMaterial'),
  8054. Convex : _dereq_('./shapes/Convex'),
  8055. DistanceConstraint : _dereq_('./constraints/DistanceConstraint'),
  8056. Equation : _dereq_('./equations/Equation'),
  8057. EventEmitter : _dereq_('./events/EventEmitter'),
  8058. FrictionEquation : _dereq_('./equations/FrictionEquation'),
  8059. FrictionEquationPool : _dereq_('./utils/FrictionEquationPool'),
  8060. GearConstraint : _dereq_('./constraints/GearConstraint'),
  8061. GSSolver : _dereq_('./solver/GSSolver'),
  8062. Heightfield : _dereq_('./shapes/Heightfield'),
  8063. Line : _dereq_('./shapes/Line'),
  8064. LockConstraint : _dereq_('./constraints/LockConstraint'),
  8065. Material : _dereq_('./material/Material'),
  8066. Narrowphase : _dereq_('./collision/Narrowphase'),
  8067. NaiveBroadphase : _dereq_('./collision/NaiveBroadphase'),
  8068. Particle : _dereq_('./shapes/Particle'),
  8069. Plane : _dereq_('./shapes/Plane'),
  8070. Pool : _dereq_('./utils/Pool'),
  8071. RevoluteConstraint : _dereq_('./constraints/RevoluteConstraint'),
  8072. PrismaticConstraint : _dereq_('./constraints/PrismaticConstraint'),
  8073. Ray : _dereq_('./collision/Ray'),
  8074. RaycastResult : _dereq_('./collision/RaycastResult'),
  8075. Box : _dereq_('./shapes/Box'),
  8076. RotationalVelocityEquation : _dereq_('./equations/RotationalVelocityEquation'),
  8077. SAPBroadphase : _dereq_('./collision/SAPBroadphase'),
  8078. Shape : _dereq_('./shapes/Shape'),
  8079. Solver : _dereq_('./solver/Solver'),
  8080. Spring : _dereq_('./objects/Spring'),
  8081. TopDownVehicle : _dereq_('./objects/TopDownVehicle'),
  8082. LinearSpring : _dereq_('./objects/LinearSpring'),
  8083. RotationalSpring : _dereq_('./objects/RotationalSpring'),
  8084. Utils : _dereq_('./utils/Utils'),
  8085. World : _dereq_('./world/World'),
  8086. vec2 : _dereq_('./math/vec2'),
  8087. version : _dereq_('../package.json').version,
  8088. };
  8089. Object.defineProperty(p2, 'Rectangle', {
  8090. get: function() {
  8091. console.warn('The Rectangle class has been renamed to Box.');
  8092. return this.Box;
  8093. }
  8094. });
  8095. },{"../package.json":6,"./collision/AABB":7,"./collision/Broadphase":8,"./collision/NaiveBroadphase":9,"./collision/Narrowphase":10,"./collision/Ray":11,"./collision/RaycastResult":12,"./collision/SAPBroadphase":13,"./constraints/Constraint":14,"./constraints/DistanceConstraint":15,"./constraints/GearConstraint":16,"./constraints/LockConstraint":17,"./constraints/PrismaticConstraint":18,"./constraints/RevoluteConstraint":19,"./equations/AngleLockEquation":20,"./equations/ContactEquation":21,"./equations/Equation":22,"./equations/FrictionEquation":23,"./equations/RotationalVelocityEquation":25,"./events/EventEmitter":26,"./material/ContactMaterial":27,"./material/Material":28,"./math/vec2":30,"./objects/Body":31,"./objects/LinearSpring":32,"./objects/RotationalSpring":33,"./objects/Spring":34,"./objects/TopDownVehicle":35,"./shapes/Box":37,"./shapes/Capsule":38,"./shapes/Circle":39,"./shapes/Convex":40,"./shapes/Heightfield":41,"./shapes/Line":42,"./shapes/Particle":43,"./shapes/Plane":44,"./shapes/Shape":45,"./solver/GSSolver":46,"./solver/Solver":47,"./utils/ContactEquationPool":48,"./utils/FrictionEquationPool":49,"./utils/Pool":55,"./utils/Utils":57,"./world/World":61}],37:[function(_dereq_,module,exports){
  8096. var vec2 = _dereq_('../math/vec2')
  8097. , Shape = _dereq_('./Shape')
  8098. , Convex = _dereq_('./Convex');
  8099. module.exports = Box;
  8100. /**
  8101. * Box shape class.
  8102. * @class Box
  8103. * @constructor
  8104. * @param {object} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  8105. * @param {Number} [options.width=1] Total width of the box
  8106. * @param {Number} [options.height=1] Total height of the box
  8107. * @extends Convex
  8108. */
  8109. function Box(options){
  8110. if(typeof(arguments[0]) === 'number' && typeof(arguments[1]) === 'number'){
  8111. options = {
  8112. width: arguments[0],
  8113. height: arguments[1]
  8114. };
  8115. console.warn('The Rectangle has been renamed to Box and its constructor signature has changed. Please use the following format: new Box({ width: 1, height: 1, ... })');
  8116. }
  8117. options = options || {};
  8118. /**
  8119. * Total width of the box
  8120. * @property width
  8121. * @type {Number}
  8122. */
  8123. var width = this.width = options.width || 1;
  8124. /**
  8125. * Total height of the box
  8126. * @property height
  8127. * @type {Number}
  8128. */
  8129. var height = this.height = options.height || 1;
  8130. var verts = [
  8131. vec2.fromValues(-width/2, -height/2),
  8132. vec2.fromValues( width/2, -height/2),
  8133. vec2.fromValues( width/2, height/2),
  8134. vec2.fromValues(-width/2, height/2)
  8135. ];
  8136. var axes = [
  8137. vec2.fromValues(1, 0),
  8138. vec2.fromValues(0, 1)
  8139. ];
  8140. options.vertices = verts;
  8141. options.axes = axes;
  8142. options.type = Shape.BOX;
  8143. Convex.call(this, options);
  8144. }
  8145. Box.prototype = new Convex();
  8146. Box.prototype.constructor = Box;
  8147. /**
  8148. * Compute moment of inertia
  8149. * @method computeMomentOfInertia
  8150. * @param {Number} mass
  8151. * @return {Number}
  8152. */
  8153. Box.prototype.computeMomentOfInertia = function(mass){
  8154. var w = this.width,
  8155. h = this.height;
  8156. return mass * (h*h + w*w) / 12;
  8157. };
  8158. /**
  8159. * Update the bounding radius
  8160. * @method updateBoundingRadius
  8161. */
  8162. Box.prototype.updateBoundingRadius = function(){
  8163. var w = this.width,
  8164. h = this.height;
  8165. this.boundingRadius = Math.sqrt(w*w + h*h) / 2;
  8166. };
  8167. var corner1 = vec2.create(),
  8168. corner2 = vec2.create(),
  8169. corner3 = vec2.create(),
  8170. corner4 = vec2.create();
  8171. /**
  8172. * @method computeAABB
  8173. * @param {AABB} out The resulting AABB.
  8174. * @param {Array} position
  8175. * @param {Number} angle
  8176. */
  8177. Box.prototype.computeAABB = function(out, position, angle){
  8178. out.setFromPoints(this.vertices,position,angle,0);
  8179. };
  8180. Box.prototype.updateArea = function(){
  8181. this.area = this.width * this.height;
  8182. };
  8183. },{"../math/vec2":30,"./Convex":40,"./Shape":45}],38:[function(_dereq_,module,exports){
  8184. var Shape = _dereq_('./Shape')
  8185. , vec2 = _dereq_('../math/vec2');
  8186. module.exports = Capsule;
  8187. /**
  8188. * Capsule shape class.
  8189. * @class Capsule
  8190. * @constructor
  8191. * @extends Shape
  8192. * @param {object} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  8193. * @param {Number} [options.length=1] The distance between the end points
  8194. * @param {Number} [options.radius=1] Radius of the capsule
  8195. * @example
  8196. * var capsuleShape = new Capsule({
  8197. * length: 1,
  8198. * radius: 2
  8199. * });
  8200. * body.addShape(capsuleShape);
  8201. */
  8202. function Capsule(options){
  8203. if(typeof(arguments[0]) === 'number' && typeof(arguments[1]) === 'number'){
  8204. options = {
  8205. length: arguments[0],
  8206. radius: arguments[1]
  8207. };
  8208. console.warn('The Capsule constructor signature has changed. Please use the following format: new Capsule({ radius: 1, length: 1 })');
  8209. }
  8210. options = options || {};
  8211. /**
  8212. * The distance between the end points.
  8213. * @property {Number} length
  8214. */
  8215. this.length = options.length || 1;
  8216. /**
  8217. * The radius of the capsule.
  8218. * @property {Number} radius
  8219. */
  8220. this.radius = options.radius || 1;
  8221. options.type = Shape.CAPSULE;
  8222. Shape.call(this, options);
  8223. }
  8224. Capsule.prototype = new Shape();
  8225. Capsule.prototype.constructor = Capsule;
  8226. /**
  8227. * Compute the mass moment of inertia of the Capsule.
  8228. * @method conputeMomentOfInertia
  8229. * @param {Number} mass
  8230. * @return {Number}
  8231. * @todo
  8232. */
  8233. Capsule.prototype.computeMomentOfInertia = function(mass){
  8234. // Approximate with rectangle
  8235. var r = this.radius,
  8236. w = this.length + r, // 2*r is too much, 0 is too little
  8237. h = r*2;
  8238. return mass * (h*h + w*w) / 12;
  8239. };
  8240. /**
  8241. * @method updateBoundingRadius
  8242. */
  8243. Capsule.prototype.updateBoundingRadius = function(){
  8244. this.boundingRadius = this.radius + this.length/2;
  8245. };
  8246. /**
  8247. * @method updateArea
  8248. */
  8249. Capsule.prototype.updateArea = function(){
  8250. this.area = Math.PI * this.radius * this.radius + this.radius * 2 * this.length;
  8251. };
  8252. var r = vec2.create();
  8253. /**
  8254. * @method computeAABB
  8255. * @param {AABB} out The resulting AABB.
  8256. * @param {Array} position
  8257. * @param {Number} angle
  8258. */
  8259. Capsule.prototype.computeAABB = function(out, position, angle){
  8260. var radius = this.radius;
  8261. // Compute center position of one of the the circles, world oriented, but with local offset
  8262. vec2.set(r,this.length / 2,0);
  8263. if(angle !== 0){
  8264. vec2.rotate(r,r,angle);
  8265. }
  8266. // Get bounds
  8267. vec2.set(out.upperBound, Math.max(r[0]+radius, -r[0]+radius),
  8268. Math.max(r[1]+radius, -r[1]+radius));
  8269. vec2.set(out.lowerBound, Math.min(r[0]-radius, -r[0]-radius),
  8270. Math.min(r[1]-radius, -r[1]-radius));
  8271. // Add offset
  8272. vec2.add(out.lowerBound, out.lowerBound, position);
  8273. vec2.add(out.upperBound, out.upperBound, position);
  8274. };
  8275. var intersectCapsule_hitPointWorld = vec2.create();
  8276. var intersectCapsule_normal = vec2.create();
  8277. var intersectCapsule_l0 = vec2.create();
  8278. var intersectCapsule_l1 = vec2.create();
  8279. var intersectCapsule_unit_y = vec2.fromValues(0,1);
  8280. /**
  8281. * @method raycast
  8282. * @param {RaycastResult} result
  8283. * @param {Ray} ray
  8284. * @param {array} position
  8285. * @param {number} angle
  8286. */
  8287. Capsule.prototype.raycast = function(result, ray, position, angle){
  8288. var from = ray.from;
  8289. var to = ray.to;
  8290. var direction = ray.direction;
  8291. var hitPointWorld = intersectCapsule_hitPointWorld;
  8292. var normal = intersectCapsule_normal;
  8293. var l0 = intersectCapsule_l0;
  8294. var l1 = intersectCapsule_l1;
  8295. // The sides
  8296. var halfLen = this.length / 2;
  8297. for(var i=0; i<2; i++){
  8298. // get start and end of the line
  8299. var y = this.radius * (i*2-1);
  8300. vec2.set(l0, -halfLen, y);
  8301. vec2.set(l1, halfLen, y);
  8302. vec2.toGlobalFrame(l0, l0, position, angle);
  8303. vec2.toGlobalFrame(l1, l1, position, angle);
  8304. var delta = vec2.getLineSegmentsIntersectionFraction(from, to, l0, l1);
  8305. if(delta >= 0){
  8306. vec2.rotate(normal, intersectCapsule_unit_y, angle);
  8307. vec2.scale(normal, normal, (i*2-1));
  8308. ray.reportIntersection(result, delta, normal, -1);
  8309. if(result.shouldStop(ray)){
  8310. return;
  8311. }
  8312. }
  8313. }
  8314. // Circles
  8315. var diagonalLengthSquared = Math.pow(this.radius, 2) + Math.pow(halfLen, 2);
  8316. for(var i=0; i<2; i++){
  8317. vec2.set(l0, halfLen * (i*2-1), 0);
  8318. vec2.toGlobalFrame(l0, l0, position, angle);
  8319. var a = Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2);
  8320. var b = 2 * ((to[0] - from[0]) * (from[0] - l0[0]) + (to[1] - from[1]) * (from[1] - l0[1]));
  8321. var c = Math.pow(from[0] - l0[0], 2) + Math.pow(from[1] - l0[1], 2) - Math.pow(this.radius, 2);
  8322. var delta = Math.pow(b, 2) - 4 * a * c;
  8323. if(delta < 0){
  8324. // No intersection
  8325. continue;
  8326. } else if(delta === 0){
  8327. // single intersection point
  8328. vec2.lerp(hitPointWorld, from, to, delta);
  8329. if(vec2.squaredDistance(hitPointWorld, position) > diagonalLengthSquared){
  8330. vec2.sub(normal, hitPointWorld, l0);
  8331. vec2.normalize(normal,normal);
  8332. ray.reportIntersection(result, delta, normal, -1);
  8333. if(result.shouldStop(ray)){
  8334. return;
  8335. }
  8336. }
  8337. } else {
  8338. var sqrtDelta = Math.sqrt(delta);
  8339. var inv2a = 1 / (2 * a);
  8340. var d1 = (- b - sqrtDelta) * inv2a;
  8341. var d2 = (- b + sqrtDelta) * inv2a;
  8342. if(d1 >= 0 && d1 <= 1){
  8343. vec2.lerp(hitPointWorld, from, to, d1);
  8344. if(vec2.squaredDistance(hitPointWorld, position) > diagonalLengthSquared){
  8345. vec2.sub(normal, hitPointWorld, l0);
  8346. vec2.normalize(normal,normal);
  8347. ray.reportIntersection(result, d1, normal, -1);
  8348. if(result.shouldStop(ray)){
  8349. return;
  8350. }
  8351. }
  8352. }
  8353. if(d2 >= 0 && d2 <= 1){
  8354. vec2.lerp(hitPointWorld, from, to, d2);
  8355. if(vec2.squaredDistance(hitPointWorld, position) > diagonalLengthSquared){
  8356. vec2.sub(normal, hitPointWorld, l0);
  8357. vec2.normalize(normal,normal);
  8358. ray.reportIntersection(result, d2, normal, -1);
  8359. if(result.shouldStop(ray)){
  8360. return;
  8361. }
  8362. }
  8363. }
  8364. }
  8365. }
  8366. };
  8367. },{"../math/vec2":30,"./Shape":45}],39:[function(_dereq_,module,exports){
  8368. var Shape = _dereq_('./Shape')
  8369. , vec2 = _dereq_('../math/vec2');
  8370. module.exports = Circle;
  8371. /**
  8372. * Circle shape class.
  8373. * @class Circle
  8374. * @extends Shape
  8375. * @constructor
  8376. * @param {options} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  8377. * @param {number} [options.radius=1] The radius of this circle
  8378. *
  8379. * @example
  8380. * var circleShape = new Circle({ radius: 1 });
  8381. * body.addShape(circleShape);
  8382. */
  8383. function Circle(options){
  8384. if(typeof(arguments[0]) === 'number'){
  8385. options = {
  8386. radius: arguments[0]
  8387. };
  8388. console.warn('The Circle constructor signature has changed. Please use the following format: new Circle({ radius: 1 })');
  8389. }
  8390. options = options || {};
  8391. /**
  8392. * The radius of the circle.
  8393. * @property radius
  8394. * @type {number}
  8395. */
  8396. this.radius = options.radius || 1;
  8397. options.type = Shape.CIRCLE;
  8398. Shape.call(this, options);
  8399. }
  8400. Circle.prototype = new Shape();
  8401. Circle.prototype.constructor = Circle;
  8402. /**
  8403. * @method computeMomentOfInertia
  8404. * @param {Number} mass
  8405. * @return {Number}
  8406. */
  8407. Circle.prototype.computeMomentOfInertia = function(mass){
  8408. var r = this.radius;
  8409. return mass * r * r / 2;
  8410. };
  8411. /**
  8412. * @method updateBoundingRadius
  8413. * @return {Number}
  8414. */
  8415. Circle.prototype.updateBoundingRadius = function(){
  8416. this.boundingRadius = this.radius;
  8417. };
  8418. /**
  8419. * @method updateArea
  8420. * @return {Number}
  8421. */
  8422. Circle.prototype.updateArea = function(){
  8423. this.area = Math.PI * this.radius * this.radius;
  8424. };
  8425. /**
  8426. * @method computeAABB
  8427. * @param {AABB} out The resulting AABB.
  8428. * @param {Array} position
  8429. * @param {Number} angle
  8430. */
  8431. Circle.prototype.computeAABB = function(out, position, angle){
  8432. var r = this.radius;
  8433. vec2.set(out.upperBound, r, r);
  8434. vec2.set(out.lowerBound, -r, -r);
  8435. if(position){
  8436. vec2.add(out.lowerBound, out.lowerBound, position);
  8437. vec2.add(out.upperBound, out.upperBound, position);
  8438. }
  8439. };
  8440. var Ray_intersectSphere_intersectionPoint = vec2.create();
  8441. var Ray_intersectSphere_normal = vec2.create();
  8442. /**
  8443. * @method raycast
  8444. * @param {RaycastResult} result
  8445. * @param {Ray} ray
  8446. * @param {array} position
  8447. * @param {number} angle
  8448. */
  8449. Circle.prototype.raycast = function(result, ray, position, angle){
  8450. var from = ray.from,
  8451. to = ray.to,
  8452. r = this.radius;
  8453. var a = Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2);
  8454. var b = 2 * ((to[0] - from[0]) * (from[0] - position[0]) + (to[1] - from[1]) * (from[1] - position[1]));
  8455. var c = Math.pow(from[0] - position[0], 2) + Math.pow(from[1] - position[1], 2) - Math.pow(r, 2);
  8456. var delta = Math.pow(b, 2) - 4 * a * c;
  8457. var intersectionPoint = Ray_intersectSphere_intersectionPoint;
  8458. var normal = Ray_intersectSphere_normal;
  8459. if(delta < 0){
  8460. // No intersection
  8461. return;
  8462. } else if(delta === 0){
  8463. // single intersection point
  8464. vec2.lerp(intersectionPoint, from, to, delta);
  8465. vec2.sub(normal, intersectionPoint, position);
  8466. vec2.normalize(normal,normal);
  8467. ray.reportIntersection(result, delta, normal, -1);
  8468. } else {
  8469. var sqrtDelta = Math.sqrt(delta);
  8470. var inv2a = 1 / (2 * a);
  8471. var d1 = (- b - sqrtDelta) * inv2a;
  8472. var d2 = (- b + sqrtDelta) * inv2a;
  8473. if(d1 >= 0 && d1 <= 1){
  8474. vec2.lerp(intersectionPoint, from, to, d1);
  8475. vec2.sub(normal, intersectionPoint, position);
  8476. vec2.normalize(normal,normal);
  8477. ray.reportIntersection(result, d1, normal, -1);
  8478. if(result.shouldStop(ray)){
  8479. return;
  8480. }
  8481. }
  8482. if(d2 >= 0 && d2 <= 1){
  8483. vec2.lerp(intersectionPoint, from, to, d2);
  8484. vec2.sub(normal, intersectionPoint, position);
  8485. vec2.normalize(normal,normal);
  8486. ray.reportIntersection(result, d2, normal, -1);
  8487. }
  8488. }
  8489. };
  8490. },{"../math/vec2":30,"./Shape":45}],40:[function(_dereq_,module,exports){
  8491. var Shape = _dereq_('./Shape')
  8492. , vec2 = _dereq_('../math/vec2')
  8493. , polyk = _dereq_('../math/polyk')
  8494. , decomp = _dereq_('poly-decomp');
  8495. module.exports = Convex;
  8496. /**
  8497. * Convex shape class.
  8498. * @class Convex
  8499. * @constructor
  8500. * @extends Shape
  8501. * @param {object} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  8502. * @param {Array} [options.vertices] An array of vertices that span this shape. Vertices are given in counter-clockwise (CCW) direction.
  8503. * @param {Array} [options.axes] An array of unit length vectors, representing the symmetry axes in the convex.
  8504. * @example
  8505. * // Create a box
  8506. * var vertices = [[-1,-1], [1,-1], [1,1], [-1,1]];
  8507. * var convexShape = new Convex({ vertices: vertices });
  8508. * body.addShape(convexShape);
  8509. */
  8510. function Convex(options){
  8511. if(Array.isArray(arguments[0])){
  8512. options = {
  8513. vertices: arguments[0],
  8514. axes: arguments[1]
  8515. };
  8516. console.warn('The Convex constructor signature has changed. Please use the following format: new Convex({ vertices: [...], ... })');
  8517. }
  8518. options = options || {};
  8519. /**
  8520. * Vertices defined in the local frame.
  8521. * @property vertices
  8522. * @type {Array}
  8523. */
  8524. this.vertices = [];
  8525. // Copy the verts
  8526. var vertices = options.vertices !== undefined ? options.vertices : [];
  8527. for(var i=0; i < vertices.length; i++){
  8528. var v = vec2.create();
  8529. vec2.copy(v, vertices[i]);
  8530. this.vertices.push(v);
  8531. }
  8532. /**
  8533. * Axes defined in the local frame.
  8534. * @property axes
  8535. * @type {Array}
  8536. */
  8537. this.axes = [];
  8538. if(options.axes){
  8539. // Copy the axes
  8540. for(var i=0; i < options.axes.length; i++){
  8541. var axis = vec2.create();
  8542. vec2.copy(axis, options.axes[i]);
  8543. this.axes.push(axis);
  8544. }
  8545. } else {
  8546. // Construct axes from the vertex data
  8547. for(var i = 0; i < this.vertices.length; i++){
  8548. // Get the world edge
  8549. var worldPoint0 = this.vertices[i];
  8550. var worldPoint1 = this.vertices[(i+1) % this.vertices.length];
  8551. var normal = vec2.create();
  8552. vec2.sub(normal, worldPoint1, worldPoint0);
  8553. // Get normal - just rotate 90 degrees since vertices are given in CCW
  8554. vec2.rotate90cw(normal, normal);
  8555. vec2.normalize(normal, normal);
  8556. this.axes.push(normal);
  8557. }
  8558. }
  8559. /**
  8560. * The center of mass of the Convex
  8561. * @property centerOfMass
  8562. * @type {Array}
  8563. */
  8564. this.centerOfMass = vec2.fromValues(0,0);
  8565. /**
  8566. * Triangulated version of this convex. The structure is Array of 3-Arrays, and each subarray contains 3 integers, referencing the vertices.
  8567. * @property triangles
  8568. * @type {Array}
  8569. */
  8570. this.triangles = [];
  8571. if(this.vertices.length){
  8572. this.updateTriangles();
  8573. this.updateCenterOfMass();
  8574. }
  8575. /**
  8576. * The bounding radius of the convex
  8577. * @property boundingRadius
  8578. * @type {Number}
  8579. */
  8580. this.boundingRadius = 0;
  8581. options.type = Shape.CONVEX;
  8582. Shape.call(this, options);
  8583. this.updateBoundingRadius();
  8584. this.updateArea();
  8585. if(this.area < 0){
  8586. throw new Error("Convex vertices must be given in conter-clockwise winding.");
  8587. }
  8588. }
  8589. Convex.prototype = new Shape();
  8590. Convex.prototype.constructor = Convex;
  8591. var tmpVec1 = vec2.create();
  8592. var tmpVec2 = vec2.create();
  8593. /**
  8594. * Project a Convex onto a world-oriented axis
  8595. * @method projectOntoAxis
  8596. * @static
  8597. * @param {Array} offset
  8598. * @param {Array} localAxis
  8599. * @param {Array} result
  8600. */
  8601. Convex.prototype.projectOntoLocalAxis = function(localAxis, result){
  8602. var max=null,
  8603. min=null,
  8604. v,
  8605. value,
  8606. localAxis = tmpVec1;
  8607. // Get projected position of all vertices
  8608. for(var i=0; i<this.vertices.length; i++){
  8609. v = this.vertices[i];
  8610. value = vec2.dot(v, localAxis);
  8611. if(max === null || value > max){
  8612. max = value;
  8613. }
  8614. if(min === null || value < min){
  8615. min = value;
  8616. }
  8617. }
  8618. if(min > max){
  8619. var t = min;
  8620. min = max;
  8621. max = t;
  8622. }
  8623. vec2.set(result, min, max);
  8624. };
  8625. Convex.prototype.projectOntoWorldAxis = function(localAxis, shapeOffset, shapeAngle, result){
  8626. var worldAxis = tmpVec2;
  8627. this.projectOntoLocalAxis(localAxis, result);
  8628. // Project the position of the body onto the axis - need to add this to the result
  8629. if(shapeAngle !== 0){
  8630. vec2.rotate(worldAxis, localAxis, shapeAngle);
  8631. } else {
  8632. worldAxis = localAxis;
  8633. }
  8634. var offset = vec2.dot(shapeOffset, worldAxis);
  8635. vec2.set(result, result[0] + offset, result[1] + offset);
  8636. };
  8637. /**
  8638. * Update the .triangles property
  8639. * @method updateTriangles
  8640. */
  8641. Convex.prototype.updateTriangles = function(){
  8642. this.triangles.length = 0;
  8643. // Rewrite on polyk notation, array of numbers
  8644. var polykVerts = [];
  8645. for(var i=0; i<this.vertices.length; i++){
  8646. var v = this.vertices[i];
  8647. polykVerts.push(v[0],v[1]);
  8648. }
  8649. // Triangulate
  8650. var triangles = polyk.Triangulate(polykVerts);
  8651. // Loop over all triangles, add their inertia contributions to I
  8652. for(var i=0; i<triangles.length; i+=3){
  8653. var id1 = triangles[i],
  8654. id2 = triangles[i+1],
  8655. id3 = triangles[i+2];
  8656. // Add to triangles
  8657. this.triangles.push([id1,id2,id3]);
  8658. }
  8659. };
  8660. var updateCenterOfMass_centroid = vec2.create(),
  8661. updateCenterOfMass_centroid_times_mass = vec2.create(),
  8662. updateCenterOfMass_a = vec2.create(),
  8663. updateCenterOfMass_b = vec2.create(),
  8664. updateCenterOfMass_c = vec2.create(),
  8665. updateCenterOfMass_ac = vec2.create(),
  8666. updateCenterOfMass_ca = vec2.create(),
  8667. updateCenterOfMass_cb = vec2.create(),
  8668. updateCenterOfMass_n = vec2.create();
  8669. /**
  8670. * Update the .centerOfMass property.
  8671. * @method updateCenterOfMass
  8672. */
  8673. Convex.prototype.updateCenterOfMass = function(){
  8674. var triangles = this.triangles,
  8675. verts = this.vertices,
  8676. cm = this.centerOfMass,
  8677. centroid = updateCenterOfMass_centroid,
  8678. n = updateCenterOfMass_n,
  8679. a = updateCenterOfMass_a,
  8680. b = updateCenterOfMass_b,
  8681. c = updateCenterOfMass_c,
  8682. ac = updateCenterOfMass_ac,
  8683. ca = updateCenterOfMass_ca,
  8684. cb = updateCenterOfMass_cb,
  8685. centroid_times_mass = updateCenterOfMass_centroid_times_mass;
  8686. vec2.set(cm,0,0);
  8687. var totalArea = 0;
  8688. for(var i=0; i!==triangles.length; i++){
  8689. var t = triangles[i],
  8690. a = verts[t[0]],
  8691. b = verts[t[1]],
  8692. c = verts[t[2]];
  8693. vec2.centroid(centroid,a,b,c);
  8694. // Get mass for the triangle (density=1 in this case)
  8695. // http://math.stackexchange.com/questions/80198/area-of-triangle-via-vectors
  8696. var m = Convex.triangleArea(a,b,c);
  8697. totalArea += m;
  8698. // Add to center of mass
  8699. vec2.scale(centroid_times_mass, centroid, m);
  8700. vec2.add(cm, cm, centroid_times_mass);
  8701. }
  8702. vec2.scale(cm,cm,1/totalArea);
  8703. };
  8704. /**
  8705. * Compute the mass moment of inertia of the Convex.
  8706. * @method computeMomentOfInertia
  8707. * @param {Number} mass
  8708. * @return {Number}
  8709. * @see http://www.gamedev.net/topic/342822-moment-of-inertia-of-a-polygon-2d/
  8710. */
  8711. Convex.prototype.computeMomentOfInertia = function(mass){
  8712. var denom = 0.0,
  8713. numer = 0.0,
  8714. N = this.vertices.length;
  8715. for(var j = N-1, i = 0; i < N; j = i, i ++){
  8716. var p0 = this.vertices[j];
  8717. var p1 = this.vertices[i];
  8718. var a = Math.abs(vec2.crossLength(p0,p1));
  8719. var b = vec2.dot(p1,p1) + vec2.dot(p1,p0) + vec2.dot(p0,p0);
  8720. denom += a * b;
  8721. numer += a;
  8722. }
  8723. return (mass / 6.0) * (denom / numer);
  8724. };
  8725. /**
  8726. * Updates the .boundingRadius property
  8727. * @method updateBoundingRadius
  8728. */
  8729. Convex.prototype.updateBoundingRadius = function(){
  8730. var verts = this.vertices,
  8731. r2 = 0;
  8732. for(var i=0; i!==verts.length; i++){
  8733. var l2 = vec2.squaredLength(verts[i]);
  8734. if(l2 > r2){
  8735. r2 = l2;
  8736. }
  8737. }
  8738. this.boundingRadius = Math.sqrt(r2);
  8739. };
  8740. /**
  8741. * Get the area of the triangle spanned by the three points a, b, c. The area is positive if the points are given in counter-clockwise order, otherwise negative.
  8742. * @static
  8743. * @method triangleArea
  8744. * @param {Array} a
  8745. * @param {Array} b
  8746. * @param {Array} c
  8747. * @return {Number}
  8748. */
  8749. Convex.triangleArea = function(a,b,c){
  8750. return (((b[0] - a[0])*(c[1] - a[1]))-((c[0] - a[0])*(b[1] - a[1]))) * 0.5;
  8751. };
  8752. /**
  8753. * Update the .area
  8754. * @method updateArea
  8755. */
  8756. Convex.prototype.updateArea = function(){
  8757. this.updateTriangles();
  8758. this.area = 0;
  8759. var triangles = this.triangles,
  8760. verts = this.vertices;
  8761. for(var i=0; i!==triangles.length; i++){
  8762. var t = triangles[i],
  8763. a = verts[t[0]],
  8764. b = verts[t[1]],
  8765. c = verts[t[2]];
  8766. // Get mass for the triangle (density=1 in this case)
  8767. var m = Convex.triangleArea(a,b,c);
  8768. this.area += m;
  8769. }
  8770. };
  8771. /**
  8772. * @method computeAABB
  8773. * @param {AABB} out
  8774. * @param {Array} position
  8775. * @param {Number} angle
  8776. */
  8777. Convex.prototype.computeAABB = function(out, position, angle){
  8778. out.setFromPoints(this.vertices, position, angle, 0);
  8779. };
  8780. var intersectConvex_rayStart = vec2.create();
  8781. var intersectConvex_rayEnd = vec2.create();
  8782. var intersectConvex_normal = vec2.create();
  8783. /**
  8784. * @method raycast
  8785. * @param {RaycastResult} result
  8786. * @param {Ray} ray
  8787. * @param {array} position
  8788. * @param {number} angle
  8789. */
  8790. Convex.prototype.raycast = function(result, ray, position, angle){
  8791. var rayStart = intersectConvex_rayStart;
  8792. var rayEnd = intersectConvex_rayEnd;
  8793. var normal = intersectConvex_normal;
  8794. var vertices = this.vertices;
  8795. // Transform to local shape space
  8796. vec2.toLocalFrame(rayStart, ray.from, position, angle);
  8797. vec2.toLocalFrame(rayEnd, ray.to, position, angle);
  8798. var n = vertices.length;
  8799. for (var i = 0; i < n && !result.shouldStop(ray); i++) {
  8800. var q1 = vertices[i];
  8801. var q2 = vertices[(i+1) % n];
  8802. var delta = vec2.getLineSegmentsIntersectionFraction(rayStart, rayEnd, q1, q2);
  8803. if(delta >= 0){
  8804. vec2.sub(normal, q2, q1);
  8805. vec2.rotate(normal, normal, -Math.PI / 2 + angle);
  8806. vec2.normalize(normal, normal);
  8807. ray.reportIntersection(result, delta, normal, i);
  8808. }
  8809. }
  8810. };
  8811. },{"../math/polyk":29,"../math/vec2":30,"./Shape":45,"poly-decomp":5}],41:[function(_dereq_,module,exports){
  8812. var Shape = _dereq_('./Shape')
  8813. , vec2 = _dereq_('../math/vec2')
  8814. , Utils = _dereq_('../utils/Utils');
  8815. module.exports = Heightfield;
  8816. /**
  8817. * Heightfield shape class. Height data is given as an array. These data points are spread out evenly with a distance "elementWidth".
  8818. * @class Heightfield
  8819. * @extends Shape
  8820. * @constructor
  8821. * @param {object} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  8822. * @param {array} [options.heights] An array of Y values that will be used to construct the terrain.
  8823. * @param {Number} [options.minValue] Minimum value of the data points in the data array. Will be computed automatically if not given.
  8824. * @param {Number} [options.maxValue] Maximum value.
  8825. * @param {Number} [options.elementWidth=0.1] World spacing between the data points in X direction.
  8826. *
  8827. * @example
  8828. * // Generate some height data (y-values).
  8829. * var heights = [];
  8830. * for(var i = 0; i < 1000; i++){
  8831. * var y = 0.5 * Math.cos(0.2 * i);
  8832. * heights.push(y);
  8833. * }
  8834. *
  8835. * // Create the heightfield shape
  8836. * var heightfieldShape = new Heightfield({
  8837. * heights: heights,
  8838. * elementWidth: 1 // Distance between the data points in X direction
  8839. * });
  8840. * var heightfieldBody = new Body();
  8841. * heightfieldBody.addShape(heightfieldShape);
  8842. * world.addBody(heightfieldBody);
  8843. *
  8844. * @todo Should use a scale property with X and Y direction instead of just elementWidth
  8845. */
  8846. function Heightfield(options){
  8847. if(Array.isArray(arguments[0])){
  8848. options = {
  8849. heights: arguments[0]
  8850. };
  8851. if(typeof(arguments[1]) === 'object'){
  8852. for(var key in arguments[1]){
  8853. options[key] = arguments[1][key];
  8854. }
  8855. }
  8856. console.warn('The Heightfield constructor signature has changed. Please use the following format: new Heightfield({ heights: [...], ... })');
  8857. }
  8858. options = options || {};
  8859. /**
  8860. * An array of numbers, or height values, that are spread out along the x axis.
  8861. * @property {array} heights
  8862. */
  8863. this.heights = options.heights ? options.heights.slice(0) : [];
  8864. /**
  8865. * Max value of the heights
  8866. * @property {number} maxValue
  8867. */
  8868. this.maxValue = options.maxValue || null;
  8869. /**
  8870. * Max value of the heights
  8871. * @property {number} minValue
  8872. */
  8873. this.minValue = options.minValue || null;
  8874. /**
  8875. * The width of each element
  8876. * @property {number} elementWidth
  8877. */
  8878. this.elementWidth = options.elementWidth || 0.1;
  8879. if(options.maxValue === undefined || options.minValue === undefined){
  8880. this.updateMaxMinValues();
  8881. }
  8882. options.type = Shape.HEIGHTFIELD;
  8883. Shape.call(this, options);
  8884. }
  8885. Heightfield.prototype = new Shape();
  8886. Heightfield.prototype.constructor = Heightfield;
  8887. /**
  8888. * Update the .minValue and the .maxValue
  8889. * @method updateMaxMinValues
  8890. */
  8891. Heightfield.prototype.updateMaxMinValues = function(){
  8892. var data = this.heights;
  8893. var maxValue = data[0];
  8894. var minValue = data[0];
  8895. for(var i=0; i !== data.length; i++){
  8896. var v = data[i];
  8897. if(v > maxValue){
  8898. maxValue = v;
  8899. }
  8900. if(v < minValue){
  8901. minValue = v;
  8902. }
  8903. }
  8904. this.maxValue = maxValue;
  8905. this.minValue = minValue;
  8906. };
  8907. /**
  8908. * @method computeMomentOfInertia
  8909. * @param {Number} mass
  8910. * @return {Number}
  8911. */
  8912. Heightfield.prototype.computeMomentOfInertia = function(mass){
  8913. return Number.MAX_VALUE;
  8914. };
  8915. Heightfield.prototype.updateBoundingRadius = function(){
  8916. this.boundingRadius = Number.MAX_VALUE;
  8917. };
  8918. Heightfield.prototype.updateArea = function(){
  8919. var data = this.heights,
  8920. area = 0;
  8921. for(var i=0; i<data.length-1; i++){
  8922. area += (data[i]+data[i+1]) / 2 * this.elementWidth;
  8923. }
  8924. this.area = area;
  8925. };
  8926. var points = [
  8927. vec2.create(),
  8928. vec2.create(),
  8929. vec2.create(),
  8930. vec2.create()
  8931. ];
  8932. /**
  8933. * @method computeAABB
  8934. * @param {AABB} out The resulting AABB.
  8935. * @param {Array} position
  8936. * @param {Number} angle
  8937. */
  8938. Heightfield.prototype.computeAABB = function(out, position, angle){
  8939. vec2.set(points[0], 0, this.maxValue);
  8940. vec2.set(points[1], this.elementWidth * this.heights.length, this.maxValue);
  8941. vec2.set(points[2], this.elementWidth * this.heights.length, this.minValue);
  8942. vec2.set(points[3], 0, this.minValue);
  8943. out.setFromPoints(points, position, angle);
  8944. };
  8945. /**
  8946. * Get a line segment in the heightfield
  8947. * @method getLineSegment
  8948. * @param {array} start Where to store the resulting start point
  8949. * @param {array} end Where to store the resulting end point
  8950. * @param {number} i
  8951. */
  8952. Heightfield.prototype.getLineSegment = function(start, end, i){
  8953. var data = this.heights;
  8954. var width = this.elementWidth;
  8955. vec2.set(start, i * width, data[i]);
  8956. vec2.set(end, (i + 1) * width, data[i + 1]);
  8957. };
  8958. Heightfield.prototype.getSegmentIndex = function(position){
  8959. return Math.floor(position[0] / this.elementWidth);
  8960. };
  8961. Heightfield.prototype.getClampedSegmentIndex = function(position){
  8962. var i = this.getSegmentIndex(position);
  8963. i = Math.min(this.heights.length, Math.max(i, 0)); // clamp
  8964. return i;
  8965. };
  8966. var intersectHeightfield_hitPointWorld = vec2.create();
  8967. var intersectHeightfield_worldNormal = vec2.create();
  8968. var intersectHeightfield_l0 = vec2.create();
  8969. var intersectHeightfield_l1 = vec2.create();
  8970. var intersectHeightfield_localFrom = vec2.create();
  8971. var intersectHeightfield_localTo = vec2.create();
  8972. var intersectHeightfield_unit_y = vec2.fromValues(0,1);
  8973. // Returns 1 if the lines intersect, otherwise 0.
  8974. function getLineSegmentsIntersection (out, p0, p1, p2, p3) {
  8975. var s1_x, s1_y, s2_x, s2_y;
  8976. s1_x = p1[0] - p0[0];
  8977. s1_y = p1[1] - p0[1];
  8978. s2_x = p3[0] - p2[0];
  8979. s2_y = p3[1] - p2[1];
  8980. var s, t;
  8981. s = (-s1_y * (p0[0] - p2[0]) + s1_x * (p0[1] - p2[1])) / (-s2_x * s1_y + s1_x * s2_y);
  8982. t = ( s2_x * (p0[1] - p2[1]) - s2_y * (p0[0] - p2[0])) / (-s2_x * s1_y + s1_x * s2_y);
  8983. if (s >= 0 && s <= 1 && t >= 0 && t <= 1) { // Collision detected
  8984. var intX = p0[0] + (t * s1_x);
  8985. var intY = p0[1] + (t * s1_y);
  8986. out[0] = intX;
  8987. out[1] = intY;
  8988. return t;
  8989. }
  8990. return -1; // No collision
  8991. }
  8992. /**
  8993. * @method raycast
  8994. * @param {RayResult} result
  8995. * @param {Ray} ray
  8996. * @param {array} position
  8997. * @param {number} angle
  8998. */
  8999. Heightfield.prototype.raycast = function(result, ray, position, angle){
  9000. var from = ray.from;
  9001. var to = ray.to;
  9002. var direction = ray.direction;
  9003. var hitPointWorld = intersectHeightfield_hitPointWorld;
  9004. var worldNormal = intersectHeightfield_worldNormal;
  9005. var l0 = intersectHeightfield_l0;
  9006. var l1 = intersectHeightfield_l1;
  9007. var localFrom = intersectHeightfield_localFrom;
  9008. var localTo = intersectHeightfield_localTo;
  9009. // get local ray start and end
  9010. vec2.toLocalFrame(localFrom, from, position, angle);
  9011. vec2.toLocalFrame(localTo, to, position, angle);
  9012. // Get the segment range
  9013. var i0 = this.getClampedSegmentIndex(localFrom);
  9014. var i1 = this.getClampedSegmentIndex(localTo);
  9015. if(i0 > i1){
  9016. var tmp = i0;
  9017. i0 = i1;
  9018. i1 = tmp;
  9019. }
  9020. // The segments
  9021. for(var i=0; i<this.heights.length - 1; i++){
  9022. this.getLineSegment(l0, l1, i);
  9023. var t = vec2.getLineSegmentsIntersectionFraction(localFrom, localTo, l0, l1);
  9024. if(t >= 0){
  9025. vec2.sub(worldNormal, l1, l0);
  9026. vec2.rotate(worldNormal, worldNormal, angle + Math.PI / 2);
  9027. vec2.normalize(worldNormal, worldNormal);
  9028. ray.reportIntersection(result, t, worldNormal, -1);
  9029. if(result.shouldStop(ray)){
  9030. return;
  9031. }
  9032. }
  9033. }
  9034. };
  9035. },{"../math/vec2":30,"../utils/Utils":57,"./Shape":45}],42:[function(_dereq_,module,exports){
  9036. var Shape = _dereq_('./Shape')
  9037. , vec2 = _dereq_('../math/vec2');
  9038. module.exports = Line;
  9039. /**
  9040. * Line shape class. The line shape is along the x direction, and stretches from [-length/2, 0] to [length/2,0].
  9041. * @class Line
  9042. * @param {object} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  9043. * @param {Number} [options.length=1] The total length of the line
  9044. * @extends Shape
  9045. * @constructor
  9046. */
  9047. function Line(options){
  9048. if(typeof(arguments[0]) === 'number'){
  9049. options = {
  9050. length: arguments[0]
  9051. };
  9052. console.warn('The Line constructor signature has changed. Please use the following format: new Line({ length: 1, ... })');
  9053. }
  9054. options = options || {};
  9055. /**
  9056. * Length of this line
  9057. * @property {Number} length
  9058. * @default 1
  9059. */
  9060. this.length = options.length || 1;
  9061. options.type = Shape.LINE;
  9062. Shape.call(this, options);
  9063. }
  9064. Line.prototype = new Shape();
  9065. Line.prototype.constructor = Line;
  9066. Line.prototype.computeMomentOfInertia = function(mass){
  9067. return mass * Math.pow(this.length,2) / 12;
  9068. };
  9069. Line.prototype.updateBoundingRadius = function(){
  9070. this.boundingRadius = this.length/2;
  9071. };
  9072. var points = [vec2.create(),vec2.create()];
  9073. /**
  9074. * @method computeAABB
  9075. * @param {AABB} out The resulting AABB.
  9076. * @param {Array} position
  9077. * @param {Number} angle
  9078. */
  9079. Line.prototype.computeAABB = function(out, position, angle){
  9080. var l2 = this.length / 2;
  9081. vec2.set(points[0], -l2, 0);
  9082. vec2.set(points[1], l2, 0);
  9083. out.setFromPoints(points,position,angle,0);
  9084. };
  9085. var raycast_hitPoint = vec2.create();
  9086. var raycast_normal = vec2.create();
  9087. var raycast_l0 = vec2.create();
  9088. var raycast_l1 = vec2.create();
  9089. var raycast_unit_y = vec2.fromValues(0,1);
  9090. /**
  9091. * @method raycast
  9092. * @param {RaycastResult} result
  9093. * @param {Ray} ray
  9094. * @param {number} angle
  9095. * @param {array} position
  9096. */
  9097. Line.prototype.raycast = function(result, ray, position, angle){
  9098. var from = ray.from;
  9099. var to = ray.to;
  9100. var l0 = raycast_l0;
  9101. var l1 = raycast_l1;
  9102. // get start and end of the line
  9103. var halfLen = this.length / 2;
  9104. vec2.set(l0, -halfLen, 0);
  9105. vec2.set(l1, halfLen, 0);
  9106. vec2.toGlobalFrame(l0, l0, position, angle);
  9107. vec2.toGlobalFrame(l1, l1, position, angle);
  9108. var fraction = vec2.getLineSegmentsIntersectionFraction(l0, l1, from, to);
  9109. if(fraction >= 0){
  9110. var normal = raycast_normal;
  9111. vec2.rotate(normal, raycast_unit_y, angle); // todo: this should depend on which side the ray comes from
  9112. ray.reportIntersection(result, fraction, normal, -1);
  9113. }
  9114. };
  9115. },{"../math/vec2":30,"./Shape":45}],43:[function(_dereq_,module,exports){
  9116. var Shape = _dereq_('./Shape')
  9117. , vec2 = _dereq_('../math/vec2');
  9118. module.exports = Particle;
  9119. /**
  9120. * Particle shape class.
  9121. * @class Particle
  9122. * @constructor
  9123. * @param {object} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  9124. * @extends Shape
  9125. */
  9126. function Particle(options){
  9127. options = options || {};
  9128. options.type = Shape.PARTICLE;
  9129. Shape.call(this, options);
  9130. }
  9131. Particle.prototype = new Shape();
  9132. Particle.prototype.constructor = Particle;
  9133. Particle.prototype.computeMomentOfInertia = function(mass){
  9134. return 0; // Can't rotate a particle
  9135. };
  9136. Particle.prototype.updateBoundingRadius = function(){
  9137. this.boundingRadius = 0;
  9138. };
  9139. /**
  9140. * @method computeAABB
  9141. * @param {AABB} out
  9142. * @param {Array} position
  9143. * @param {Number} angle
  9144. */
  9145. Particle.prototype.computeAABB = function(out, position, angle){
  9146. vec2.copy(out.lowerBound, position);
  9147. vec2.copy(out.upperBound, position);
  9148. };
  9149. },{"../math/vec2":30,"./Shape":45}],44:[function(_dereq_,module,exports){
  9150. var Shape = _dereq_('./Shape')
  9151. , vec2 = _dereq_('../math/vec2')
  9152. , Utils = _dereq_('../utils/Utils');
  9153. module.exports = Plane;
  9154. /**
  9155. * Plane shape class. The plane is facing in the Y direction.
  9156. * @class Plane
  9157. * @extends Shape
  9158. * @constructor
  9159. * @param {object} [options] (Note that this options object will be passed on to the {{#crossLink "Shape"}}{{/crossLink}} constructor.)
  9160. */
  9161. function Plane(options){
  9162. options = options || {};
  9163. options.type = Shape.PLANE;
  9164. Shape.call(this, options);
  9165. }
  9166. Plane.prototype = new Shape();
  9167. Plane.prototype.constructor = Plane;
  9168. /**
  9169. * Compute moment of inertia
  9170. * @method computeMomentOfInertia
  9171. */
  9172. Plane.prototype.computeMomentOfInertia = function(mass){
  9173. return 0; // Plane is infinite. The inertia should therefore be infinty but by convention we set 0 here
  9174. };
  9175. /**
  9176. * Update the bounding radius
  9177. * @method updateBoundingRadius
  9178. */
  9179. Plane.prototype.updateBoundingRadius = function(){
  9180. this.boundingRadius = Number.MAX_VALUE;
  9181. };
  9182. /**
  9183. * @method computeAABB
  9184. * @param {AABB} out
  9185. * @param {Array} position
  9186. * @param {Number} angle
  9187. */
  9188. Plane.prototype.computeAABB = function(out, position, angle){
  9189. var a = angle % (2 * Math.PI);
  9190. var set = vec2.set;
  9191. var max = 1e7;
  9192. var lowerBound = out.lowerBound;
  9193. var upperBound = out.upperBound;
  9194. // Set max bounds
  9195. set(lowerBound, -max, -max);
  9196. set(upperBound, max, max);
  9197. if(a === 0){
  9198. // y goes from -inf to 0
  9199. upperBound[1] = 0;
  9200. // set(lowerBound, -max, -max);
  9201. // set(upperBound, max, 0);
  9202. } else if(a === Math.PI / 2){
  9203. // x goes from 0 to inf
  9204. lowerBound[0] = 0;
  9205. // set(lowerBound, 0, -max);
  9206. // set(upperBound, max, max);
  9207. } else if(a === Math.PI){
  9208. // y goes from 0 to inf
  9209. lowerBound[1] = 0;
  9210. // set(lowerBound, -max, 0);
  9211. // set(upperBound, max, max);
  9212. } else if(a === 3*Math.PI/2){
  9213. // x goes from -inf to 0
  9214. upperBound[0] = 0;
  9215. // set(lowerBound, -max, -max);
  9216. // set(upperBound, 0, max);
  9217. }
  9218. };
  9219. Plane.prototype.updateArea = function(){
  9220. this.area = Number.MAX_VALUE;
  9221. };
  9222. var intersectPlane_planePointToFrom = vec2.create();
  9223. var intersectPlane_dir_scaled_with_t = vec2.create();
  9224. var intersectPlane_hitPoint = vec2.create();
  9225. var intersectPlane_normal = vec2.create();
  9226. var intersectPlane_len = vec2.create();
  9227. /**
  9228. * @method raycast
  9229. * @param {RayResult} result
  9230. * @param {Ray} ray
  9231. * @param {array} position
  9232. * @param {number} angle
  9233. */
  9234. Plane.prototype.raycast = function(result, ray, position, angle){
  9235. var from = ray.from;
  9236. var to = ray.to;
  9237. var direction = ray.direction;
  9238. var planePointToFrom = intersectPlane_planePointToFrom;
  9239. var dir_scaled_with_t = intersectPlane_dir_scaled_with_t;
  9240. var hitPoint = intersectPlane_hitPoint;
  9241. var normal = intersectPlane_normal;
  9242. var len = intersectPlane_len;
  9243. // Get plane normal
  9244. vec2.set(normal, 0, 1);
  9245. vec2.rotate(normal, normal, angle);
  9246. vec2.sub(len, from, position);
  9247. var planeToFrom = vec2.dot(len, normal);
  9248. vec2.sub(len, to, position);
  9249. var planeToTo = vec2.dot(len, normal);
  9250. if(planeToFrom * planeToTo > 0){
  9251. // "from" and "to" are on the same side of the plane... bail out
  9252. return;
  9253. }
  9254. if(vec2.squaredDistance(from, to) < planeToFrom * planeToFrom){
  9255. return;
  9256. }
  9257. var n_dot_dir = vec2.dot(normal, direction);
  9258. vec2.sub(planePointToFrom, from, position);
  9259. var t = -vec2.dot(normal, planePointToFrom) / n_dot_dir / ray.length;
  9260. ray.reportIntersection(result, t, normal, -1);
  9261. };
  9262. },{"../math/vec2":30,"../utils/Utils":57,"./Shape":45}],45:[function(_dereq_,module,exports){
  9263. module.exports = Shape;
  9264. var vec2 = _dereq_('../math/vec2');
  9265. /**
  9266. * Base class for shapes.
  9267. * @class Shape
  9268. * @constructor
  9269. * @param {object} [options]
  9270. * @param {array} [options.position]
  9271. * @param {number} [options.angle=0]
  9272. * @param {number} [options.collisionGroup=1]
  9273. * @param {number} [options.collisionMask=1]
  9274. * @param {boolean} [options.sensor=false]
  9275. * @param {boolean} [options.collisionResponse=true]
  9276. * @param {object} [options.type=0]
  9277. */
  9278. function Shape(options){
  9279. options = options || {};
  9280. /**
  9281. * The body this shape is attached to. A shape can only be attached to a single body.
  9282. * @property {Body} body
  9283. */
  9284. this.body = null;
  9285. /**
  9286. * Body-local position of the shape.
  9287. * @property {Array} position
  9288. */
  9289. this.position = vec2.fromValues(0,0);
  9290. if(options.position){
  9291. vec2.copy(this.position, options.position);
  9292. }
  9293. /**
  9294. * Body-local angle of the shape.
  9295. * @property {number} angle
  9296. */
  9297. this.angle = options.angle || 0;
  9298. /**
  9299. * The type of the shape. One of:
  9300. *
  9301. * * {{#crossLink "Shape/CIRCLE:property"}}Shape.CIRCLE{{/crossLink}}
  9302. * * {{#crossLink "Shape/PARTICLE:property"}}Shape.PARTICLE{{/crossLink}}
  9303. * * {{#crossLink "Shape/PLANE:property"}}Shape.PLANE{{/crossLink}}
  9304. * * {{#crossLink "Shape/CONVEX:property"}}Shape.CONVEX{{/crossLink}}
  9305. * * {{#crossLink "Shape/LINE:property"}}Shape.LINE{{/crossLink}}
  9306. * * {{#crossLink "Shape/BOX:property"}}Shape.BOX{{/crossLink}}
  9307. * * {{#crossLink "Shape/CAPSULE:property"}}Shape.CAPSULE{{/crossLink}}
  9308. * * {{#crossLink "Shape/HEIGHTFIELD:property"}}Shape.HEIGHTFIELD{{/crossLink}}
  9309. *
  9310. * @property {number} type
  9311. */
  9312. this.type = options.type || 0;
  9313. /**
  9314. * Shape object identifier.
  9315. * @type {Number}
  9316. * @property id
  9317. */
  9318. this.id = Shape.idCounter++;
  9319. /**
  9320. * Bounding circle radius of this shape
  9321. * @property boundingRadius
  9322. * @type {Number}
  9323. */
  9324. this.boundingRadius = 0;
  9325. /**
  9326. * Collision group that this shape belongs to (bit mask). See <a href="http://www.aurelienribon.com/blog/2011/07/box2d-tutorial-collision-filtering/">this tutorial</a>.
  9327. * @property collisionGroup
  9328. * @type {Number}
  9329. * @example
  9330. * // Setup bits for each available group
  9331. * var PLAYER = Math.pow(2,0),
  9332. * ENEMY = Math.pow(2,1),
  9333. * GROUND = Math.pow(2,2)
  9334. *
  9335. * // Put shapes into their groups
  9336. * player1Shape.collisionGroup = PLAYER;
  9337. * player2Shape.collisionGroup = PLAYER;
  9338. * enemyShape .collisionGroup = ENEMY;
  9339. * groundShape .collisionGroup = GROUND;
  9340. *
  9341. * // Assign groups that each shape collide with.
  9342. * // Note that the players can collide with ground and enemies, but not with other players.
  9343. * player1Shape.collisionMask = ENEMY | GROUND;
  9344. * player2Shape.collisionMask = ENEMY | GROUND;
  9345. * enemyShape .collisionMask = PLAYER | GROUND;
  9346. * groundShape .collisionMask = PLAYER | ENEMY;
  9347. *
  9348. * @example
  9349. * // How collision check is done
  9350. * if(shapeA.collisionGroup & shapeB.collisionMask)!=0 && (shapeB.collisionGroup & shapeA.collisionMask)!=0){
  9351. * // The shapes will collide
  9352. * }
  9353. */
  9354. this.collisionGroup = options.collisionGroup !== undefined ? options.collisionGroup : 1;
  9355. /**
  9356. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled. That means that this shape will move through other body shapes, but it will still trigger contact events, etc.
  9357. * @property {Boolean} collisionResponse
  9358. */
  9359. this.collisionResponse = options.collisionResponse !== undefined ? options.collisionResponse : true;
  9360. /**
  9361. * Collision mask of this shape. See .collisionGroup.
  9362. * @property collisionMask
  9363. * @type {Number}
  9364. */
  9365. this.collisionMask = options.collisionMask !== undefined ? options.collisionMask : 1;
  9366. /**
  9367. * Material to use in collisions for this Shape. If this is set to null, the world will use default material properties instead.
  9368. * @property material
  9369. * @type {Material}
  9370. */
  9371. this.material = options.material || null;
  9372. /**
  9373. * Area of this shape.
  9374. * @property area
  9375. * @type {Number}
  9376. */
  9377. this.area = 0;
  9378. /**
  9379. * Set to true if you want this shape to be a sensor. A sensor does not generate contacts, but it still reports contact events. This is good if you want to know if a shape is overlapping another shape, without them generating contacts.
  9380. * @property {Boolean} sensor
  9381. */
  9382. this.sensor = options.sensor !== undefined ? options.sensor : false;
  9383. if(this.type){
  9384. this.updateBoundingRadius();
  9385. }
  9386. this.updateArea();
  9387. }
  9388. Shape.idCounter = 0;
  9389. /**
  9390. * @static
  9391. * @property {Number} CIRCLE
  9392. */
  9393. Shape.CIRCLE = 1;
  9394. /**
  9395. * @static
  9396. * @property {Number} PARTICLE
  9397. */
  9398. Shape.PARTICLE = 2;
  9399. /**
  9400. * @static
  9401. * @property {Number} PLANE
  9402. */
  9403. Shape.PLANE = 4;
  9404. /**
  9405. * @static
  9406. * @property {Number} CONVEX
  9407. */
  9408. Shape.CONVEX = 8;
  9409. /**
  9410. * @static
  9411. * @property {Number} LINE
  9412. */
  9413. Shape.LINE = 16;
  9414. /**
  9415. * @static
  9416. * @property {Number} BOX
  9417. */
  9418. Shape.BOX = 32;
  9419. Object.defineProperty(Shape, 'RECTANGLE', {
  9420. get: function() {
  9421. console.warn('Shape.RECTANGLE is deprecated, use Shape.BOX instead.');
  9422. return Shape.BOX;
  9423. }
  9424. });
  9425. /**
  9426. * @static
  9427. * @property {Number} CAPSULE
  9428. */
  9429. Shape.CAPSULE = 64;
  9430. /**
  9431. * @static
  9432. * @property {Number} HEIGHTFIELD
  9433. */
  9434. Shape.HEIGHTFIELD = 128;
  9435. /**
  9436. * Should return the moment of inertia around the Z axis of the body given the total mass. See <a href="http://en.wikipedia.org/wiki/List_of_moments_of_inertia">Wikipedia's list of moments of inertia</a>.
  9437. * @method computeMomentOfInertia
  9438. * @param {Number} mass
  9439. * @return {Number} If the inertia is infinity or if the object simply isn't possible to rotate, return 0.
  9440. */
  9441. Shape.prototype.computeMomentOfInertia = function(mass){};
  9442. /**
  9443. * Returns the bounding circle radius of this shape.
  9444. * @method updateBoundingRadius
  9445. * @return {Number}
  9446. */
  9447. Shape.prototype.updateBoundingRadius = function(){};
  9448. /**
  9449. * Update the .area property of the shape.
  9450. * @method updateArea
  9451. */
  9452. Shape.prototype.updateArea = function(){
  9453. // To be implemented in all subclasses
  9454. };
  9455. /**
  9456. * Compute the world axis-aligned bounding box (AABB) of this shape.
  9457. * @method computeAABB
  9458. * @param {AABB} out The resulting AABB.
  9459. * @param {Array} position World position of the shape.
  9460. * @param {Number} angle World angle of the shape.
  9461. */
  9462. Shape.prototype.computeAABB = function(out, position, angle){
  9463. // To be implemented in each subclass
  9464. };
  9465. /**
  9466. * Perform raycasting on this shape.
  9467. * @method raycast
  9468. * @param {RayResult} result Where to store the resulting data.
  9469. * @param {Ray} ray The Ray that you want to use for raycasting.
  9470. * @param {array} position World position of the shape (the .position property will be ignored).
  9471. * @param {number} angle World angle of the shape (the .angle property will be ignored).
  9472. */
  9473. Shape.prototype.raycast = function(result, ray, position, angle){
  9474. // To be implemented in each subclass
  9475. };
  9476. },{"../math/vec2":30}],46:[function(_dereq_,module,exports){
  9477. var vec2 = _dereq_('../math/vec2')
  9478. , Solver = _dereq_('./Solver')
  9479. , Utils = _dereq_('../utils/Utils')
  9480. , FrictionEquation = _dereq_('../equations/FrictionEquation');
  9481. module.exports = GSSolver;
  9482. /**
  9483. * Iterative Gauss-Seidel constraint equation solver.
  9484. *
  9485. * @class GSSolver
  9486. * @constructor
  9487. * @extends Solver
  9488. * @param {Object} [options]
  9489. * @param {Number} [options.iterations=10]
  9490. * @param {Number} [options.tolerance=0]
  9491. */
  9492. function GSSolver(options){
  9493. Solver.call(this,options,Solver.GS);
  9494. options = options || {};
  9495. /**
  9496. * The max number of iterations to do when solving. More gives better results, but is more expensive.
  9497. * @property iterations
  9498. * @type {Number}
  9499. */
  9500. this.iterations = options.iterations || 10;
  9501. /**
  9502. * The error tolerance, per constraint. If the total error is below this limit, the solver will stop iterating. Set to zero for as good solution as possible, but to something larger than zero to make computations faster.
  9503. * @property tolerance
  9504. * @type {Number}
  9505. * @default 1e-7
  9506. */
  9507. this.tolerance = options.tolerance || 1e-7;
  9508. this.arrayStep = 30;
  9509. this.lambda = new Utils.ARRAY_TYPE(this.arrayStep);
  9510. this.Bs = new Utils.ARRAY_TYPE(this.arrayStep);
  9511. this.invCs = new Utils.ARRAY_TYPE(this.arrayStep);
  9512. /**
  9513. * Set to true to set all right hand side terms to zero when solving. Can be handy for a few applications.
  9514. * @property useZeroRHS
  9515. * @type {Boolean}
  9516. * @todo Remove, not used
  9517. */
  9518. this.useZeroRHS = false;
  9519. /**
  9520. * Number of solver iterations that are used to approximate normal forces used for friction (F_friction = mu * F_normal). These friction forces will override any other friction forces that are set. If you set frictionIterations = 0, then this feature will be disabled.
  9521. *
  9522. * Use only frictionIterations > 0 if the approximated normal force (F_normal = mass * gravity) is not good enough. Examples of where it can happen is in space games where gravity is zero, or in tall stacks where the normal force is large at bottom but small at top.
  9523. *
  9524. * @property frictionIterations
  9525. * @type {Number}
  9526. * @default 0
  9527. */
  9528. this.frictionIterations = options.frictionIterations !== undefined ? 0 : options.frictionIterations;
  9529. /**
  9530. * The number of iterations that were made during the last solve. If .tolerance is zero, this value will always be equal to .iterations, but if .tolerance is larger than zero, and the solver can quit early, then this number will be somewhere between 1 and .iterations.
  9531. * @property {Number} usedIterations
  9532. */
  9533. this.usedIterations = 0;
  9534. }
  9535. GSSolver.prototype = new Solver();
  9536. GSSolver.prototype.constructor = GSSolver;
  9537. function setArrayZero(array){
  9538. var l = array.length;
  9539. while(l--){
  9540. array[l] = +0.0;
  9541. }
  9542. }
  9543. /**
  9544. * Solve the system of equations
  9545. * @method solve
  9546. * @param {Number} h Time step
  9547. * @param {World} world World to solve
  9548. */
  9549. GSSolver.prototype.solve = function(h, world){
  9550. this.sortEquations();
  9551. var iter = 0,
  9552. maxIter = this.iterations,
  9553. maxFrictionIter = this.frictionIterations,
  9554. equations = this.equations,
  9555. Neq = equations.length,
  9556. tolSquared = Math.pow(this.tolerance*Neq, 2),
  9557. bodies = world.bodies,
  9558. Nbodies = world.bodies.length,
  9559. add = vec2.add,
  9560. set = vec2.set,
  9561. useZeroRHS = this.useZeroRHS,
  9562. lambda = this.lambda;
  9563. this.usedIterations = 0;
  9564. if(Neq){
  9565. for(var i=0; i!==Nbodies; i++){
  9566. var b = bodies[i];
  9567. // Update solve mass
  9568. b.updateSolveMassProperties();
  9569. }
  9570. }
  9571. // Things that does not change during iteration can be computed once
  9572. if(lambda.length < Neq){
  9573. lambda = this.lambda = new Utils.ARRAY_TYPE(Neq + this.arrayStep);
  9574. this.Bs = new Utils.ARRAY_TYPE(Neq + this.arrayStep);
  9575. this.invCs = new Utils.ARRAY_TYPE(Neq + this.arrayStep);
  9576. }
  9577. setArrayZero(lambda);
  9578. var invCs = this.invCs,
  9579. Bs = this.Bs,
  9580. lambda = this.lambda;
  9581. for(var i=0; i!==equations.length; i++){
  9582. var c = equations[i];
  9583. if(c.timeStep !== h || c.needsUpdate){
  9584. c.timeStep = h;
  9585. c.update();
  9586. }
  9587. Bs[i] = c.computeB(c.a,c.b,h);
  9588. invCs[i] = c.computeInvC(c.epsilon);
  9589. }
  9590. var q, B, c, deltalambdaTot,i,j;
  9591. if(Neq !== 0){
  9592. for(i=0; i!==Nbodies; i++){
  9593. var b = bodies[i];
  9594. // Reset vlambda
  9595. b.resetConstraintVelocity();
  9596. }
  9597. if(maxFrictionIter){
  9598. // Iterate over contact equations to get normal forces
  9599. for(iter=0; iter!==maxFrictionIter; iter++){
  9600. // Accumulate the total error for each iteration.
  9601. deltalambdaTot = 0.0;
  9602. for(j=0; j!==Neq; j++){
  9603. c = equations[j];
  9604. var deltalambda = GSSolver.iterateEquation(j,c,c.epsilon,Bs,invCs,lambda,useZeroRHS,h,iter);
  9605. deltalambdaTot += Math.abs(deltalambda);
  9606. }
  9607. this.usedIterations++;
  9608. // If the total error is small enough - stop iterate
  9609. if(deltalambdaTot*deltalambdaTot <= tolSquared){
  9610. break;
  9611. }
  9612. }
  9613. GSSolver.updateMultipliers(equations, lambda, 1/h);
  9614. // Set computed friction force
  9615. for(j=0; j!==Neq; j++){
  9616. var eq = equations[j];
  9617. if(eq instanceof FrictionEquation){
  9618. var f = 0.0;
  9619. for(var k=0; k!==eq.contactEquations.length; k++){
  9620. f += eq.contactEquations[k].multiplier;
  9621. }
  9622. f *= eq.frictionCoefficient / eq.contactEquations.length;
  9623. eq.maxForce = f;
  9624. eq.minForce = -f;
  9625. }
  9626. }
  9627. }
  9628. // Iterate over all equations
  9629. for(iter=0; iter!==maxIter; iter++){
  9630. // Accumulate the total error for each iteration.
  9631. deltalambdaTot = 0.0;
  9632. for(j=0; j!==Neq; j++){
  9633. c = equations[j];
  9634. var deltalambda = GSSolver.iterateEquation(j,c,c.epsilon,Bs,invCs,lambda,useZeroRHS,h,iter);
  9635. deltalambdaTot += Math.abs(deltalambda);
  9636. }
  9637. this.usedIterations++;
  9638. // If the total error is small enough - stop iterate
  9639. if(deltalambdaTot*deltalambdaTot <= tolSquared){
  9640. break;
  9641. }
  9642. }
  9643. // Add result to velocity
  9644. for(i=0; i!==Nbodies; i++){
  9645. bodies[i].addConstraintVelocity();
  9646. }
  9647. GSSolver.updateMultipliers(equations, lambda, 1/h);
  9648. }
  9649. };
  9650. // Sets the .multiplier property of each equation
  9651. GSSolver.updateMultipliers = function(equations, lambda, invDt){
  9652. // Set the .multiplier property of each equation
  9653. var l = equations.length;
  9654. while(l--){
  9655. equations[l].multiplier = lambda[l] * invDt;
  9656. }
  9657. };
  9658. GSSolver.iterateEquation = function(j,eq,eps,Bs,invCs,lambda,useZeroRHS,dt,iter){
  9659. // Compute iteration
  9660. var B = Bs[j],
  9661. invC = invCs[j],
  9662. lambdaj = lambda[j],
  9663. GWlambda = eq.computeGWlambda();
  9664. var maxForce = eq.maxForce,
  9665. minForce = eq.minForce;
  9666. if(useZeroRHS){
  9667. B = 0;
  9668. }
  9669. var deltalambda = invC * ( B - GWlambda - eps * lambdaj );
  9670. // Clamp if we are not within the min/max interval
  9671. var lambdaj_plus_deltalambda = lambdaj + deltalambda;
  9672. if(lambdaj_plus_deltalambda < minForce*dt){
  9673. deltalambda = minForce*dt - lambdaj;
  9674. } else if(lambdaj_plus_deltalambda > maxForce*dt){
  9675. deltalambda = maxForce*dt - lambdaj;
  9676. }
  9677. lambda[j] += deltalambda;
  9678. eq.addToWlambda(deltalambda);
  9679. return deltalambda;
  9680. };
  9681. },{"../equations/FrictionEquation":23,"../math/vec2":30,"../utils/Utils":57,"./Solver":47}],47:[function(_dereq_,module,exports){
  9682. var Utils = _dereq_('../utils/Utils')
  9683. , EventEmitter = _dereq_('../events/EventEmitter');
  9684. module.exports = Solver;
  9685. /**
  9686. * Base class for constraint solvers.
  9687. * @class Solver
  9688. * @constructor
  9689. * @extends EventEmitter
  9690. */
  9691. function Solver(options,type){
  9692. options = options || {};
  9693. EventEmitter.call(this);
  9694. this.type = type;
  9695. /**
  9696. * Current equations in the solver.
  9697. *
  9698. * @property equations
  9699. * @type {Array}
  9700. */
  9701. this.equations = [];
  9702. /**
  9703. * Function that is used to sort all equations before each solve.
  9704. * @property equationSortFunction
  9705. * @type {function|boolean}
  9706. */
  9707. this.equationSortFunction = options.equationSortFunction || false;
  9708. }
  9709. Solver.prototype = new EventEmitter();
  9710. Solver.prototype.constructor = Solver;
  9711. /**
  9712. * Method to be implemented in each subclass
  9713. * @method solve
  9714. * @param {Number} dt
  9715. * @param {World} world
  9716. */
  9717. Solver.prototype.solve = function(dt,world){
  9718. throw new Error("Solver.solve should be implemented by subclasses!");
  9719. };
  9720. var mockWorld = {bodies:[]};
  9721. /**
  9722. * Solves all constraints in an island.
  9723. * @method solveIsland
  9724. * @param {Number} dt
  9725. * @param {Island} island
  9726. */
  9727. Solver.prototype.solveIsland = function(dt,island){
  9728. this.removeAllEquations();
  9729. if(island.equations.length){
  9730. // Add equations to solver
  9731. this.addEquations(island.equations);
  9732. mockWorld.bodies.length = 0;
  9733. island.getBodies(mockWorld.bodies);
  9734. // Solve
  9735. if(mockWorld.bodies.length){
  9736. this.solve(dt,mockWorld);
  9737. }
  9738. }
  9739. };
  9740. /**
  9741. * Sort all equations using the .equationSortFunction. Should be called by subclasses before solving.
  9742. * @method sortEquations
  9743. */
  9744. Solver.prototype.sortEquations = function(){
  9745. if(this.equationSortFunction){
  9746. this.equations.sort(this.equationSortFunction);
  9747. }
  9748. };
  9749. /**
  9750. * Add an equation to be solved.
  9751. *
  9752. * @method addEquation
  9753. * @param {Equation} eq
  9754. */
  9755. Solver.prototype.addEquation = function(eq){
  9756. if(eq.enabled){
  9757. this.equations.push(eq);
  9758. }
  9759. };
  9760. /**
  9761. * Add equations. Same as .addEquation, but this time the argument is an array of Equations
  9762. *
  9763. * @method addEquations
  9764. * @param {Array} eqs
  9765. */
  9766. Solver.prototype.addEquations = function(eqs){
  9767. //Utils.appendArray(this.equations,eqs);
  9768. for(var i=0, N=eqs.length; i!==N; i++){
  9769. var eq = eqs[i];
  9770. if(eq.enabled){
  9771. this.equations.push(eq);
  9772. }
  9773. }
  9774. };
  9775. /**
  9776. * Remove an equation.
  9777. *
  9778. * @method removeEquation
  9779. * @param {Equation} eq
  9780. */
  9781. Solver.prototype.removeEquation = function(eq){
  9782. var i = this.equations.indexOf(eq);
  9783. if(i !== -1){
  9784. this.equations.splice(i,1);
  9785. }
  9786. };
  9787. /**
  9788. * Remove all currently added equations.
  9789. *
  9790. * @method removeAllEquations
  9791. */
  9792. Solver.prototype.removeAllEquations = function(){
  9793. this.equations.length=0;
  9794. };
  9795. Solver.GS = 1;
  9796. Solver.ISLAND = 2;
  9797. },{"../events/EventEmitter":26,"../utils/Utils":57}],48:[function(_dereq_,module,exports){
  9798. var ContactEquation = _dereq_('../equations/ContactEquation');
  9799. var Pool = _dereq_('./Pool');
  9800. module.exports = ContactEquationPool;
  9801. /**
  9802. * @class
  9803. */
  9804. function ContactEquationPool() {
  9805. Pool.apply(this, arguments);
  9806. }
  9807. ContactEquationPool.prototype = new Pool();
  9808. ContactEquationPool.prototype.constructor = ContactEquationPool;
  9809. /**
  9810. * @method create
  9811. * @return {ContactEquation}
  9812. */
  9813. ContactEquationPool.prototype.create = function () {
  9814. return new ContactEquation();
  9815. };
  9816. /**
  9817. * @method destroy
  9818. * @param {ContactEquation} equation
  9819. * @return {ContactEquationPool}
  9820. */
  9821. ContactEquationPool.prototype.destroy = function (equation) {
  9822. equation.bodyA = equation.bodyB = null;
  9823. return this;
  9824. };
  9825. },{"../equations/ContactEquation":21,"./Pool":55}],49:[function(_dereq_,module,exports){
  9826. var FrictionEquation = _dereq_('../equations/FrictionEquation');
  9827. var Pool = _dereq_('./Pool');
  9828. module.exports = FrictionEquationPool;
  9829. /**
  9830. * @class
  9831. */
  9832. function FrictionEquationPool() {
  9833. Pool.apply(this, arguments);
  9834. }
  9835. FrictionEquationPool.prototype = new Pool();
  9836. FrictionEquationPool.prototype.constructor = FrictionEquationPool;
  9837. /**
  9838. * @method create
  9839. * @return {FrictionEquation}
  9840. */
  9841. FrictionEquationPool.prototype.create = function () {
  9842. return new FrictionEquation();
  9843. };
  9844. /**
  9845. * @method destroy
  9846. * @param {FrictionEquation} equation
  9847. * @return {FrictionEquationPool}
  9848. */
  9849. FrictionEquationPool.prototype.destroy = function (equation) {
  9850. equation.bodyA = equation.bodyB = null;
  9851. return this;
  9852. };
  9853. },{"../equations/FrictionEquation":23,"./Pool":55}],50:[function(_dereq_,module,exports){
  9854. var IslandNode = _dereq_('../world/IslandNode');
  9855. var Pool = _dereq_('./Pool');
  9856. module.exports = IslandNodePool;
  9857. /**
  9858. * @class
  9859. */
  9860. function IslandNodePool() {
  9861. Pool.apply(this, arguments);
  9862. }
  9863. IslandNodePool.prototype = new Pool();
  9864. IslandNodePool.prototype.constructor = IslandNodePool;
  9865. /**
  9866. * @method create
  9867. * @return {IslandNode}
  9868. */
  9869. IslandNodePool.prototype.create = function () {
  9870. return new IslandNode();
  9871. };
  9872. /**
  9873. * @method destroy
  9874. * @param {IslandNode} node
  9875. * @return {IslandNodePool}
  9876. */
  9877. IslandNodePool.prototype.destroy = function (node) {
  9878. node.reset();
  9879. return this;
  9880. };
  9881. },{"../world/IslandNode":60,"./Pool":55}],51:[function(_dereq_,module,exports){
  9882. var Island = _dereq_('../world/Island');
  9883. var Pool = _dereq_('./Pool');
  9884. module.exports = IslandPool;
  9885. /**
  9886. * @class
  9887. */
  9888. function IslandPool() {
  9889. Pool.apply(this, arguments);
  9890. }
  9891. IslandPool.prototype = new Pool();
  9892. IslandPool.prototype.constructor = IslandPool;
  9893. /**
  9894. * @method create
  9895. * @return {Island}
  9896. */
  9897. IslandPool.prototype.create = function () {
  9898. return new Island();
  9899. };
  9900. /**
  9901. * @method destroy
  9902. * @param {Island} island
  9903. * @return {IslandPool}
  9904. */
  9905. IslandPool.prototype.destroy = function (island) {
  9906. island.reset();
  9907. return this;
  9908. };
  9909. },{"../world/Island":58,"./Pool":55}],52:[function(_dereq_,module,exports){
  9910. var TupleDictionary = _dereq_('./TupleDictionary');
  9911. var OverlapKeeperRecord = _dereq_('./OverlapKeeperRecord');
  9912. var OverlapKeeperRecordPool = _dereq_('./OverlapKeeperRecordPool');
  9913. var Utils = _dereq_('./Utils');
  9914. module.exports = OverlapKeeper;
  9915. /**
  9916. * Keeps track of overlaps in the current state and the last step state.
  9917. * @class OverlapKeeper
  9918. * @constructor
  9919. */
  9920. function OverlapKeeper() {
  9921. this.overlappingShapesLastState = new TupleDictionary();
  9922. this.overlappingShapesCurrentState = new TupleDictionary();
  9923. this.recordPool = new OverlapKeeperRecordPool({ size: 16 });
  9924. this.tmpDict = new TupleDictionary();
  9925. this.tmpArray1 = [];
  9926. }
  9927. /**
  9928. * Ticks one step forward in time. This will move the current overlap state to the "old" overlap state, and create a new one as current.
  9929. * @method tick
  9930. */
  9931. OverlapKeeper.prototype.tick = function() {
  9932. var last = this.overlappingShapesLastState;
  9933. var current = this.overlappingShapesCurrentState;
  9934. // Save old objects into pool
  9935. var l = last.keys.length;
  9936. while(l--){
  9937. var key = last.keys[l];
  9938. var lastObject = last.getByKey(key);
  9939. var currentObject = current.getByKey(key);
  9940. if(lastObject){
  9941. // The record is only used in the "last" dict, and will be removed. We might as well pool it.
  9942. this.recordPool.release(lastObject);
  9943. }
  9944. }
  9945. // Clear last object
  9946. last.reset();
  9947. // Transfer from new object to old
  9948. last.copy(current);
  9949. // Clear current object
  9950. current.reset();
  9951. };
  9952. /**
  9953. * @method setOverlapping
  9954. * @param {Body} bodyA
  9955. * @param {Body} shapeA
  9956. * @param {Body} bodyB
  9957. * @param {Body} shapeB
  9958. */
  9959. OverlapKeeper.prototype.setOverlapping = function(bodyA, shapeA, bodyB, shapeB) {
  9960. var last = this.overlappingShapesLastState;
  9961. var current = this.overlappingShapesCurrentState;
  9962. // Store current contact state
  9963. if(!current.get(shapeA.id, shapeB.id)){
  9964. var data = this.recordPool.get();
  9965. data.set(bodyA, shapeA, bodyB, shapeB);
  9966. current.set(shapeA.id, shapeB.id, data);
  9967. }
  9968. };
  9969. OverlapKeeper.prototype.getNewOverlaps = function(result){
  9970. return this.getDiff(this.overlappingShapesLastState, this.overlappingShapesCurrentState, result);
  9971. };
  9972. OverlapKeeper.prototype.getEndOverlaps = function(result){
  9973. return this.getDiff(this.overlappingShapesCurrentState, this.overlappingShapesLastState, result);
  9974. };
  9975. /**
  9976. * Checks if two bodies are currently overlapping.
  9977. * @method bodiesAreOverlapping
  9978. * @param {Body} bodyA
  9979. * @param {Body} bodyB
  9980. * @return {boolean}
  9981. */
  9982. OverlapKeeper.prototype.bodiesAreOverlapping = function(bodyA, bodyB){
  9983. var current = this.overlappingShapesCurrentState;
  9984. var l = current.keys.length;
  9985. while(l--){
  9986. var key = current.keys[l];
  9987. var data = current.data[key];
  9988. if((data.bodyA === bodyA && data.bodyB === bodyB) || data.bodyA === bodyB && data.bodyB === bodyA){
  9989. return true;
  9990. }
  9991. }
  9992. return false;
  9993. };
  9994. OverlapKeeper.prototype.getDiff = function(dictA, dictB, result){
  9995. var result = result || [];
  9996. var last = dictA;
  9997. var current = dictB;
  9998. result.length = 0;
  9999. var l = current.keys.length;
  10000. while(l--){
  10001. var key = current.keys[l];
  10002. var data = current.data[key];
  10003. if(!data){
  10004. throw new Error('Key '+key+' had no data!');
  10005. }
  10006. var lastData = last.data[key];
  10007. if(!lastData){
  10008. // Not overlapping in last state, but in current.
  10009. result.push(data);
  10010. }
  10011. }
  10012. return result;
  10013. };
  10014. OverlapKeeper.prototype.isNewOverlap = function(shapeA, shapeB){
  10015. var idA = shapeA.id|0,
  10016. idB = shapeB.id|0;
  10017. var last = this.overlappingShapesLastState;
  10018. var current = this.overlappingShapesCurrentState;
  10019. // Not in last but in new
  10020. return !!!last.get(idA, idB) && !!current.get(idA, idB);
  10021. };
  10022. OverlapKeeper.prototype.getNewBodyOverlaps = function(result){
  10023. this.tmpArray1.length = 0;
  10024. var overlaps = this.getNewOverlaps(this.tmpArray1);
  10025. return this.getBodyDiff(overlaps, result);
  10026. };
  10027. OverlapKeeper.prototype.getEndBodyOverlaps = function(result){
  10028. this.tmpArray1.length = 0;
  10029. var overlaps = this.getEndOverlaps(this.tmpArray1);
  10030. return this.getBodyDiff(overlaps, result);
  10031. };
  10032. OverlapKeeper.prototype.getBodyDiff = function(overlaps, result){
  10033. result = result || [];
  10034. var accumulator = this.tmpDict;
  10035. var l = overlaps.length;
  10036. while(l--){
  10037. var data = overlaps[l];
  10038. // Since we use body id's for the accumulator, these will be a subset of the original one
  10039. accumulator.set(data.bodyA.id|0, data.bodyB.id|0, data);
  10040. }
  10041. l = accumulator.keys.length;
  10042. while(l--){
  10043. var data = accumulator.getByKey(accumulator.keys[l]);
  10044. if(data){
  10045. result.push(data.bodyA, data.bodyB);
  10046. }
  10047. }
  10048. accumulator.reset();
  10049. return result;
  10050. };
  10051. },{"./OverlapKeeperRecord":53,"./OverlapKeeperRecordPool":54,"./TupleDictionary":56,"./Utils":57}],53:[function(_dereq_,module,exports){
  10052. module.exports = OverlapKeeperRecord;
  10053. /**
  10054. * Overlap data container for the OverlapKeeper
  10055. * @class OverlapKeeperRecord
  10056. * @constructor
  10057. * @param {Body} bodyA
  10058. * @param {Shape} shapeA
  10059. * @param {Body} bodyB
  10060. * @param {Shape} shapeB
  10061. */
  10062. function OverlapKeeperRecord(bodyA, shapeA, bodyB, shapeB){
  10063. /**
  10064. * @property {Shape} shapeA
  10065. */
  10066. this.shapeA = shapeA;
  10067. /**
  10068. * @property {Shape} shapeB
  10069. */
  10070. this.shapeB = shapeB;
  10071. /**
  10072. * @property {Body} bodyA
  10073. */
  10074. this.bodyA = bodyA;
  10075. /**
  10076. * @property {Body} bodyB
  10077. */
  10078. this.bodyB = bodyB;
  10079. }
  10080. /**
  10081. * Set the data for the record
  10082. * @method set
  10083. * @param {Body} bodyA
  10084. * @param {Shape} shapeA
  10085. * @param {Body} bodyB
  10086. * @param {Shape} shapeB
  10087. */
  10088. OverlapKeeperRecord.prototype.set = function(bodyA, shapeA, bodyB, shapeB){
  10089. OverlapKeeperRecord.call(this, bodyA, shapeA, bodyB, shapeB);
  10090. };
  10091. },{}],54:[function(_dereq_,module,exports){
  10092. var OverlapKeeperRecord = _dereq_('./OverlapKeeperRecord');
  10093. var Pool = _dereq_('./Pool');
  10094. module.exports = OverlapKeeperRecordPool;
  10095. /**
  10096. * @class
  10097. */
  10098. function OverlapKeeperRecordPool() {
  10099. Pool.apply(this, arguments);
  10100. }
  10101. OverlapKeeperRecordPool.prototype = new Pool();
  10102. OverlapKeeperRecordPool.prototype.constructor = OverlapKeeperRecordPool;
  10103. /**
  10104. * @method create
  10105. * @return {OverlapKeeperRecord}
  10106. */
  10107. OverlapKeeperRecordPool.prototype.create = function () {
  10108. return new OverlapKeeperRecord();
  10109. };
  10110. /**
  10111. * @method destroy
  10112. * @param {OverlapKeeperRecord} record
  10113. * @return {OverlapKeeperRecordPool}
  10114. */
  10115. OverlapKeeperRecordPool.prototype.destroy = function (record) {
  10116. record.bodyA = record.bodyB = record.shapeA = record.shapeB = null;
  10117. return this;
  10118. };
  10119. },{"./OverlapKeeperRecord":53,"./Pool":55}],55:[function(_dereq_,module,exports){
  10120. module.exports = Pool;
  10121. /**
  10122. * @class Object pooling utility.
  10123. */
  10124. function Pool(options) {
  10125. options = options || {};
  10126. /**
  10127. * @property {Array} objects
  10128. * @type {Array}
  10129. */
  10130. this.objects = [];
  10131. if(options.size !== undefined){
  10132. this.resize(options.size);
  10133. }
  10134. }
  10135. /**
  10136. * @method resize
  10137. * @param {number} size
  10138. * @return {Pool} Self, for chaining
  10139. */
  10140. Pool.prototype.resize = function (size) {
  10141. var objects = this.objects;
  10142. while (objects.length > size) {
  10143. objects.pop();
  10144. }
  10145. while (objects.length < size) {
  10146. objects.push(this.create());
  10147. }
  10148. return this;
  10149. };
  10150. /**
  10151. * Get an object from the pool or create a new instance.
  10152. * @method get
  10153. * @return {Object}
  10154. */
  10155. Pool.prototype.get = function () {
  10156. var objects = this.objects;
  10157. return objects.length ? objects.pop() : this.create();
  10158. };
  10159. /**
  10160. * Clean up and put the object back into the pool for later use.
  10161. * @method release
  10162. * @param {Object} object
  10163. * @return {Pool} Self for chaining
  10164. */
  10165. Pool.prototype.release = function (object) {
  10166. this.destroy(object);
  10167. this.objects.push(object);
  10168. return this;
  10169. };
  10170. },{}],56:[function(_dereq_,module,exports){
  10171. var Utils = _dereq_('./Utils');
  10172. module.exports = TupleDictionary;
  10173. /**
  10174. * @class TupleDictionary
  10175. * @constructor
  10176. */
  10177. function TupleDictionary() {
  10178. /**
  10179. * The data storage
  10180. * @property data
  10181. * @type {Object}
  10182. */
  10183. this.data = {};
  10184. /**
  10185. * Keys that are currently used.
  10186. * @property {Array} keys
  10187. */
  10188. this.keys = [];
  10189. }
  10190. /**
  10191. * Generate a key given two integers
  10192. * @method getKey
  10193. * @param {number} i
  10194. * @param {number} j
  10195. * @return {string}
  10196. */
  10197. TupleDictionary.prototype.getKey = function(id1, id2) {
  10198. id1 = id1|0;
  10199. id2 = id2|0;
  10200. if ( (id1|0) === (id2|0) ){
  10201. return -1;
  10202. }
  10203. // valid for values < 2^16
  10204. return ((id1|0) > (id2|0) ?
  10205. (id1 << 16) | (id2 & 0xFFFF) :
  10206. (id2 << 16) | (id1 & 0xFFFF))|0
  10207. ;
  10208. };
  10209. /**
  10210. * @method getByKey
  10211. * @param {Number} key
  10212. * @return {Object}
  10213. */
  10214. TupleDictionary.prototype.getByKey = function(key) {
  10215. key = key|0;
  10216. return this.data[key];
  10217. };
  10218. /**
  10219. * @method get
  10220. * @param {Number} i
  10221. * @param {Number} j
  10222. * @return {Number}
  10223. */
  10224. TupleDictionary.prototype.get = function(i, j) {
  10225. return this.data[this.getKey(i, j)];
  10226. };
  10227. /**
  10228. * Set a value.
  10229. * @method set
  10230. * @param {Number} i
  10231. * @param {Number} j
  10232. * @param {Number} value
  10233. */
  10234. TupleDictionary.prototype.set = function(i, j, value) {
  10235. if(!value){
  10236. throw new Error("No data!");
  10237. }
  10238. var key = this.getKey(i, j);
  10239. // Check if key already exists
  10240. if(!this.data[key]){
  10241. this.keys.push(key);
  10242. }
  10243. this.data[key] = value;
  10244. return key;
  10245. };
  10246. /**
  10247. * Remove all data.
  10248. * @method reset
  10249. */
  10250. TupleDictionary.prototype.reset = function() {
  10251. var data = this.data,
  10252. keys = this.keys;
  10253. var l = keys.length;
  10254. while(l--) {
  10255. delete data[keys[l]];
  10256. }
  10257. keys.length = 0;
  10258. };
  10259. /**
  10260. * Copy another TupleDictionary. Note that all data in this dictionary will be removed.
  10261. * @method copy
  10262. * @param {TupleDictionary} dict The TupleDictionary to copy into this one.
  10263. */
  10264. TupleDictionary.prototype.copy = function(dict) {
  10265. this.reset();
  10266. Utils.appendArray(this.keys, dict.keys);
  10267. var l = dict.keys.length;
  10268. while(l--){
  10269. var key = dict.keys[l];
  10270. this.data[key] = dict.data[key];
  10271. }
  10272. };
  10273. },{"./Utils":57}],57:[function(_dereq_,module,exports){
  10274. /* global P2_ARRAY_TYPE */
  10275. module.exports = Utils;
  10276. /**
  10277. * Misc utility functions
  10278. * @class Utils
  10279. * @constructor
  10280. */
  10281. function Utils(){}
  10282. /**
  10283. * Append the values in array b to the array a. See <a href="http://stackoverflow.com/questions/1374126/how-to-append-an-array-to-an-existing-javascript-array/1374131#1374131">this</a> for an explanation.
  10284. * @method appendArray
  10285. * @static
  10286. * @param {Array} a
  10287. * @param {Array} b
  10288. */
  10289. Utils.appendArray = function(a,b){
  10290. if (b.length < 150000) {
  10291. a.push.apply(a, b);
  10292. } else {
  10293. for (var i = 0, len = b.length; i !== len; ++i) {
  10294. a.push(b[i]);
  10295. }
  10296. }
  10297. };
  10298. /**
  10299. * Garbage free Array.splice(). Does not allocate a new array.
  10300. * @method splice
  10301. * @static
  10302. * @param {Array} array
  10303. * @param {Number} index
  10304. * @param {Number} howmany
  10305. */
  10306. Utils.splice = function(array,index,howmany){
  10307. howmany = howmany || 1;
  10308. for (var i=index, len=array.length-howmany; i < len; i++){
  10309. array[i] = array[i + howmany];
  10310. }
  10311. array.length = len;
  10312. };
  10313. /**
  10314. * The array type to use for internal numeric computations throughout the library. Float32Array is used if it is available, but falls back on Array. If you want to set array type manually, inject it via the global variable P2_ARRAY_TYPE. See example below.
  10315. * @static
  10316. * @property {function} ARRAY_TYPE
  10317. * @example
  10318. * <script>
  10319. * <!-- Inject your preferred array type before loading p2.js -->
  10320. * P2_ARRAY_TYPE = Array;
  10321. * </script>
  10322. * <script src="p2.js"></script>
  10323. */
  10324. if(typeof P2_ARRAY_TYPE !== 'undefined') {
  10325. Utils.ARRAY_TYPE = P2_ARRAY_TYPE;
  10326. } else if (typeof Float32Array !== 'undefined'){
  10327. Utils.ARRAY_TYPE = Float32Array;
  10328. } else {
  10329. Utils.ARRAY_TYPE = Array;
  10330. }
  10331. /**
  10332. * Extend an object with the properties of another
  10333. * @static
  10334. * @method extend
  10335. * @param {object} a
  10336. * @param {object} b
  10337. */
  10338. Utils.extend = function(a,b){
  10339. for(var key in b){
  10340. a[key] = b[key];
  10341. }
  10342. };
  10343. /**
  10344. * Extend an options object with default values.
  10345. * @static
  10346. * @method defaults
  10347. * @param {object} options The options object. May be falsy: in this case, a new object is created and returned.
  10348. * @param {object} defaults An object containing default values.
  10349. * @return {object} The modified options object.
  10350. */
  10351. Utils.defaults = function(options, defaults){
  10352. options = options || {};
  10353. for(var key in defaults){
  10354. if(!(key in options)){
  10355. options[key] = defaults[key];
  10356. }
  10357. }
  10358. return options;
  10359. };
  10360. },{}],58:[function(_dereq_,module,exports){
  10361. var Body = _dereq_('../objects/Body');
  10362. module.exports = Island;
  10363. /**
  10364. * An island of bodies connected with equations.
  10365. * @class Island
  10366. * @constructor
  10367. */
  10368. function Island(){
  10369. /**
  10370. * Current equations in this island.
  10371. * @property equations
  10372. * @type {Array}
  10373. */
  10374. this.equations = [];
  10375. /**
  10376. * Current bodies in this island.
  10377. * @property bodies
  10378. * @type {Array}
  10379. */
  10380. this.bodies = [];
  10381. }
  10382. /**
  10383. * Clean this island from bodies and equations.
  10384. * @method reset
  10385. */
  10386. Island.prototype.reset = function(){
  10387. this.equations.length = this.bodies.length = 0;
  10388. };
  10389. var bodyIds = [];
  10390. /**
  10391. * Get all unique bodies in this island.
  10392. * @method getBodies
  10393. * @return {Array} An array of Body
  10394. */
  10395. Island.prototype.getBodies = function(result){
  10396. var bodies = result || [],
  10397. eqs = this.equations;
  10398. bodyIds.length = 0;
  10399. for(var i=0; i!==eqs.length; i++){
  10400. var eq = eqs[i];
  10401. if(bodyIds.indexOf(eq.bodyA.id)===-1){
  10402. bodies.push(eq.bodyA);
  10403. bodyIds.push(eq.bodyA.id);
  10404. }
  10405. if(bodyIds.indexOf(eq.bodyB.id)===-1){
  10406. bodies.push(eq.bodyB);
  10407. bodyIds.push(eq.bodyB.id);
  10408. }
  10409. }
  10410. return bodies;
  10411. };
  10412. /**
  10413. * Check if the entire island wants to sleep.
  10414. * @method wantsToSleep
  10415. * @return {Boolean}
  10416. */
  10417. Island.prototype.wantsToSleep = function(){
  10418. for(var i=0; i<this.bodies.length; i++){
  10419. var b = this.bodies[i];
  10420. if(b.type === Body.DYNAMIC && !b.wantsToSleep){
  10421. return false;
  10422. }
  10423. }
  10424. return true;
  10425. };
  10426. /**
  10427. * Make all bodies in the island sleep.
  10428. * @method sleep
  10429. */
  10430. Island.prototype.sleep = function(){
  10431. for(var i=0; i<this.bodies.length; i++){
  10432. var b = this.bodies[i];
  10433. b.sleep();
  10434. }
  10435. return true;
  10436. };
  10437. },{"../objects/Body":31}],59:[function(_dereq_,module,exports){
  10438. var vec2 = _dereq_('../math/vec2')
  10439. , Island = _dereq_('./Island')
  10440. , IslandNode = _dereq_('./IslandNode')
  10441. , IslandNodePool = _dereq_('./../utils/IslandNodePool')
  10442. , IslandPool = _dereq_('./../utils/IslandPool')
  10443. , Body = _dereq_('../objects/Body');
  10444. module.exports = IslandManager;
  10445. /**
  10446. * Splits the system of bodies and equations into independent islands
  10447. *
  10448. * @class IslandManager
  10449. * @constructor
  10450. * @param {Object} [options]
  10451. * @extends Solver
  10452. */
  10453. function IslandManager(options){
  10454. /**
  10455. * @property nodePool
  10456. * @type {IslandNodePool}
  10457. */
  10458. this.nodePool = new IslandNodePool({ size: 16 });
  10459. /**
  10460. * @property islandPool
  10461. * @type {IslandPool}
  10462. */
  10463. this.islandPool = new IslandPool({ size: 8 });
  10464. /**
  10465. * The equations to split. Manually fill this array before running .split().
  10466. * @property {Array} equations
  10467. */
  10468. this.equations = [];
  10469. /**
  10470. * The resulting {{#crossLink "Island"}}{{/crossLink}}s.
  10471. * @property {Array} islands
  10472. */
  10473. this.islands = [];
  10474. /**
  10475. * The resulting graph nodes.
  10476. * @property {Array} nodes
  10477. */
  10478. this.nodes = [];
  10479. /**
  10480. * The node queue, used when traversing the graph of nodes.
  10481. * @private
  10482. * @property {Array} queue
  10483. */
  10484. this.queue = [];
  10485. }
  10486. /**
  10487. * Get an unvisited node from a list of nodes.
  10488. * @static
  10489. * @method getUnvisitedNode
  10490. * @param {Array} nodes
  10491. * @return {IslandNode|boolean} The node if found, else false.
  10492. */
  10493. IslandManager.getUnvisitedNode = function(nodes){
  10494. var Nnodes = nodes.length;
  10495. for(var i=0; i!==Nnodes; i++){
  10496. var node = nodes[i];
  10497. if(!node.visited && node.body.type === Body.DYNAMIC){
  10498. return node;
  10499. }
  10500. }
  10501. return false;
  10502. };
  10503. /**
  10504. * Visit a node.
  10505. * @method visit
  10506. * @param {IslandNode} node
  10507. * @param {Array} bds
  10508. * @param {Array} eqs
  10509. */
  10510. IslandManager.prototype.visit = function (node,bds,eqs){
  10511. bds.push(node.body);
  10512. var Neqs = node.equations.length;
  10513. for(var i=0; i!==Neqs; i++){
  10514. var eq = node.equations[i];
  10515. if(eqs.indexOf(eq) === -1){ // Already added?
  10516. eqs.push(eq);
  10517. }
  10518. }
  10519. };
  10520. /**
  10521. * Runs the search algorithm, starting at a root node. The resulting bodies and equations will be stored in the provided arrays.
  10522. * @method bfs
  10523. * @param {IslandNode} root The node to start from
  10524. * @param {Array} bds An array to append resulting Bodies to.
  10525. * @param {Array} eqs An array to append resulting Equations to.
  10526. */
  10527. IslandManager.prototype.bfs = function(root,bds,eqs){
  10528. // Reset the visit queue
  10529. var queue = this.queue;
  10530. queue.length = 0;
  10531. // Add root node to queue
  10532. queue.push(root);
  10533. root.visited = true;
  10534. this.visit(root,bds,eqs);
  10535. // Process all queued nodes
  10536. while(queue.length) {
  10537. // Get next node in the queue
  10538. var node = queue.pop();
  10539. // Visit unvisited neighboring nodes
  10540. var child;
  10541. while((child = IslandManager.getUnvisitedNode(node.neighbors))) {
  10542. child.visited = true;
  10543. this.visit(child,bds,eqs);
  10544. // Only visit the children of this node if it's dynamic
  10545. if(child.body.type === Body.DYNAMIC){
  10546. queue.push(child);
  10547. }
  10548. }
  10549. }
  10550. };
  10551. /**
  10552. * Split the world into independent islands. The result is stored in .islands.
  10553. * @method split
  10554. * @param {World} world
  10555. * @return {Array} The generated islands
  10556. */
  10557. IslandManager.prototype.split = function(world){
  10558. var bodies = world.bodies,
  10559. nodes = this.nodes,
  10560. equations = this.equations;
  10561. // Move old nodes to the node pool
  10562. while(nodes.length){
  10563. this.nodePool.release(nodes.pop());
  10564. }
  10565. // Create needed nodes, reuse if possible
  10566. for(var i=0; i!==bodies.length; i++){
  10567. var node = this.nodePool.get();
  10568. node.body = bodies[i];
  10569. nodes.push(node);
  10570. // if(this.nodePool.length){
  10571. // var node = this.nodePool.pop();
  10572. // node.reset();
  10573. // node.body = bodies[i];
  10574. // nodes.push(node);
  10575. // } else {
  10576. // nodes.push(new IslandNode(bodies[i]));
  10577. // }
  10578. }
  10579. // Add connectivity data. Each equation connects 2 bodies.
  10580. for(var k=0; k!==equations.length; k++){
  10581. var eq=equations[k],
  10582. i=bodies.indexOf(eq.bodyA),
  10583. j=bodies.indexOf(eq.bodyB),
  10584. ni=nodes[i],
  10585. nj=nodes[j];
  10586. ni.neighbors.push(nj);
  10587. nj.neighbors.push(ni);
  10588. ni.equations.push(eq);
  10589. nj.equations.push(eq);
  10590. }
  10591. // Move old islands to the island pool
  10592. var islands = this.islands;
  10593. for(var i=0; i<islands.length; i++){
  10594. this.islandPool.release(islands[i]);
  10595. }
  10596. islands.length = 0;
  10597. // Get islands
  10598. var child;
  10599. while((child = IslandManager.getUnvisitedNode(nodes))){
  10600. // Create new island
  10601. var island = this.islandPool.get();
  10602. // Get all equations and bodies in this island
  10603. this.bfs(child, island.bodies, island.equations);
  10604. islands.push(island);
  10605. }
  10606. return islands;
  10607. };
  10608. },{"../math/vec2":30,"../objects/Body":31,"./../utils/IslandNodePool":50,"./../utils/IslandPool":51,"./Island":58,"./IslandNode":60}],60:[function(_dereq_,module,exports){
  10609. module.exports = IslandNode;
  10610. /**
  10611. * Holds a body and keeps track of some additional properties needed for graph traversal.
  10612. * @class IslandNode
  10613. * @constructor
  10614. * @param {Body} body
  10615. */
  10616. function IslandNode(body){
  10617. /**
  10618. * The body that is contained in this node.
  10619. * @property {Body} body
  10620. */
  10621. this.body = body;
  10622. /**
  10623. * Neighboring IslandNodes
  10624. * @property {Array} neighbors
  10625. */
  10626. this.neighbors = [];
  10627. /**
  10628. * Equations connected to this node.
  10629. * @property {Array} equations
  10630. */
  10631. this.equations = [];
  10632. /**
  10633. * If this node was visiting during the graph traversal.
  10634. * @property visited
  10635. * @type {Boolean}
  10636. */
  10637. this.visited = false;
  10638. }
  10639. /**
  10640. * Clean this node from bodies and equations.
  10641. * @method reset
  10642. */
  10643. IslandNode.prototype.reset = function(){
  10644. this.equations.length = 0;
  10645. this.neighbors.length = 0;
  10646. this.visited = false;
  10647. this.body = null;
  10648. };
  10649. },{}],61:[function(_dereq_,module,exports){
  10650. var GSSolver = _dereq_('../solver/GSSolver')
  10651. , Solver = _dereq_('../solver/Solver')
  10652. , Ray = _dereq_('../collision/Ray')
  10653. , vec2 = _dereq_('../math/vec2')
  10654. , Circle = _dereq_('../shapes/Circle')
  10655. , Convex = _dereq_('../shapes/Convex')
  10656. , Line = _dereq_('../shapes/Line')
  10657. , Plane = _dereq_('../shapes/Plane')
  10658. , Capsule = _dereq_('../shapes/Capsule')
  10659. , Particle = _dereq_('../shapes/Particle')
  10660. , EventEmitter = _dereq_('../events/EventEmitter')
  10661. , Body = _dereq_('../objects/Body')
  10662. , Shape = _dereq_('../shapes/Shape')
  10663. , LinearSpring = _dereq_('../objects/LinearSpring')
  10664. , Material = _dereq_('../material/Material')
  10665. , ContactMaterial = _dereq_('../material/ContactMaterial')
  10666. , DistanceConstraint = _dereq_('../constraints/DistanceConstraint')
  10667. , Constraint = _dereq_('../constraints/Constraint')
  10668. , LockConstraint = _dereq_('../constraints/LockConstraint')
  10669. , RevoluteConstraint = _dereq_('../constraints/RevoluteConstraint')
  10670. , PrismaticConstraint = _dereq_('../constraints/PrismaticConstraint')
  10671. , GearConstraint = _dereq_('../constraints/GearConstraint')
  10672. , pkg = _dereq_('../../package.json')
  10673. , Broadphase = _dereq_('../collision/Broadphase')
  10674. , AABB = _dereq_('../collision/AABB')
  10675. , SAPBroadphase = _dereq_('../collision/SAPBroadphase')
  10676. , Narrowphase = _dereq_('../collision/Narrowphase')
  10677. , Utils = _dereq_('../utils/Utils')
  10678. , OverlapKeeper = _dereq_('../utils/OverlapKeeper')
  10679. , IslandManager = _dereq_('./IslandManager')
  10680. , RotationalSpring = _dereq_('../objects/RotationalSpring');
  10681. module.exports = World;
  10682. /**
  10683. * The dynamics world, where all bodies and constraints live.
  10684. *
  10685. * @class World
  10686. * @constructor
  10687. * @param {Object} [options]
  10688. * @param {Solver} [options.solver] Defaults to GSSolver.
  10689. * @param {Array} [options.gravity] Defaults to y=-9.78.
  10690. * @param {Broadphase} [options.broadphase] Defaults to SAPBroadphase
  10691. * @param {Boolean} [options.islandSplit=true]
  10692. * @extends EventEmitter
  10693. *
  10694. * @example
  10695. * var world = new World({
  10696. * gravity: [0, -10],
  10697. * broadphase: new SAPBroadphase()
  10698. * });
  10699. * world.addBody(new Body());
  10700. */
  10701. function World(options){
  10702. EventEmitter.apply(this);
  10703. options = options || {};
  10704. /**
  10705. * All springs in the world. To add a spring to the world, use {{#crossLink "World/addSpring:method"}}{{/crossLink}}.
  10706. *
  10707. * @property springs
  10708. * @type {Array}
  10709. */
  10710. this.springs = [];
  10711. /**
  10712. * All bodies in the world. To add a body to the world, use {{#crossLink "World/addBody:method"}}{{/crossLink}}.
  10713. * @property {Array} bodies
  10714. */
  10715. this.bodies = [];
  10716. /**
  10717. * Disabled body collision pairs. See {{#crossLink "World/disableBodyCollision:method"}}.
  10718. * @private
  10719. * @property {Array} disabledBodyCollisionPairs
  10720. */
  10721. this.disabledBodyCollisionPairs = [];
  10722. /**
  10723. * The solver used to satisfy constraints and contacts. Default is {{#crossLink "GSSolver"}}{{/crossLink}}.
  10724. * @property {Solver} solver
  10725. */
  10726. this.solver = options.solver || new GSSolver();
  10727. /**
  10728. * The narrowphase to use to generate contacts.
  10729. *
  10730. * @property narrowphase
  10731. * @type {Narrowphase}
  10732. */
  10733. this.narrowphase = new Narrowphase(this);
  10734. /**
  10735. * The island manager of this world.
  10736. * @property {IslandManager} islandManager
  10737. */
  10738. this.islandManager = new IslandManager();
  10739. /**
  10740. * Gravity in the world. This is applied on all bodies in the beginning of each step().
  10741. *
  10742. * @property gravity
  10743. * @type {Array}
  10744. */
  10745. this.gravity = vec2.fromValues(0, -9.78);
  10746. if(options.gravity){
  10747. vec2.copy(this.gravity, options.gravity);
  10748. }
  10749. /**
  10750. * Gravity to use when approximating the friction max force (mu*mass*gravity).
  10751. * @property {Number} frictionGravity
  10752. */
  10753. this.frictionGravity = vec2.length(this.gravity) || 10;
  10754. /**
  10755. * Set to true if you want .frictionGravity to be automatically set to the length of .gravity.
  10756. * @property {Boolean} useWorldGravityAsFrictionGravity
  10757. * @default true
  10758. */
  10759. this.useWorldGravityAsFrictionGravity = true;
  10760. /**
  10761. * If the length of .gravity is zero, and .useWorldGravityAsFrictionGravity=true, then switch to using .frictionGravity for friction instead. This fallback is useful for gravityless games.
  10762. * @property {Boolean} useFrictionGravityOnZeroGravity
  10763. * @default true
  10764. */
  10765. this.useFrictionGravityOnZeroGravity = true;
  10766. /**
  10767. * The broadphase algorithm to use.
  10768. *
  10769. * @property broadphase
  10770. * @type {Broadphase}
  10771. */
  10772. this.broadphase = options.broadphase || new SAPBroadphase();
  10773. this.broadphase.setWorld(this);
  10774. /**
  10775. * User-added constraints.
  10776. *
  10777. * @property constraints
  10778. * @type {Array}
  10779. */
  10780. this.constraints = [];
  10781. /**
  10782. * Dummy default material in the world, used in .defaultContactMaterial
  10783. * @property {Material} defaultMaterial
  10784. */
  10785. this.defaultMaterial = new Material();
  10786. /**
  10787. * The default contact material to use, if no contact material was set for the colliding materials.
  10788. * @property {ContactMaterial} defaultContactMaterial
  10789. */
  10790. this.defaultContactMaterial = new ContactMaterial(this.defaultMaterial,this.defaultMaterial);
  10791. /**
  10792. * For keeping track of what time step size we used last step
  10793. * @property lastTimeStep
  10794. * @type {Number}
  10795. */
  10796. this.lastTimeStep = 1/60;
  10797. /**
  10798. * Enable to automatically apply spring forces each step.
  10799. * @property applySpringForces
  10800. * @type {Boolean}
  10801. * @default true
  10802. */
  10803. this.applySpringForces = true;
  10804. /**
  10805. * Enable to automatically apply body damping each step.
  10806. * @property applyDamping
  10807. * @type {Boolean}
  10808. * @default true
  10809. */
  10810. this.applyDamping = true;
  10811. /**
  10812. * Enable to automatically apply gravity each step.
  10813. * @property applyGravity
  10814. * @type {Boolean}
  10815. * @default true
  10816. */
  10817. this.applyGravity = true;
  10818. /**
  10819. * Enable/disable constraint solving in each step.
  10820. * @property solveConstraints
  10821. * @type {Boolean}
  10822. * @default true
  10823. */
  10824. this.solveConstraints = true;
  10825. /**
  10826. * The ContactMaterials added to the World.
  10827. * @property contactMaterials
  10828. * @type {Array}
  10829. */
  10830. this.contactMaterials = [];
  10831. /**
  10832. * World time.
  10833. * @property time
  10834. * @type {Number}
  10835. */
  10836. this.time = 0.0;
  10837. this.accumulator = 0;
  10838. /**
  10839. * Is true during step().
  10840. * @property {Boolean} stepping
  10841. */
  10842. this.stepping = false;
  10843. /**
  10844. * Bodies that are scheduled to be removed at the end of the step.
  10845. * @property {Array} bodiesToBeRemoved
  10846. * @private
  10847. */
  10848. this.bodiesToBeRemoved = [];
  10849. /**
  10850. * Whether to enable island splitting. Island splitting can be an advantage for both precision and performance. See {{#crossLink "IslandManager"}}{{/crossLink}}.
  10851. * @property {Boolean} islandSplit
  10852. * @default true
  10853. */
  10854. this.islandSplit = typeof(options.islandSplit)!=="undefined" ? !!options.islandSplit : true;
  10855. /**
  10856. * Set to true if you want to the world to emit the "impact" event. Turning this off could improve performance.
  10857. * @property emitImpactEvent
  10858. * @type {Boolean}
  10859. * @default true
  10860. */
  10861. this.emitImpactEvent = true;
  10862. // Id counters
  10863. this._constraintIdCounter = 0;
  10864. this._bodyIdCounter = 0;
  10865. /**
  10866. * Fired after the step().
  10867. * @event postStep
  10868. */
  10869. this.postStepEvent = {
  10870. type : "postStep"
  10871. };
  10872. /**
  10873. * Fired when a body is added to the world.
  10874. * @event addBody
  10875. * @param {Body} body
  10876. */
  10877. this.addBodyEvent = {
  10878. type : "addBody",
  10879. body : null
  10880. };
  10881. /**
  10882. * Fired when a body is removed from the world.
  10883. * @event removeBody
  10884. * @param {Body} body
  10885. */
  10886. this.removeBodyEvent = {
  10887. type : "removeBody",
  10888. body : null
  10889. };
  10890. /**
  10891. * Fired when a spring is added to the world.
  10892. * @event addSpring
  10893. * @param {Spring} spring
  10894. */
  10895. this.addSpringEvent = {
  10896. type : "addSpring",
  10897. spring : null
  10898. };
  10899. /**
  10900. * Fired when a first contact is created between two bodies. This event is fired after the step has been done.
  10901. * @event impact
  10902. * @param {Body} bodyA
  10903. * @param {Body} bodyB
  10904. */
  10905. this.impactEvent = {
  10906. type: "impact",
  10907. bodyA : null,
  10908. bodyB : null,
  10909. shapeA : null,
  10910. shapeB : null,
  10911. contactEquation : null
  10912. };
  10913. /**
  10914. * Fired after the Broadphase has collected collision pairs in the world.
  10915. * Inside the event handler, you can modify the pairs array as you like, to
  10916. * prevent collisions between objects that you don't want.
  10917. * @event postBroadphase
  10918. * @param {Array} pairs An array of collision pairs. If this array is [body1,body2,body3,body4], then the body pairs 1,2 and 3,4 would advance to narrowphase.
  10919. */
  10920. this.postBroadphaseEvent = {
  10921. type: "postBroadphase",
  10922. pairs: null
  10923. };
  10924. /**
  10925. * How to deactivate bodies during simulation. Possible modes are: {{#crossLink "World/NO_SLEEPING:property"}}World.NO_SLEEPING{{/crossLink}}, {{#crossLink "World/BODY_SLEEPING:property"}}World.BODY_SLEEPING{{/crossLink}} and {{#crossLink "World/ISLAND_SLEEPING:property"}}World.ISLAND_SLEEPING{{/crossLink}}.
  10926. * If sleeping is enabled, you might need to {{#crossLink "Body/wakeUp:method"}}wake up{{/crossLink}} the bodies if they fall asleep when they shouldn't. If you want to enable sleeping in the world, but want to disable it for a particular body, see {{#crossLink "Body/allowSleep:property"}}Body.allowSleep{{/crossLink}}.
  10927. * @property sleepMode
  10928. * @type {number}
  10929. * @default World.NO_SLEEPING
  10930. */
  10931. this.sleepMode = World.NO_SLEEPING;
  10932. /**
  10933. * Fired when two shapes starts start to overlap. Fired in the narrowphase, during step.
  10934. * @event beginContact
  10935. * @param {Shape} shapeA
  10936. * @param {Shape} shapeB
  10937. * @param {Body} bodyA
  10938. * @param {Body} bodyB
  10939. * @param {Array} contactEquations
  10940. */
  10941. this.beginContactEvent = {
  10942. type: "beginContact",
  10943. shapeA: null,
  10944. shapeB: null,
  10945. bodyA: null,
  10946. bodyB: null,
  10947. contactEquations: []
  10948. };
  10949. /**
  10950. * Fired when two shapes stop overlapping, after the narrowphase (during step).
  10951. * @event endContact
  10952. * @param {Shape} shapeA
  10953. * @param {Shape} shapeB
  10954. * @param {Body} bodyA
  10955. * @param {Body} bodyB
  10956. */
  10957. this.endContactEvent = {
  10958. type: "endContact",
  10959. shapeA: null,
  10960. shapeB: null,
  10961. bodyA: null,
  10962. bodyB: null
  10963. };
  10964. /**
  10965. * Fired just before equations are added to the solver to be solved. Can be used to control what equations goes into the solver.
  10966. * @event preSolve
  10967. * @param {Array} contactEquations An array of contacts to be solved.
  10968. * @param {Array} frictionEquations An array of friction equations to be solved.
  10969. */
  10970. this.preSolveEvent = {
  10971. type: "preSolve",
  10972. contactEquations: null,
  10973. frictionEquations: null
  10974. };
  10975. // For keeping track of overlapping shapes
  10976. this.overlappingShapesLastState = { keys:[] };
  10977. this.overlappingShapesCurrentState = { keys:[] };
  10978. /**
  10979. * @property {OverlapKeeper} overlapKeeper
  10980. */
  10981. this.overlapKeeper = new OverlapKeeper();
  10982. }
  10983. World.prototype = new Object(EventEmitter.prototype);
  10984. World.prototype.constructor = World;
  10985. /**
  10986. * Never deactivate bodies.
  10987. * @static
  10988. * @property {number} NO_SLEEPING
  10989. */
  10990. World.NO_SLEEPING = 1;
  10991. /**
  10992. * Deactivate individual bodies if they are sleepy.
  10993. * @static
  10994. * @property {number} BODY_SLEEPING
  10995. */
  10996. World.BODY_SLEEPING = 2;
  10997. /**
  10998. * Deactivates bodies that are in contact, if all of them are sleepy. Note that you must enable {{#crossLink "World/islandSplit:property"}}.islandSplit{{/crossLink}} for this to work.
  10999. * @static
  11000. * @property {number} ISLAND_SLEEPING
  11001. */
  11002. World.ISLAND_SLEEPING = 4;
  11003. /**
  11004. * Add a constraint to the simulation.
  11005. *
  11006. * @method addConstraint
  11007. * @param {Constraint} constraint
  11008. * @example
  11009. * var constraint = new LockConstraint(bodyA, bodyB);
  11010. * world.addConstraint(constraint);
  11011. */
  11012. World.prototype.addConstraint = function(constraint){
  11013. this.constraints.push(constraint);
  11014. };
  11015. /**
  11016. * Add a ContactMaterial to the simulation.
  11017. * @method addContactMaterial
  11018. * @param {ContactMaterial} contactMaterial
  11019. */
  11020. World.prototype.addContactMaterial = function(contactMaterial){
  11021. this.contactMaterials.push(contactMaterial);
  11022. };
  11023. /**
  11024. * Removes a contact material
  11025. *
  11026. * @method removeContactMaterial
  11027. * @param {ContactMaterial} cm
  11028. */
  11029. World.prototype.removeContactMaterial = function(cm){
  11030. var idx = this.contactMaterials.indexOf(cm);
  11031. if(idx!==-1){
  11032. Utils.splice(this.contactMaterials,idx,1);
  11033. }
  11034. };
  11035. /**
  11036. * Get a contact material given two materials
  11037. * @method getContactMaterial
  11038. * @param {Material} materialA
  11039. * @param {Material} materialB
  11040. * @return {ContactMaterial} The matching ContactMaterial, or false on fail.
  11041. * @todo Use faster hash map to lookup from material id's
  11042. */
  11043. World.prototype.getContactMaterial = function(materialA,materialB){
  11044. var cmats = this.contactMaterials;
  11045. for(var i=0, N=cmats.length; i!==N; i++){
  11046. var cm = cmats[i];
  11047. if( (cm.materialA.id === materialA.id) && (cm.materialB.id === materialB.id) ||
  11048. (cm.materialA.id === materialB.id) && (cm.materialB.id === materialA.id) ){
  11049. return cm;
  11050. }
  11051. }
  11052. return false;
  11053. };
  11054. /**
  11055. * Removes a constraint
  11056. *
  11057. * @method removeConstraint
  11058. * @param {Constraint} constraint
  11059. */
  11060. World.prototype.removeConstraint = function(constraint){
  11061. var idx = this.constraints.indexOf(constraint);
  11062. if(idx!==-1){
  11063. Utils.splice(this.constraints,idx,1);
  11064. }
  11065. };
  11066. var step_r = vec2.create(),
  11067. step_runit = vec2.create(),
  11068. step_u = vec2.create(),
  11069. step_f = vec2.create(),
  11070. step_fhMinv = vec2.create(),
  11071. step_velodt = vec2.create(),
  11072. step_mg = vec2.create(),
  11073. xiw = vec2.fromValues(0,0),
  11074. xjw = vec2.fromValues(0,0),
  11075. zero = vec2.fromValues(0,0),
  11076. interpvelo = vec2.fromValues(0,0);
  11077. /**
  11078. * Step the physics world forward in time.
  11079. *
  11080. * There are two modes. The simple mode is fixed timestepping without interpolation. In this case you only use the first argument. The second case uses interpolation. In that you also provide the time since the function was last used, as well as the maximum fixed timesteps to take.
  11081. *
  11082. * @method step
  11083. * @param {Number} dt The fixed time step size to use.
  11084. * @param {Number} [timeSinceLastCalled=0] The time elapsed since the function was last called.
  11085. * @param {Number} [maxSubSteps=10] Maximum number of fixed steps to take per function call.
  11086. *
  11087. * @example
  11088. * // Simple fixed timestepping without interpolation
  11089. * var fixedTimeStep = 1 / 60;
  11090. * var world = new World();
  11091. * var body = new Body({ mass: 1 });
  11092. * world.addBody(body);
  11093. *
  11094. * function animate(){
  11095. * requestAnimationFrame(animate);
  11096. * world.step(fixedTimeStep);
  11097. * renderBody(body.position, body.angle);
  11098. * }
  11099. *
  11100. * // Start animation loop
  11101. * requestAnimationFrame(animate);
  11102. *
  11103. * @example
  11104. * // Fixed timestepping with interpolation
  11105. * var maxSubSteps = 10;
  11106. * var lastTimeSeconds;
  11107. *
  11108. * function animate(t){
  11109. * requestAnimationFrame(animate);
  11110. * timeSeconds = t / 1000;
  11111. * lastTimeSeconds = lastTimeSeconds || timeSeconds;
  11112. *
  11113. * deltaTime = timeSeconds - lastTimeSeconds;
  11114. * world.step(fixedTimeStep, deltaTime, maxSubSteps);
  11115. *
  11116. * renderBody(body.interpolatedPosition, body.interpolatedAngle);
  11117. * }
  11118. *
  11119. * // Start animation loop
  11120. * requestAnimationFrame(animate);
  11121. *
  11122. * @see http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
  11123. */
  11124. World.prototype.step = function(dt,timeSinceLastCalled,maxSubSteps){
  11125. maxSubSteps = maxSubSteps || 10;
  11126. timeSinceLastCalled = timeSinceLastCalled || 0;
  11127. if(timeSinceLastCalled === 0){ // Fixed, simple stepping
  11128. this.internalStep(dt);
  11129. // Increment time
  11130. this.time += dt;
  11131. } else {
  11132. this.accumulator += timeSinceLastCalled;
  11133. var substeps = 0;
  11134. while (this.accumulator >= dt && substeps < maxSubSteps) {
  11135. // Do fixed steps to catch up
  11136. this.internalStep(dt);
  11137. this.time += dt;
  11138. this.accumulator -= dt;
  11139. substeps++;
  11140. }
  11141. var t = (this.accumulator % dt) / dt;
  11142. for(var j=0; j!==this.bodies.length; j++){
  11143. var b = this.bodies[j];
  11144. vec2.lerp(b.interpolatedPosition, b.previousPosition, b.position, t);
  11145. b.interpolatedAngle = b.previousAngle + t * (b.angle - b.previousAngle);
  11146. }
  11147. }
  11148. };
  11149. var endOverlaps = [];
  11150. /**
  11151. * Make a fixed step.
  11152. * @method internalStep
  11153. * @param {number} dt
  11154. * @private
  11155. */
  11156. World.prototype.internalStep = function(dt){
  11157. this.stepping = true;
  11158. var that = this,
  11159. Nsprings = this.springs.length,
  11160. springs = this.springs,
  11161. bodies = this.bodies,
  11162. g = this.gravity,
  11163. solver = this.solver,
  11164. Nbodies = this.bodies.length,
  11165. broadphase = this.broadphase,
  11166. np = this.narrowphase,
  11167. constraints = this.constraints,
  11168. t0, t1,
  11169. fhMinv = step_fhMinv,
  11170. velodt = step_velodt,
  11171. mg = step_mg,
  11172. scale = vec2.scale,
  11173. add = vec2.add,
  11174. rotate = vec2.rotate,
  11175. islandManager = this.islandManager;
  11176. this.overlapKeeper.tick();
  11177. this.lastTimeStep = dt;
  11178. // Update approximate friction gravity.
  11179. if(this.useWorldGravityAsFrictionGravity){
  11180. var gravityLen = vec2.length(this.gravity);
  11181. if(!(gravityLen === 0 && this.useFrictionGravityOnZeroGravity)){
  11182. // Nonzero gravity. Use it.
  11183. this.frictionGravity = gravityLen;
  11184. }
  11185. }
  11186. // Add gravity to bodies
  11187. if(this.applyGravity){
  11188. for(var i=0; i!==Nbodies; i++){
  11189. var b = bodies[i],
  11190. fi = b.force;
  11191. if(b.type !== Body.DYNAMIC || b.sleepState === Body.SLEEPING){
  11192. continue;
  11193. }
  11194. vec2.scale(mg,g,b.mass*b.gravityScale); // F=m*g
  11195. add(fi,fi,mg);
  11196. }
  11197. }
  11198. // Add spring forces
  11199. if(this.applySpringForces){
  11200. for(var i=0; i!==Nsprings; i++){
  11201. var s = springs[i];
  11202. s.applyForce();
  11203. }
  11204. }
  11205. if(this.applyDamping){
  11206. for(var i=0; i!==Nbodies; i++){
  11207. var b = bodies[i];
  11208. if(b.type === Body.DYNAMIC){
  11209. b.applyDamping(dt);
  11210. }
  11211. }
  11212. }
  11213. // Broadphase
  11214. var result = broadphase.getCollisionPairs(this);
  11215. // Remove ignored collision pairs
  11216. var ignoredPairs = this.disabledBodyCollisionPairs;
  11217. for(var i=ignoredPairs.length-2; i>=0; i-=2){
  11218. for(var j=result.length-2; j>=0; j-=2){
  11219. if( (ignoredPairs[i] === result[j] && ignoredPairs[i+1] === result[j+1]) ||
  11220. (ignoredPairs[i+1] === result[j] && ignoredPairs[i] === result[j+1])){
  11221. result.splice(j,2);
  11222. }
  11223. }
  11224. }
  11225. // Remove constrained pairs with collideConnected == false
  11226. var Nconstraints = constraints.length;
  11227. for(i=0; i!==Nconstraints; i++){
  11228. var c = constraints[i];
  11229. if(!c.collideConnected){
  11230. for(var j=result.length-2; j>=0; j-=2){
  11231. if( (c.bodyA === result[j] && c.bodyB === result[j+1]) ||
  11232. (c.bodyB === result[j] && c.bodyA === result[j+1])){
  11233. result.splice(j,2);
  11234. }
  11235. }
  11236. }
  11237. }
  11238. // postBroadphase event
  11239. this.postBroadphaseEvent.pairs = result;
  11240. this.emit(this.postBroadphaseEvent);
  11241. this.postBroadphaseEvent.pairs = null;
  11242. // Narrowphase
  11243. np.reset(this);
  11244. for(var i=0, Nresults=result.length; i!==Nresults; i+=2){
  11245. var bi = result[i],
  11246. bj = result[i+1];
  11247. // Loop over all shapes of body i
  11248. for(var k=0, Nshapesi=bi.shapes.length; k!==Nshapesi; k++){
  11249. var si = bi.shapes[k],
  11250. xi = si.position,
  11251. ai = si.angle;
  11252. // All shapes of body j
  11253. for(var l=0, Nshapesj=bj.shapes.length; l!==Nshapesj; l++){
  11254. var sj = bj.shapes[l],
  11255. xj = sj.position,
  11256. aj = sj.angle;
  11257. var cm = this.defaultContactMaterial;
  11258. if(si.material && sj.material){
  11259. var tmp = this.getContactMaterial(si.material,sj.material);
  11260. if(tmp){
  11261. cm = tmp;
  11262. }
  11263. }
  11264. this.runNarrowphase(np,bi,si,xi,ai,bj,sj,xj,aj,cm,this.frictionGravity);
  11265. }
  11266. }
  11267. }
  11268. // Wake up bodies
  11269. for(var i=0; i!==Nbodies; i++){
  11270. var body = bodies[i];
  11271. if(body._wakeUpAfterNarrowphase){
  11272. body.wakeUp();
  11273. body._wakeUpAfterNarrowphase = false;
  11274. }
  11275. }
  11276. // Emit end overlap events
  11277. if(this.has('endContact')){
  11278. this.overlapKeeper.getEndOverlaps(endOverlaps);
  11279. var e = this.endContactEvent;
  11280. var l = endOverlaps.length;
  11281. while(l--){
  11282. var data = endOverlaps[l];
  11283. e.shapeA = data.shapeA;
  11284. e.shapeB = data.shapeB;
  11285. e.bodyA = data.bodyA;
  11286. e.bodyB = data.bodyB;
  11287. this.emit(e);
  11288. }
  11289. endOverlaps.length = 0;
  11290. }
  11291. var preSolveEvent = this.preSolveEvent;
  11292. preSolveEvent.contactEquations = np.contactEquations;
  11293. preSolveEvent.frictionEquations = np.frictionEquations;
  11294. this.emit(preSolveEvent);
  11295. preSolveEvent.contactEquations = preSolveEvent.frictionEquations = null;
  11296. // update constraint equations
  11297. var Nconstraints = constraints.length;
  11298. for(i=0; i!==Nconstraints; i++){
  11299. constraints[i].update();
  11300. }
  11301. if(np.contactEquations.length || np.frictionEquations.length || Nconstraints){
  11302. if(this.islandSplit){
  11303. // Split into islands
  11304. islandManager.equations.length = 0;
  11305. Utils.appendArray(islandManager.equations, np.contactEquations);
  11306. Utils.appendArray(islandManager.equations, np.frictionEquations);
  11307. for(i=0; i!==Nconstraints; i++){
  11308. Utils.appendArray(islandManager.equations, constraints[i].equations);
  11309. }
  11310. islandManager.split(this);
  11311. for(var i=0; i!==islandManager.islands.length; i++){
  11312. var island = islandManager.islands[i];
  11313. if(island.equations.length){
  11314. solver.solveIsland(dt,island);
  11315. }
  11316. }
  11317. } else {
  11318. // Add contact equations to solver
  11319. solver.addEquations(np.contactEquations);
  11320. solver.addEquations(np.frictionEquations);
  11321. // Add user-defined constraint equations
  11322. for(i=0; i!==Nconstraints; i++){
  11323. solver.addEquations(constraints[i].equations);
  11324. }
  11325. if(this.solveConstraints){
  11326. solver.solve(dt,this);
  11327. }
  11328. solver.removeAllEquations();
  11329. }
  11330. }
  11331. // Step forward
  11332. for(var i=0; i!==Nbodies; i++){
  11333. var body = bodies[i];
  11334. // if(body.sleepState !== Body.SLEEPING && body.type !== Body.STATIC){
  11335. body.integrate(dt);
  11336. // }
  11337. }
  11338. // Reset force
  11339. for(var i=0; i!==Nbodies; i++){
  11340. bodies[i].setZeroForce();
  11341. }
  11342. // Emit impact event
  11343. if(this.emitImpactEvent && this.has('impact')){
  11344. var ev = this.impactEvent;
  11345. for(var i=0; i!==np.contactEquations.length; i++){
  11346. var eq = np.contactEquations[i];
  11347. if(eq.firstImpact){
  11348. ev.bodyA = eq.bodyA;
  11349. ev.bodyB = eq.bodyB;
  11350. ev.shapeA = eq.shapeA;
  11351. ev.shapeB = eq.shapeB;
  11352. ev.contactEquation = eq;
  11353. this.emit(ev);
  11354. }
  11355. }
  11356. }
  11357. // Sleeping update
  11358. if(this.sleepMode === World.BODY_SLEEPING){
  11359. for(i=0; i!==Nbodies; i++){
  11360. bodies[i].sleepTick(this.time, false, dt);
  11361. }
  11362. } else if(this.sleepMode === World.ISLAND_SLEEPING && this.islandSplit){
  11363. // Tell all bodies to sleep tick but dont sleep yet
  11364. for(i=0; i!==Nbodies; i++){
  11365. bodies[i].sleepTick(this.time, true, dt);
  11366. }
  11367. // Sleep islands
  11368. for(var i=0; i<this.islandManager.islands.length; i++){
  11369. var island = this.islandManager.islands[i];
  11370. if(island.wantsToSleep()){
  11371. island.sleep();
  11372. }
  11373. }
  11374. }
  11375. this.stepping = false;
  11376. // Remove bodies that are scheduled for removal
  11377. var bodiesToBeRemoved = this.bodiesToBeRemoved;
  11378. for(var i=0; i!==bodiesToBeRemoved.length; i++){
  11379. this.removeBody(bodiesToBeRemoved[i]);
  11380. }
  11381. bodiesToBeRemoved.length = 0;
  11382. this.emit(this.postStepEvent);
  11383. };
  11384. /**
  11385. * Runs narrowphase for the shape pair i and j.
  11386. * @method runNarrowphase
  11387. * @param {Narrowphase} np
  11388. * @param {Body} bi
  11389. * @param {Shape} si
  11390. * @param {Array} xi
  11391. * @param {Number} ai
  11392. * @param {Body} bj
  11393. * @param {Shape} sj
  11394. * @param {Array} xj
  11395. * @param {Number} aj
  11396. * @param {Number} mu
  11397. */
  11398. World.prototype.runNarrowphase = function(np,bi,si,xi,ai,bj,sj,xj,aj,cm,glen){
  11399. // Check collision groups and masks
  11400. if(!((si.collisionGroup & sj.collisionMask) !== 0 && (sj.collisionGroup & si.collisionMask) !== 0)){
  11401. return;
  11402. }
  11403. // Get world position and angle of each shape
  11404. vec2.rotate(xiw, xi, bi.angle);
  11405. vec2.rotate(xjw, xj, bj.angle);
  11406. vec2.add(xiw, xiw, bi.position);
  11407. vec2.add(xjw, xjw, bj.position);
  11408. var aiw = ai + bi.angle;
  11409. var ajw = aj + bj.angle;
  11410. np.enableFriction = cm.friction > 0;
  11411. np.frictionCoefficient = cm.friction;
  11412. var reducedMass;
  11413. if(bi.type === Body.STATIC || bi.type === Body.KINEMATIC){
  11414. reducedMass = bj.mass;
  11415. } else if(bj.type === Body.STATIC || bj.type === Body.KINEMATIC){
  11416. reducedMass = bi.mass;
  11417. } else {
  11418. reducedMass = (bi.mass*bj.mass)/(bi.mass+bj.mass);
  11419. }
  11420. np.slipForce = cm.friction*glen*reducedMass;
  11421. np.restitution = cm.restitution;
  11422. np.surfaceVelocity = cm.surfaceVelocity;
  11423. np.frictionStiffness = cm.frictionStiffness;
  11424. np.frictionRelaxation = cm.frictionRelaxation;
  11425. np.stiffness = cm.stiffness;
  11426. np.relaxation = cm.relaxation;
  11427. np.contactSkinSize = cm.contactSkinSize;
  11428. np.enabledEquations = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
  11429. var resolver = np[si.type | sj.type],
  11430. numContacts = 0;
  11431. if (resolver) {
  11432. var sensor = si.sensor || sj.sensor;
  11433. var numFrictionBefore = np.frictionEquations.length;
  11434. if (si.type < sj.type) {
  11435. numContacts = resolver.call(np, bi,si,xiw,aiw, bj,sj,xjw,ajw, sensor);
  11436. } else {
  11437. numContacts = resolver.call(np, bj,sj,xjw,ajw, bi,si,xiw,aiw, sensor);
  11438. }
  11439. var numFrictionEquations = np.frictionEquations.length - numFrictionBefore;
  11440. if(numContacts){
  11441. if( bi.allowSleep &&
  11442. bi.type === Body.DYNAMIC &&
  11443. bi.sleepState === Body.SLEEPING &&
  11444. bj.sleepState === Body.AWAKE &&
  11445. bj.type !== Body.STATIC
  11446. ){
  11447. var speedSquaredB = vec2.squaredLength(bj.velocity) + Math.pow(bj.angularVelocity,2);
  11448. var speedLimitSquaredB = Math.pow(bj.sleepSpeedLimit,2);
  11449. if(speedSquaredB >= speedLimitSquaredB*2){
  11450. bi._wakeUpAfterNarrowphase = true;
  11451. }
  11452. }
  11453. if( bj.allowSleep &&
  11454. bj.type === Body.DYNAMIC &&
  11455. bj.sleepState === Body.SLEEPING &&
  11456. bi.sleepState === Body.AWAKE &&
  11457. bi.type !== Body.STATIC
  11458. ){
  11459. var speedSquaredA = vec2.squaredLength(bi.velocity) + Math.pow(bi.angularVelocity,2);
  11460. var speedLimitSquaredA = Math.pow(bi.sleepSpeedLimit,2);
  11461. if(speedSquaredA >= speedLimitSquaredA*2){
  11462. bj._wakeUpAfterNarrowphase = true;
  11463. }
  11464. }
  11465. this.overlapKeeper.setOverlapping(bi, si, bj, sj);
  11466. if(this.has('beginContact') && this.overlapKeeper.isNewOverlap(si, sj)){
  11467. // Report new shape overlap
  11468. var e = this.beginContactEvent;
  11469. e.shapeA = si;
  11470. e.shapeB = sj;
  11471. e.bodyA = bi;
  11472. e.bodyB = bj;
  11473. // Reset contact equations
  11474. e.contactEquations.length = 0;
  11475. if(typeof(numContacts)==="number"){
  11476. for(var i=np.contactEquations.length-numContacts; i<np.contactEquations.length; i++){
  11477. e.contactEquations.push(np.contactEquations[i]);
  11478. }
  11479. }
  11480. this.emit(e);
  11481. }
  11482. // divide the max friction force by the number of contacts
  11483. if(typeof(numContacts)==="number" && numFrictionEquations > 1){ // Why divide by 1?
  11484. for(var i=np.frictionEquations.length-numFrictionEquations; i<np.frictionEquations.length; i++){
  11485. var f = np.frictionEquations[i];
  11486. f.setSlipForce(f.getSlipForce() / numFrictionEquations);
  11487. }
  11488. }
  11489. }
  11490. }
  11491. };
  11492. /**
  11493. * Add a spring to the simulation
  11494. *
  11495. * @method addSpring
  11496. * @param {Spring} spring
  11497. */
  11498. World.prototype.addSpring = function(spring){
  11499. this.springs.push(spring);
  11500. var evt = this.addSpringEvent;
  11501. evt.spring = spring;
  11502. this.emit(evt);
  11503. evt.spring = null;
  11504. };
  11505. /**
  11506. * Remove a spring
  11507. *
  11508. * @method removeSpring
  11509. * @param {Spring} spring
  11510. */
  11511. World.prototype.removeSpring = function(spring){
  11512. var idx = this.springs.indexOf(spring);
  11513. if(idx !== -1){
  11514. Utils.splice(this.springs,idx,1);
  11515. }
  11516. };
  11517. /**
  11518. * Add a body to the simulation
  11519. *
  11520. * @method addBody
  11521. * @param {Body} body
  11522. *
  11523. * @example
  11524. * var world = new World(),
  11525. * body = new Body();
  11526. * world.addBody(body);
  11527. * @todo What if this is done during step?
  11528. */
  11529. World.prototype.addBody = function(body){
  11530. if(this.bodies.indexOf(body) === -1){
  11531. this.bodies.push(body);
  11532. body.world = this;
  11533. var evt = this.addBodyEvent;
  11534. evt.body = body;
  11535. this.emit(evt);
  11536. evt.body = null;
  11537. }
  11538. };
  11539. /**
  11540. * Remove a body from the simulation. If this method is called during step(), the body removal is scheduled to after the step.
  11541. *
  11542. * @method removeBody
  11543. * @param {Body} body
  11544. */
  11545. World.prototype.removeBody = function(body){
  11546. if(this.stepping){
  11547. this.bodiesToBeRemoved.push(body);
  11548. } else {
  11549. body.world = null;
  11550. var idx = this.bodies.indexOf(body);
  11551. if(idx!==-1){
  11552. Utils.splice(this.bodies,idx,1);
  11553. this.removeBodyEvent.body = body;
  11554. body.resetConstraintVelocity();
  11555. this.emit(this.removeBodyEvent);
  11556. this.removeBodyEvent.body = null;
  11557. }
  11558. }
  11559. };
  11560. /**
  11561. * Get a body by its id.
  11562. * @method getBodyById
  11563. * @param {number} id
  11564. * @return {Body} The body, or false if it was not found.
  11565. */
  11566. World.prototype.getBodyById = function(id){
  11567. var bodies = this.bodies;
  11568. for(var i=0; i<bodies.length; i++){
  11569. var b = bodies[i];
  11570. if(b.id === id){
  11571. return b;
  11572. }
  11573. }
  11574. return false;
  11575. };
  11576. /**
  11577. * Disable collision between two bodies
  11578. * @method disableBodyCollision
  11579. * @param {Body} bodyA
  11580. * @param {Body} bodyB
  11581. */
  11582. World.prototype.disableBodyCollision = function(bodyA,bodyB){
  11583. this.disabledBodyCollisionPairs.push(bodyA,bodyB);
  11584. };
  11585. /**
  11586. * Enable collisions between the given two bodies
  11587. * @method enableBodyCollision
  11588. * @param {Body} bodyA
  11589. * @param {Body} bodyB
  11590. */
  11591. World.prototype.enableBodyCollision = function(bodyA,bodyB){
  11592. var pairs = this.disabledBodyCollisionPairs;
  11593. for(var i=0; i<pairs.length; i+=2){
  11594. if((pairs[i] === bodyA && pairs[i+1] === bodyB) || (pairs[i+1] === bodyA && pairs[i] === bodyB)){
  11595. pairs.splice(i,2);
  11596. return;
  11597. }
  11598. }
  11599. };
  11600. /**
  11601. * Resets the World, removes all bodies, constraints and springs.
  11602. *
  11603. * @method clear
  11604. */
  11605. World.prototype.clear = function(){
  11606. this.time = 0;
  11607. // Remove all solver equations
  11608. if(this.solver && this.solver.equations.length){
  11609. this.solver.removeAllEquations();
  11610. }
  11611. // Remove all constraints
  11612. var cs = this.constraints;
  11613. for(var i=cs.length-1; i>=0; i--){
  11614. this.removeConstraint(cs[i]);
  11615. }
  11616. // Remove all bodies
  11617. var bodies = this.bodies;
  11618. for(var i=bodies.length-1; i>=0; i--){
  11619. this.removeBody(bodies[i]);
  11620. }
  11621. // Remove all springs
  11622. var springs = this.springs;
  11623. for(var i=springs.length-1; i>=0; i--){
  11624. this.removeSpring(springs[i]);
  11625. }
  11626. // Remove all contact materials
  11627. var cms = this.contactMaterials;
  11628. for(var i=cms.length-1; i>=0; i--){
  11629. this.removeContactMaterial(cms[i]);
  11630. }
  11631. World.apply(this);
  11632. };
  11633. var hitTest_tmp1 = vec2.create(),
  11634. hitTest_zero = vec2.fromValues(0,0),
  11635. hitTest_tmp2 = vec2.fromValues(0,0);
  11636. /**
  11637. * Test if a world point overlaps bodies
  11638. * @method hitTest
  11639. * @param {Array} worldPoint Point to use for intersection tests
  11640. * @param {Array} bodies A list of objects to check for intersection
  11641. * @param {Number} precision Used for matching against particles and lines. Adds some margin to these infinitesimal objects.
  11642. * @return {Array} Array of bodies that overlap the point
  11643. * @todo Should use an api similar to the raycast function
  11644. * @todo Should probably implement a .containsPoint method for all shapes. Would be more efficient
  11645. * @todo Should use the broadphase
  11646. */
  11647. World.prototype.hitTest = function(worldPoint,bodies,precision){
  11648. precision = precision || 0;
  11649. // Create a dummy particle body with a particle shape to test against the bodies
  11650. var pb = new Body({ position:worldPoint }),
  11651. ps = new Particle(),
  11652. px = worldPoint,
  11653. pa = 0,
  11654. x = hitTest_tmp1,
  11655. zero = hitTest_zero,
  11656. tmp = hitTest_tmp2;
  11657. pb.addShape(ps);
  11658. var n = this.narrowphase,
  11659. result = [];
  11660. // Check bodies
  11661. for(var i=0, N=bodies.length; i!==N; i++){
  11662. var b = bodies[i];
  11663. for(var j=0, NS=b.shapes.length; j!==NS; j++){
  11664. var s = b.shapes[j];
  11665. // Get shape world position + angle
  11666. vec2.rotate(x, s.position, b.angle);
  11667. vec2.add(x, x, b.position);
  11668. var a = s.angle + b.angle;
  11669. if( (s instanceof Circle && n.circleParticle (b,s,x,a, pb,ps,px,pa, true)) ||
  11670. (s instanceof Convex && n.particleConvex (pb,ps,px,pa, b,s,x,a, true)) ||
  11671. (s instanceof Plane && n.particlePlane (pb,ps,px,pa, b,s,x,a, true)) ||
  11672. (s instanceof Capsule && n.particleCapsule (pb,ps,px,pa, b,s,x,a, true)) ||
  11673. (s instanceof Particle && vec2.squaredLength(vec2.sub(tmp,x,worldPoint)) < precision*precision)
  11674. ){
  11675. result.push(b);
  11676. }
  11677. }
  11678. }
  11679. return result;
  11680. };
  11681. /**
  11682. * Set the stiffness for all equations and contact materials.
  11683. * @method setGlobalStiffness
  11684. * @param {Number} stiffness
  11685. */
  11686. World.prototype.setGlobalStiffness = function(stiffness){
  11687. // Set for all constraints
  11688. var constraints = this.constraints;
  11689. for(var i=0; i !== constraints.length; i++){
  11690. var c = constraints[i];
  11691. for(var j=0; j !== c.equations.length; j++){
  11692. var eq = c.equations[j];
  11693. eq.stiffness = stiffness;
  11694. eq.needsUpdate = true;
  11695. }
  11696. }
  11697. // Set for all contact materials
  11698. var contactMaterials = this.contactMaterials;
  11699. for(var i=0; i !== contactMaterials.length; i++){
  11700. var c = contactMaterials[i];
  11701. c.stiffness = c.frictionStiffness = stiffness;
  11702. }
  11703. // Set for default contact material
  11704. var c = this.defaultContactMaterial;
  11705. c.stiffness = c.frictionStiffness = stiffness;
  11706. };
  11707. /**
  11708. * Set the relaxation for all equations and contact materials.
  11709. * @method setGlobalRelaxation
  11710. * @param {Number} relaxation
  11711. */
  11712. World.prototype.setGlobalRelaxation = function(relaxation){
  11713. // Set for all constraints
  11714. for(var i=0; i !== this.constraints.length; i++){
  11715. var c = this.constraints[i];
  11716. for(var j=0; j !== c.equations.length; j++){
  11717. var eq = c.equations[j];
  11718. eq.relaxation = relaxation;
  11719. eq.needsUpdate = true;
  11720. }
  11721. }
  11722. // Set for all contact materials
  11723. for(var i=0; i !== this.contactMaterials.length; i++){
  11724. var c = this.contactMaterials[i];
  11725. c.relaxation = c.frictionRelaxation = relaxation;
  11726. }
  11727. // Set for default contact material
  11728. var c = this.defaultContactMaterial;
  11729. c.relaxation = c.frictionRelaxation = relaxation;
  11730. };
  11731. var tmpAABB = new AABB();
  11732. var tmpArray = [];
  11733. /**
  11734. * Ray cast against all bodies in the world.
  11735. * @method raycast
  11736. * @param {RaycastResult} result
  11737. * @param {Ray} ray
  11738. * @return {boolean} True if any body was hit.
  11739. *
  11740. * @example
  11741. * var ray = new Ray({
  11742. * mode: Ray.CLOSEST, // or ANY
  11743. * from: [0, 0],
  11744. * to: [10, 0],
  11745. * });
  11746. * var result = new RaycastResult();
  11747. * world.raycast(result, ray);
  11748. *
  11749. * // Get the hit point
  11750. * var hitPoint = vec2.create();
  11751. * result.getHitPoint(hitPoint, ray);
  11752. * console.log('Hit point: ', hitPoint[0], hitPoint[1], ' at distance ' + result.getHitDistance(ray));
  11753. *
  11754. * @example
  11755. * var ray = new Ray({
  11756. * mode: Ray.ALL,
  11757. * from: [0, 0],
  11758. * to: [10, 0],
  11759. * callback: function(result){
  11760. *
  11761. * // Print some info about the hit
  11762. * console.log('Hit body and shape: ', result.body, result.shape);
  11763. *
  11764. * // Get the hit point
  11765. * var hitPoint = vec2.create();
  11766. * result.getHitPoint(hitPoint, ray);
  11767. * console.log('Hit point: ', hitPoint[0], hitPoint[1], ' at distance ' + result.getHitDistance(ray));
  11768. *
  11769. * // If you are happy with the hits you got this far, you can stop the traversal here:
  11770. * result.stop();
  11771. * }
  11772. * });
  11773. * var result = new RaycastResult();
  11774. * world.raycast(result, ray);
  11775. */
  11776. World.prototype.raycast = function(result, ray){
  11777. // Get all bodies within the ray AABB
  11778. ray.getAABB(tmpAABB);
  11779. this.broadphase.aabbQuery(this, tmpAABB, tmpArray);
  11780. ray.intersectBodies(result, tmpArray);
  11781. tmpArray.length = 0;
  11782. return result.hasHit();
  11783. };
  11784. },{"../../package.json":6,"../collision/AABB":7,"../collision/Broadphase":8,"../collision/Narrowphase":10,"../collision/Ray":11,"../collision/SAPBroadphase":13,"../constraints/Constraint":14,"../constraints/DistanceConstraint":15,"../constraints/GearConstraint":16,"../constraints/LockConstraint":17,"../constraints/PrismaticConstraint":18,"../constraints/RevoluteConstraint":19,"../events/EventEmitter":26,"../material/ContactMaterial":27,"../material/Material":28,"../math/vec2":30,"../objects/Body":31,"../objects/LinearSpring":32,"../objects/RotationalSpring":33,"../shapes/Capsule":38,"../shapes/Circle":39,"../shapes/Convex":40,"../shapes/Line":42,"../shapes/Particle":43,"../shapes/Plane":44,"../shapes/Shape":45,"../solver/GSSolver":46,"../solver/Solver":47,"../utils/OverlapKeeper":52,"../utils/Utils":57,"./IslandManager":59}]},{},[36])
  11785. (36)
  11786. });
  11787. /**
  11788. * @author Mat Groves http://matgroves.com/ @Doormat23
  11789. */
  11790. (function(){
  11791. var root = this;
  11792. /**
  11793. * Namespace-class for [pixi.js](http://www.pixijs.com/).
  11794. *
  11795. * Contains assorted static properties and enumerations.
  11796. *
  11797. * @namespace PIXI
  11798. * @author Mat Groves http://matgroves.com/ @Doormat23
  11799. */
  11800. var PIXI = PIXI || {};
  11801. /**
  11802. * @author Mat Groves http://matgroves.com @Doormat23
  11803. * @author Richard Davey <rich@photonstorm.com>
  11804. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11805. */
  11806. /**
  11807. * The base class for all objects that are rendered. Contains properties for position, scaling,
  11808. * rotation, masks and cache handling.
  11809. *
  11810. * This is an abstract class and should not be used on its own, rather it should be extended.
  11811. *
  11812. * It is used internally by the likes of PIXI.Sprite.
  11813. *
  11814. * @class PIXI.DisplayObject
  11815. * @constructor
  11816. */
  11817. PIXI.DisplayObject = function () {
  11818. /**
  11819. * The coordinates, in pixels, of this DisplayObject, relative to its parent container.
  11820. *
  11821. * The value of this property does not reflect any positioning happening further up the display list.
  11822. * To obtain that value please see the `worldPosition` property.
  11823. *
  11824. * @property {PIXI.Point} position
  11825. * @default
  11826. */
  11827. this.position = new PIXI.Point(0, 0);
  11828. /**
  11829. * The scale of this DisplayObject. A scale of 1:1 represents the DisplayObject
  11830. * at its default size. A value of 0.5 would scale this DisplayObject by half, and so on.
  11831. *
  11832. * The value of this property does not reflect any scaling happening further up the display list.
  11833. * To obtain that value please see the `worldScale` property.
  11834. *
  11835. * @property {PIXI.Point} scale
  11836. * @default
  11837. */
  11838. this.scale = new PIXI.Point(1, 1);
  11839. /**
  11840. * The pivot point of this DisplayObject that it rotates around. The values are expressed
  11841. * in pixel values.
  11842. * @property {PIXI.Point} pivot
  11843. * @default
  11844. */
  11845. this.pivot = new PIXI.Point(0, 0);
  11846. /**
  11847. * The rotation of this DisplayObject. The value is given, and expressed, in radians, and is based on
  11848. * a right-handed orientation.
  11849. *
  11850. * The value of this property does not reflect any rotation happening further up the display list.
  11851. * To obtain that value please see the `worldRotation` property.
  11852. *
  11853. * @property {number} rotation
  11854. * @default
  11855. */
  11856. this.rotation = 0;
  11857. /**
  11858. * The alpha value of this DisplayObject. A value of 1 is fully opaque. A value of 0 is transparent.
  11859. * Please note that an object with an alpha value of 0 is skipped during the render pass.
  11860. *
  11861. * The value of this property does not reflect any alpha values set further up the display list.
  11862. * To obtain that value please see the `worldAlpha` property.
  11863. *
  11864. * @property {number} alpha
  11865. * @default
  11866. */
  11867. this.alpha = 1;
  11868. /**
  11869. * The visibility of this DisplayObject. A value of `false` makes the object invisible.
  11870. * A value of `true` makes it visible. Please note that an object with a visible value of
  11871. * `false` is skipped during the render pass. Equally a DisplayObject with visible false will
  11872. * not render any of its children.
  11873. *
  11874. * The value of this property does not reflect any visible values set further up the display list.
  11875. * To obtain that value please see the `worldVisible` property.
  11876. *
  11877. * @property {boolean} visible
  11878. * @default
  11879. */
  11880. this.visible = true;
  11881. /**
  11882. * This is the defined area that will pick up mouse / touch events. It is null by default.
  11883. * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children)
  11884. *
  11885. * @property hitArea
  11886. * @type Rectangle|Circle|Ellipse|Polygon
  11887. */
  11888. this.hitArea = null;
  11889. /**
  11890. * Should this DisplayObject be rendered by the renderer? An object with a renderable value of
  11891. * `false` is skipped during the render pass.
  11892. *
  11893. * @property {boolean} renderable
  11894. * @default
  11895. */
  11896. this.renderable = false;
  11897. /**
  11898. * The parent DisplayObjectContainer that this DisplayObject is a child of.
  11899. * All DisplayObjects must belong to a parent in order to be rendered.
  11900. * The root parent is the Stage object. This property is set automatically when the
  11901. * DisplayObject is added to, or removed from, a DisplayObjectContainer.
  11902. *
  11903. * @property {PIXI.DisplayObjectContainer} parent
  11904. * @default
  11905. * @readOnly
  11906. */
  11907. this.parent = null;
  11908. /**
  11909. * The multiplied alpha value of this DisplayObject. A value of 1 is fully opaque. A value of 0 is transparent.
  11910. * This value is the calculated total, based on the alpha values of all parents of this DisplayObjects
  11911. * in the display list.
  11912. *
  11913. * To obtain, and set, the local alpha value, see the `alpha` property.
  11914. *
  11915. * Note: This property is only updated at the end of the `updateTransform` call, once per render. Until
  11916. * that happens this property will contain values based on the previous frame. Be mindful of this if
  11917. * accessing this property outside of the normal game flow, i.e. from an asynchronous event callback.
  11918. *
  11919. * @property {number} worldAlpha
  11920. * @readOnly
  11921. */
  11922. this.worldAlpha = 1;
  11923. /**
  11924. * The current transform of this DisplayObject.
  11925. *
  11926. * This property contains the calculated total, based on the transforms of all parents of this
  11927. * DisplayObject in the display list.
  11928. *
  11929. * Note: This property is only updated at the end of the `updateTransform` call, once per render. Until
  11930. * that happens this property will contain values based on the previous frame. Be mindful of this if
  11931. * accessing this property outside of the normal game flow, i.e. from an asynchronous event callback.
  11932. *
  11933. * @property {Phaser.Matrix} worldTransform
  11934. * @readOnly
  11935. */
  11936. this.worldTransform = new Phaser.Matrix();
  11937. /**
  11938. * The coordinates, in pixels, of this DisplayObject within the world.
  11939. *
  11940. * This property contains the calculated total, based on the positions of all parents of this
  11941. * DisplayObject in the display list.
  11942. *
  11943. * Note: This property is only updated at the end of the `updateTransform` call, once per render. Until
  11944. * that happens this property will contain values based on the previous frame. Be mindful of this if
  11945. * accessing this property outside of the normal game flow, i.e. from an asynchronous event callback.
  11946. *
  11947. * @property {PIXI.Point} worldPosition
  11948. * @readOnly
  11949. */
  11950. this.worldPosition = new PIXI.Point(0, 0);
  11951. /**
  11952. * The global scale of this DisplayObject.
  11953. *
  11954. * This property contains the calculated total, based on the scales of all parents of this
  11955. * DisplayObject in the display list.
  11956. *
  11957. * Note: This property is only updated at the end of the `updateTransform` call, once per render. Until
  11958. * that happens this property will contain values based on the previous frame. Be mindful of this if
  11959. * accessing this property outside of the normal game flow, i.e. from an asynchronous event callback.
  11960. *
  11961. * @property {PIXI.Point} worldScale
  11962. * @readOnly
  11963. */
  11964. this.worldScale = new PIXI.Point(1, 1);
  11965. /**
  11966. * The rotation, in radians, of this DisplayObject.
  11967. *
  11968. * This property contains the calculated total, based on the rotations of all parents of this
  11969. * DisplayObject in the display list.
  11970. *
  11971. * Note: This property is only updated at the end of the `updateTransform` call, once per render. Until
  11972. * that happens this property will contain values based on the previous frame. Be mindful of this if
  11973. * accessing this property outside of the normal game flow, i.e. from an asynchronous event callback.
  11974. *
  11975. * @property {number} worldRotation
  11976. * @readOnly
  11977. */
  11978. this.worldRotation = 0;
  11979. /**
  11980. * The rectangular area used by filters when rendering a shader for this DisplayObject.
  11981. *
  11982. * @property {PIXI.Rectangle} filterArea
  11983. * @type Rectangle
  11984. * @default
  11985. */
  11986. this.filterArea = null;
  11987. /**
  11988. * @property {number} _sr - Cached rotation value.
  11989. * @private
  11990. */
  11991. this._sr = 0;
  11992. /**
  11993. * @property {number} _cr - Cached rotation value.
  11994. * @private
  11995. */
  11996. this._cr = 1;
  11997. /**
  11998. * @property {PIXI.Rectangle} _bounds - The cached bounds of this object.
  11999. * @private
  12000. */
  12001. this._bounds = new PIXI.Rectangle(0, 0, 0, 0);
  12002. /**
  12003. * @property {PIXI.Rectangle} _currentBounds - The most recently calculated bounds of this object.
  12004. * @private
  12005. */
  12006. this._currentBounds = null;
  12007. /**
  12008. * @property {PIXI.Rectangle} _mask - The cached mask of this object.
  12009. * @private
  12010. */
  12011. this._mask = null;
  12012. /**
  12013. * @property {boolean} _cacheAsBitmap - Internal cache as bitmap flag.
  12014. * @private
  12015. */
  12016. this._cacheAsBitmap = false;
  12017. /**
  12018. * @property {boolean} _cacheIsDirty - Internal dirty cache flag.
  12019. * @private
  12020. */
  12021. this._cacheIsDirty = false;
  12022. };
  12023. PIXI.DisplayObject.prototype = {
  12024. constructor: PIXI.DisplayObject,
  12025. /**
  12026. * Destroy this DisplayObject.
  12027. *
  12028. * Removes any cached sprites, sets renderable flag to false, and nulls filters, bounds and mask.
  12029. *
  12030. * Also iteratively calls `destroy` on any children.
  12031. *
  12032. * @method PIXI.DisplayObject#destroy
  12033. */
  12034. destroy: function () {
  12035. if (this.children)
  12036. {
  12037. var i = this.children.length;
  12038. while (i--)
  12039. {
  12040. this.children[i].destroy();
  12041. }
  12042. this.children = [];
  12043. }
  12044. this.hitArea = null;
  12045. this.parent = null;
  12046. this.worldTransform = null;
  12047. this.filterArea = null;
  12048. this.renderable = false;
  12049. this._bounds = null;
  12050. this._currentBounds = null;
  12051. this._mask = null;
  12052. this._destroyCachedSprite();
  12053. },
  12054. /**
  12055. * Updates the transform matrix this DisplayObject uses for rendering.
  12056. *
  12057. * If the object has no parent, and no parent parameter is provided, it will default to
  12058. * Phaser.Game.World as the parent transform to use. If that is unavailable the transform fails to take place.
  12059. *
  12060. * The `parent` parameter has priority over the actual parent. Use it as a parent override.
  12061. * Setting it does **not** change the actual parent of this DisplayObject.
  12062. *
  12063. * Calling this method updates the `worldTransform`, `worldAlpha`, `worldPosition`, `worldScale`
  12064. * and `worldRotation` properties.
  12065. *
  12066. * If a `transformCallback` has been specified, it is called at the end of this method, and is passed
  12067. * the new, updated, worldTransform property, along with the parent transform used.
  12068. *
  12069. * @method PIXI.DisplayObject#updateTransform
  12070. * @param {PIXI.DisplayObjectContainer} [parent] - Optional parent to calculate this DisplayObjects transform from.
  12071. * @return {PIXI.DisplayObject} - A reference to this DisplayObject.
  12072. */
  12073. updateTransform: function (parent) {
  12074. if (!parent && !this.parent && !this.game)
  12075. {
  12076. return this;
  12077. }
  12078. var p = this.parent;
  12079. if (parent)
  12080. {
  12081. p = parent;
  12082. }
  12083. else if (!this.parent)
  12084. {
  12085. p = this.game.world;
  12086. }
  12087. // create some matrix refs for easy access
  12088. var pt = p.worldTransform;
  12089. var wt = this.worldTransform;
  12090. // temporary matrix variables
  12091. var a, b, c, d, tx, ty;
  12092. // so if rotation is between 0 then we can simplify the multiplication process..
  12093. if (this.rotation % Phaser.Math.PI2)
  12094. {
  12095. // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes
  12096. if (this.rotation !== this.rotationCache)
  12097. {
  12098. this.rotationCache = this.rotation;
  12099. this._sr = Math.sin(this.rotation);
  12100. this._cr = Math.cos(this.rotation);
  12101. }
  12102. // get the matrix values of the displayobject based on its transform properties..
  12103. a = this._cr * this.scale.x;
  12104. b = this._sr * this.scale.x;
  12105. c = -this._sr * this.scale.y;
  12106. d = this._cr * this.scale.y;
  12107. tx = this.position.x;
  12108. ty = this.position.y;
  12109. // check for pivot.. not often used so geared towards that fact!
  12110. if (this.pivot.x || this.pivot.y)
  12111. {
  12112. tx -= this.pivot.x * a + this.pivot.y * c;
  12113. ty -= this.pivot.x * b + this.pivot.y * d;
  12114. }
  12115. // concat the parent matrix with the objects transform.
  12116. wt.a = a * pt.a + b * pt.c;
  12117. wt.b = a * pt.b + b * pt.d;
  12118. wt.c = c * pt.a + d * pt.c;
  12119. wt.d = c * pt.b + d * pt.d;
  12120. wt.tx = tx * pt.a + ty * pt.c + pt.tx;
  12121. wt.ty = tx * pt.b + ty * pt.d + pt.ty;
  12122. }
  12123. else
  12124. {
  12125. // lets do the fast version as we know there is no rotation..
  12126. a = this.scale.x;
  12127. b = 0;
  12128. c = 0;
  12129. d = this.scale.y;
  12130. tx = this.position.x - this.pivot.x * a;
  12131. ty = this.position.y - this.pivot.y * d;
  12132. wt.a = a * pt.a;
  12133. wt.b = a * pt.b;
  12134. wt.c = d * pt.c;
  12135. wt.d = d * pt.d;
  12136. wt.tx = tx * pt.a + ty * pt.c + pt.tx;
  12137. wt.ty = tx * pt.b + ty * pt.d + pt.ty;
  12138. }
  12139. a = wt.a;
  12140. b = wt.b;
  12141. c = wt.c;
  12142. d = wt.d;
  12143. var determ = (a * d) - (b * c);
  12144. if (a || b)
  12145. {
  12146. var r = Math.sqrt((a * a) + (b * b));
  12147. this.worldRotation = (b > 0) ? Math.acos(a / r) : -Math.acos(a / r);
  12148. this.worldScale.x = r;
  12149. this.worldScale.y = determ / r;
  12150. }
  12151. else if (c || d)
  12152. {
  12153. var s = Math.sqrt((c * c) + (d * d));
  12154. this.worldRotation = Phaser.Math.HALF_PI - ((d > 0) ? Math.acos(-c / s) : -Math.acos(c / s));
  12155. this.worldScale.x = determ / s;
  12156. this.worldScale.y = s;
  12157. }
  12158. else
  12159. {
  12160. this.worldScale.x = 0;
  12161. this.worldScale.y = 0;
  12162. }
  12163. // Set the World values
  12164. this.worldAlpha = this.alpha * p.worldAlpha;
  12165. this.worldPosition.x = wt.tx;
  12166. this.worldPosition.y = wt.ty;
  12167. // reset the bounds each time this is called!
  12168. this._currentBounds = null;
  12169. // Custom callback?
  12170. if (this.transformCallback)
  12171. {
  12172. this.transformCallback.call(this.transformCallbackContext, wt, pt);
  12173. }
  12174. return this;
  12175. },
  12176. /**
  12177. * To be overridden by classes that require it.
  12178. *
  12179. * @method PIXI.DisplayObject#preUpdate
  12180. */
  12181. preUpdate: function () {
  12182. },
  12183. /**
  12184. * Generates a RenderTexture based on this DisplayObject, which can they be used to texture other Sprites.
  12185. * This can be useful if your DisplayObject is static, or complicated, and needs to be reused multiple times.
  12186. *
  12187. * Please note that no garbage collection takes place on old textures. It is up to you to destroy old textures,
  12188. * and references to them, so they don't linger in memory.
  12189. *
  12190. * @method PIXI.DisplayObject#generateTexture
  12191. * @param {number} [resolution=1] - The resolution of the texture being generated.
  12192. * @param {number} [scaleMode=PIXI.scaleModes.DEFAULT] - See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values.
  12193. * @param {PIXI.CanvasRenderer|PIXI.WebGLRenderer} renderer - The renderer used to generate the texture.
  12194. * @return {Phaser.RenderTexture} - A RenderTexture containing an image of this DisplayObject at the time it was invoked.
  12195. */
  12196. generateTexture: function (resolution, scaleMode, renderer) {
  12197. var bounds = this.getLocalBounds();
  12198. var renderTexture = new Phaser.RenderTexture(this.game, bounds.width | 0, bounds.height | 0, renderer, scaleMode, resolution);
  12199. PIXI.DisplayObject._tempMatrix.tx = -bounds.x;
  12200. PIXI.DisplayObject._tempMatrix.ty = -bounds.y;
  12201. renderTexture.render(this, PIXI.DisplayObject._tempMatrix);
  12202. return renderTexture;
  12203. },
  12204. /**
  12205. * If this DisplayObject has a cached Sprite, this method generates and updates it.
  12206. *
  12207. * @method PIXI.DisplayObject#updateCache
  12208. * @return {PIXI.DisplayObject} - A reference to this DisplayObject.
  12209. */
  12210. updateCache: function () {
  12211. this._generateCachedSprite();
  12212. return this;
  12213. },
  12214. /**
  12215. * Calculates the global position of this DisplayObject, based on the position given.
  12216. *
  12217. * @method PIXI.DisplayObject#toGlobal
  12218. * @param {PIXI.Point} position - The global position to calculate from.
  12219. * @return {PIXI.Point} - A point object representing the position of this DisplayObject based on the global position given.
  12220. */
  12221. toGlobal: function (position) {
  12222. this.updateTransform();
  12223. return this.worldTransform.apply(position);
  12224. },
  12225. /**
  12226. * Calculates the local position of this DisplayObject, relative to another point.
  12227. *
  12228. * @method PIXI.DisplayObject#toLocal
  12229. * @param {PIXI.Point} position - The world origin to calculate from.
  12230. * @param {PIXI.DisplayObject} [from] - An optional DisplayObject to calculate the global position from.
  12231. * @return {PIXI.Point} - A point object representing the position of this DisplayObject based on the global position given.
  12232. */
  12233. toLocal: function (position, from) {
  12234. if (from)
  12235. {
  12236. position = from.toGlobal(position);
  12237. }
  12238. this.updateTransform();
  12239. return this.worldTransform.applyInverse(position);
  12240. },
  12241. /**
  12242. * Internal method.
  12243. *
  12244. * @method PIXI.DisplayObject#_renderCachedSprite
  12245. * @private
  12246. * @param {Object} renderSession - The render session
  12247. */
  12248. _renderCachedSprite: function (renderSession) {
  12249. this._cachedSprite.worldAlpha = this.worldAlpha;
  12250. if (renderSession.gl)
  12251. {
  12252. PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession);
  12253. }
  12254. else
  12255. {
  12256. PIXI.Sprite.prototype._renderCanvas.call(this._cachedSprite, renderSession);
  12257. }
  12258. },
  12259. /**
  12260. * Internal method.
  12261. *
  12262. * @method PIXI.DisplayObject#_generateCachedSprite
  12263. * @private
  12264. */
  12265. _generateCachedSprite: function () {
  12266. this._cacheAsBitmap = false;
  12267. var bounds = this.getLocalBounds();
  12268. // Round it off and force non-zero dimensions
  12269. bounds.width = Math.max(1, Math.ceil(bounds.width));
  12270. bounds.height = Math.max(1, Math.ceil(bounds.height));
  12271. this.updateTransform();
  12272. if (!this._cachedSprite)
  12273. {
  12274. var textureUnit = 0;
  12275. if (this.texture && this.texture.baseTexture && PIXI._enableMultiTextureToggle)
  12276. {
  12277. textureUnit = this.texture.baseTexture.textureIndex;
  12278. }
  12279. var renderTexture = new Phaser.RenderTexture(this.game, bounds.width, bounds.height, undefined, undefined, undefined, undefined, textureUnit);
  12280. this._cachedSprite = new PIXI.Sprite(renderTexture);
  12281. this._cachedSprite.worldTransform = this.worldTransform;
  12282. }
  12283. else
  12284. {
  12285. this._cachedSprite.texture.resize(bounds.width, bounds.height);
  12286. }
  12287. // Remove filters
  12288. var tempFilters = this._filters;
  12289. this._filters = null;
  12290. this._cachedSprite.filters = tempFilters;
  12291. PIXI.DisplayObject._tempMatrix.tx = -bounds.x;
  12292. PIXI.DisplayObject._tempMatrix.ty = -bounds.y;
  12293. this._cachedSprite.texture.render(this, PIXI.DisplayObject._tempMatrix, true);
  12294. this._cachedSprite.anchor.x = -(bounds.x / bounds.width);
  12295. this._cachedSprite.anchor.y = -(bounds.y / bounds.height);
  12296. this._filters = tempFilters;
  12297. this._cacheAsBitmap = true;
  12298. },
  12299. /**
  12300. * Destroys a cached Sprite.
  12301. *
  12302. * @method PIXI.DisplayObject#_destroyCachedSprite
  12303. * @private
  12304. */
  12305. _destroyCachedSprite: function () {
  12306. if (!this._cachedSprite)
  12307. {
  12308. return;
  12309. }
  12310. this._cachedSprite.texture.destroy(true);
  12311. this._cachedSprite = null;
  12312. }
  12313. };
  12314. // Alias for updateTransform. As used in DisplayObject container, etc.
  12315. PIXI.DisplayObject.prototype.displayObjectUpdateTransform = PIXI.DisplayObject.prototype.updateTransform;
  12316. Object.defineProperties(PIXI.DisplayObject.prototype, {
  12317. /**
  12318. * The horizontal position of the DisplayObject, in pixels, relative to its parent.
  12319. * If you need the world position of the DisplayObject, use `DisplayObject.worldPosition` instead.
  12320. * @name PIXI.DisplayObject#x
  12321. * @property {number} x - The horizontal position of the DisplayObject, in pixels, relative to its parent.
  12322. */
  12323. 'x': {
  12324. get: function () {
  12325. return this.position.x;
  12326. },
  12327. set: function (value) {
  12328. this.position.x = value;
  12329. }
  12330. },
  12331. /**
  12332. * The vertical position of the DisplayObject, in pixels, relative to its parent.
  12333. * If you need the world position of the DisplayObject, use `DisplayObject.worldPosition` instead.
  12334. * @name PIXI.DisplayObject#y
  12335. * @property {number} y - The vertical position of the DisplayObject, in pixels, relative to its parent.
  12336. */
  12337. 'y': {
  12338. get: function () {
  12339. return this.position.y;
  12340. },
  12341. set: function (value) {
  12342. this.position.y = value;
  12343. }
  12344. },
  12345. /**
  12346. * Indicates if this DisplayObject is visible, based on it, and all of its parents, `visible` property values.
  12347. * @name PIXI.DisplayObject#worldVisible
  12348. * @property {boolean} worldVisible - Indicates if this DisplayObject is visible, based on it, and all of its parents, `visible` property values.
  12349. */
  12350. 'worldVisible': {
  12351. get: function () {
  12352. if (!this.visible)
  12353. {
  12354. return false;
  12355. }
  12356. else
  12357. {
  12358. var item = this.parent;
  12359. if (!item)
  12360. {
  12361. return this.visible;
  12362. }
  12363. else
  12364. {
  12365. do
  12366. {
  12367. if (!item.visible)
  12368. {
  12369. return false;
  12370. }
  12371. item = item.parent;
  12372. }
  12373. while (item);
  12374. }
  12375. return true;
  12376. }
  12377. }
  12378. },
  12379. /**
  12380. * Sets a mask for this DisplayObject. A mask is an instance of a Graphics object.
  12381. * When applied it limits the visible area of this DisplayObject to the shape of the mask.
  12382. * Under a Canvas renderer it uses shape clipping. Under a WebGL renderer it uses a Stencil Buffer.
  12383. * To remove a mask, set this property to `null`.
  12384. *
  12385. * @name PIXI.DisplayObject#mask
  12386. * @property {Phaser.Graphics} mask - The mask applied to this DisplayObject. Set to `null` to remove an existing mask.
  12387. */
  12388. 'mask': {
  12389. get: function () {
  12390. return this._mask;
  12391. },
  12392. set: function (value) {
  12393. if (this._mask)
  12394. {
  12395. this._mask.isMask = false;
  12396. }
  12397. this._mask = value;
  12398. if (value)
  12399. {
  12400. this._mask.isMask = true;
  12401. }
  12402. }
  12403. },
  12404. /**
  12405. * Sets the filters for this DisplayObject. This is a WebGL only feature, and is ignored by the Canvas
  12406. * Renderer. A filter is a shader applied to this DisplayObject. You can modify the placement of the filter
  12407. * using `DisplayObject.filterArea`.
  12408. *
  12409. * To remove filters, set this property to `null`.
  12410. *
  12411. * Note: You cannot have a filter set, and a MULTIPLY Blend Mode active, at the same time. Setting a
  12412. * filter will reset this DisplayObjects blend mode to NORMAL.
  12413. *
  12414. * @name PIXI.DisplayObject#filters
  12415. * @property {Array} filters - An Array of Phaser.Filter objects, or objects that extend them.
  12416. */
  12417. 'filters': {
  12418. get: function () {
  12419. return this._filters;
  12420. },
  12421. set: function (value) {
  12422. if (Array.isArray(value))
  12423. {
  12424. // Put all the passes in one place.
  12425. var passes = [];
  12426. for (var i = 0; i < value.length; i++)
  12427. {
  12428. var filterPasses = value[i].passes;
  12429. for (var j = 0; j < filterPasses.length; j++)
  12430. {
  12431. passes.push(filterPasses[j]);
  12432. }
  12433. }
  12434. // Needed any more?
  12435. this._filterBlock = { target: this, filterPasses: passes };
  12436. }
  12437. this._filters = value;
  12438. if (this.blendMode && this.blendMode === PIXI.blendModes.MULTIPLY)
  12439. {
  12440. this.blendMode = PIXI.blendModes.NORMAL;
  12441. }
  12442. }
  12443. },
  12444. /**
  12445. * Sets if this DisplayObject should be cached as a bitmap.
  12446. *
  12447. * When invoked it will take a snapshot of the DisplayObject, as it is at that moment, and store it
  12448. * in a RenderTexture. This is then used whenever this DisplayObject is rendered. It can provide a
  12449. * performance benefit for complex, but static, DisplayObjects. I.e. those with lots of children.
  12450. *
  12451. * Transparent areas adjoining the edges may be removed ({@link https://github.com/photonstorm/phaser-ce/issues/283 #283}).
  12452. *
  12453. * Cached Bitmaps do not track their parents. If you update a property of this DisplayObject, it will not
  12454. * re-generate the cached bitmap automatically. To do that you need to call `DisplayObject.updateCache`.
  12455. *
  12456. * To remove a cached bitmap, set this property to `null`.
  12457. *
  12458. * @name PIXI.DisplayObject#cacheAsBitmap
  12459. * @property {boolean} cacheAsBitmap - Cache this DisplayObject as a Bitmap. Set to `null` to remove an existing cached bitmap.
  12460. */
  12461. 'cacheAsBitmap': {
  12462. get: function () {
  12463. return this._cacheAsBitmap;
  12464. },
  12465. set: function (value) {
  12466. if (this._cacheAsBitmap === value)
  12467. {
  12468. return;
  12469. }
  12470. if (value)
  12471. {
  12472. this._generateCachedSprite();
  12473. }
  12474. else
  12475. {
  12476. this._destroyCachedSprite();
  12477. }
  12478. this._cacheAsBitmap = value;
  12479. }
  12480. }
  12481. });
  12482. /**
  12483. * @author Mat Groves http://matgroves.com/ @Doormat23
  12484. */
  12485. /**
  12486. * A DisplayObjectContainer represents a collection of display objects.
  12487. * It is the base class of all display objects that act as a container for other objects.
  12488. *
  12489. * @class PIXI.DisplayObjectContainer
  12490. * @extends PIXI.DisplayObject
  12491. * @constructor
  12492. */
  12493. PIXI.DisplayObjectContainer = function () {
  12494. PIXI.DisplayObject.call(this);
  12495. /**
  12496. * [read-only] The array of children of this container.
  12497. *
  12498. * @property children
  12499. * @type Array(DisplayObject)
  12500. * @readOnly
  12501. */
  12502. this.children = [];
  12503. /**
  12504. * If `ignoreChildInput` is `false` it will allow this objects _children_ to be considered as valid for Input events.
  12505. *
  12506. * If this property is `true` then the children will _not_ be considered as valid for Input events.
  12507. *
  12508. * Note that this property isn't recursive: only immediate children are influenced, it doesn't scan further down.
  12509. * @property {boolean} ignoreChildInput
  12510. * @default
  12511. */
  12512. this.ignoreChildInput = false;
  12513. };
  12514. PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype );
  12515. PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer;
  12516. /**
  12517. * Adds a child to the container.
  12518. *
  12519. * @method PIXI.DisplayObjectContainer#addChild
  12520. * @param child {DisplayObject} The DisplayObject to add to the container
  12521. * @return {DisplayObject} The child that was added.
  12522. */
  12523. PIXI.DisplayObjectContainer.prototype.addChild = function (child) {
  12524. return this.addChildAt(child, this.children.length);
  12525. };
  12526. /**
  12527. * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown
  12528. *
  12529. * @method PIXI.DisplayObjectContainer#addChildAt
  12530. * @param child {DisplayObject} The child to add
  12531. * @param index {Number} The index to place the child in
  12532. * @return {DisplayObject} The child that was added.
  12533. */
  12534. PIXI.DisplayObjectContainer.prototype.addChildAt = function (child, index) {
  12535. if (index >= 0 && index <= this.children.length)
  12536. {
  12537. if (child.parent)
  12538. {
  12539. child.parent.removeChild(child);
  12540. }
  12541. child.parent = this;
  12542. this.children.splice(index, 0, child);
  12543. return child;
  12544. }
  12545. else
  12546. {
  12547. throw new Error(child + 'addChildAt: The index '+ index +' supplied is out of bounds ' + this.children.length);
  12548. }
  12549. };
  12550. /**
  12551. * Swaps the position of 2 Display Objects within this container.
  12552. *
  12553. * @method PIXI.DisplayObjectContainer#swapChildren
  12554. * @param child {DisplayObject}
  12555. * @param child2 {DisplayObject}
  12556. */
  12557. PIXI.DisplayObjectContainer.prototype.swapChildren = function (child, child2) {
  12558. if (child === child2)
  12559. {
  12560. return;
  12561. }
  12562. var index1 = this.getChildIndex(child);
  12563. var index2 = this.getChildIndex(child2);
  12564. if (index1 < 0 || index2 < 0)
  12565. {
  12566. throw new Error('swapChildren: Both the supplied DisplayObjects must be a child of the caller.');
  12567. }
  12568. this.children[index1] = child2;
  12569. this.children[index2] = child;
  12570. };
  12571. /**
  12572. * Returns the index position of a child DisplayObject instance
  12573. *
  12574. * @method PIXI.DisplayObjectContainer#getChildIndex
  12575. * @param child {DisplayObject} The DisplayObject instance to identify
  12576. * @return {Number} The index position of the child display object to identify
  12577. */
  12578. PIXI.DisplayObjectContainer.prototype.getChildIndex = function (child) {
  12579. var index = this.children.indexOf(child);
  12580. if (index === -1)
  12581. {
  12582. throw new Error('The supplied DisplayObject must be a child of the caller');
  12583. }
  12584. return index;
  12585. };
  12586. /**
  12587. * Changes the position of an existing child in the display object container
  12588. *
  12589. * @method PIXI.DisplayObjectContainer#setChildIndex
  12590. * @param child {DisplayObject} The child DisplayObject instance for which you want to change the index number
  12591. * @param index {Number} The resulting index number for the child display object
  12592. */
  12593. PIXI.DisplayObjectContainer.prototype.setChildIndex = function (child, index) {
  12594. if (index < 0 || index >= this.children.length)
  12595. {
  12596. throw new Error('The supplied index is out of bounds');
  12597. }
  12598. var currentIndex = this.getChildIndex(child);
  12599. this.children.splice(currentIndex, 1); //remove from old position
  12600. this.children.splice(index, 0, child); //add at new position
  12601. };
  12602. /**
  12603. * Returns the child at the specified index
  12604. *
  12605. * @method PIXI.DisplayObjectContainer#getChildAt
  12606. * @param index {Number} The index to get the child from
  12607. * @return {DisplayObject} The child at the given index, if any.
  12608. */
  12609. PIXI.DisplayObjectContainer.prototype.getChildAt = function (index) {
  12610. if (index < 0 || index >= this.children.length)
  12611. {
  12612. throw new Error('getChildAt: Supplied index '+ index +' does not exist in the child list, or the supplied DisplayObject must be a child of the caller');
  12613. }
  12614. return this.children[index];
  12615. };
  12616. /**
  12617. * Removes a child from the container.
  12618. *
  12619. * @method PIXI.DisplayObjectContainer#removeChild
  12620. * @param child {DisplayObject} The DisplayObject to remove
  12621. * @return {DisplayObject} The child that was removed.
  12622. */
  12623. PIXI.DisplayObjectContainer.prototype.removeChild = function (child) {
  12624. var index = this.children.indexOf(child);
  12625. if (index === -1)
  12626. {
  12627. return;
  12628. }
  12629. return this.removeChildAt(index);
  12630. };
  12631. /**
  12632. * Removes a child from the specified index position.
  12633. *
  12634. * @method PIXI.DisplayObjectContainer#removeChildAt
  12635. * @param index {Number} The index to get the child from
  12636. * @return {DisplayObject} The child that was removed.
  12637. */
  12638. PIXI.DisplayObjectContainer.prototype.removeChildAt = function (index) {
  12639. var child = this.getChildAt(index);
  12640. if (child)
  12641. {
  12642. child.parent = undefined;
  12643. this.children.splice(index, 1);
  12644. }
  12645. return child;
  12646. };
  12647. /**
  12648. * Removes all children from this container that are within the begin and end indexes.
  12649. *
  12650. * @method PIXI.DisplayObjectContainer#removeChildren
  12651. * @param beginIndex {Number} The beginning position. Default value is 0.
  12652. * @param endIndex {Number} The ending position. Default value is size of the container.
  12653. */
  12654. PIXI.DisplayObjectContainer.prototype.removeChildren = function (beginIndex, endIndex) {
  12655. if (beginIndex === undefined) { beginIndex = 0; }
  12656. if (endIndex === undefined) { endIndex = this.children.length; }
  12657. var range = endIndex - beginIndex;
  12658. if (range > 0 && range <= endIndex)
  12659. {
  12660. var removed = this.children.splice(beginIndex, range);
  12661. for (var i = 0; i < removed.length; i++)
  12662. {
  12663. var child = removed[i];
  12664. child.parent = undefined;
  12665. }
  12666. return removed;
  12667. }
  12668. else if (range === 0 && this.children.length === 0)
  12669. {
  12670. return [];
  12671. }
  12672. else
  12673. {
  12674. throw new Error( 'removeChildren: Range Error, numeric values are outside the acceptable range' );
  12675. }
  12676. };
  12677. /*
  12678. * Updates the transform on all children of this container for rendering
  12679. *
  12680. * @method PIXI.DisplayObjectContainer#updateTransform
  12681. * @private
  12682. */
  12683. PIXI.DisplayObjectContainer.prototype.updateTransform = function () {
  12684. if (!this.visible)
  12685. {
  12686. return;
  12687. }
  12688. this.displayObjectUpdateTransform();
  12689. if (this._cacheAsBitmap)
  12690. {
  12691. return;
  12692. }
  12693. for (var i = 0; i < this.children.length; i++)
  12694. {
  12695. this.children[i].updateTransform();
  12696. }
  12697. };
  12698. // performance increase to avoid using call.. (10x faster)
  12699. PIXI.DisplayObjectContainer.prototype.displayObjectContainerUpdateTransform = PIXI.DisplayObjectContainer.prototype.updateTransform;
  12700. /**
  12701. * Retrieves the global bounds of the displayObjectContainer as a rectangle. The bounds calculation takes all visible children into consideration.
  12702. *
  12703. * @method PIXI.DisplayObjectContainer#getBounds
  12704. * @param {PIXI.DisplayObject|Phaser.Matrix} [targetCoordinateSpace] Returns a rectangle that defines the area of the display object relative to the coordinate system of the targetCoordinateSpace object.
  12705. * @return {Rectangle} The rectangular bounding area
  12706. */
  12707. PIXI.DisplayObjectContainer.prototype.getBounds = function (targetCoordinateSpace) {
  12708. var isTargetCoordinateSpaceDisplayObject = (targetCoordinateSpace && targetCoordinateSpace instanceof PIXI.DisplayObject);
  12709. var isTargetCoordinateSpaceThisOrParent = true;
  12710. if (!isTargetCoordinateSpaceDisplayObject)
  12711. {
  12712. targetCoordinateSpace = this;
  12713. }
  12714. else if (targetCoordinateSpace instanceof PIXI.DisplayObjectContainer)
  12715. {
  12716. isTargetCoordinateSpaceThisOrParent = targetCoordinateSpace.contains(this);
  12717. }
  12718. else
  12719. {
  12720. isTargetCoordinateSpaceThisOrParent = false;
  12721. }
  12722. var i;
  12723. if (isTargetCoordinateSpaceDisplayObject)
  12724. {
  12725. var matrixCache = targetCoordinateSpace.worldTransform;
  12726. targetCoordinateSpace.worldTransform = Phaser.identityMatrix;
  12727. for (i = 0; i < targetCoordinateSpace.children.length; i++)
  12728. {
  12729. targetCoordinateSpace.children[i].updateTransform();
  12730. }
  12731. }
  12732. var minX = Infinity;
  12733. var minY = Infinity;
  12734. var maxX = -Infinity;
  12735. var maxY = -Infinity;
  12736. var childBounds;
  12737. var childMaxX;
  12738. var childMaxY;
  12739. var childVisible = false;
  12740. for (i = 0; i < this.children.length; i++)
  12741. {
  12742. var child = this.children[i];
  12743. if (!child.visible)
  12744. {
  12745. continue;
  12746. }
  12747. childVisible = true;
  12748. childBounds = this.children[i].getBounds();
  12749. minX = (minX < childBounds.x) ? minX : childBounds.x;
  12750. minY = (minY < childBounds.y) ? minY : childBounds.y;
  12751. childMaxX = childBounds.width + childBounds.x;
  12752. childMaxY = childBounds.height + childBounds.y;
  12753. maxX = (maxX > childMaxX) ? maxX : childMaxX;
  12754. maxY = (maxY > childMaxY) ? maxY : childMaxY;
  12755. }
  12756. var bounds = this._bounds;
  12757. if (!childVisible)
  12758. {
  12759. bounds = new PIXI.Rectangle();
  12760. var w0 = bounds.x;
  12761. var w1 = bounds.width + bounds.x;
  12762. var h0 = bounds.y;
  12763. var h1 = bounds.height + bounds.y;
  12764. var worldTransform = this.worldTransform;
  12765. var a = worldTransform.a;
  12766. var b = worldTransform.b;
  12767. var c = worldTransform.c;
  12768. var d = worldTransform.d;
  12769. var tx = worldTransform.tx;
  12770. var ty = worldTransform.ty;
  12771. var x1 = a * w1 + c * h1 + tx;
  12772. var y1 = d * h1 + b * w1 + ty;
  12773. var x2 = a * w0 + c * h1 + tx;
  12774. var y2 = d * h1 + b * w0 + ty;
  12775. var x3 = a * w0 + c * h0 + tx;
  12776. var y3 = d * h0 + b * w0 + ty;
  12777. var x4 = a * w1 + c * h0 + tx;
  12778. var y4 = d * h0 + b * w1 + ty;
  12779. maxX = x1;
  12780. maxY = y1;
  12781. minX = x1;
  12782. minY = y1;
  12783. minX = x2 < minX ? x2 : minX;
  12784. minX = x3 < minX ? x3 : minX;
  12785. minX = x4 < minX ? x4 : minX;
  12786. minY = y2 < minY ? y2 : minY;
  12787. minY = y3 < minY ? y3 : minY;
  12788. minY = y4 < minY ? y4 : minY;
  12789. maxX = x2 > maxX ? x2 : maxX;
  12790. maxX = x3 > maxX ? x3 : maxX;
  12791. maxX = x4 > maxX ? x4 : maxX;
  12792. maxY = y2 > maxY ? y2 : maxY;
  12793. maxY = y3 > maxY ? y3 : maxY;
  12794. maxY = y4 > maxY ? y4 : maxY;
  12795. }
  12796. bounds.x = minX;
  12797. bounds.y = minY;
  12798. bounds.width = maxX - minX;
  12799. bounds.height = maxY - minY;
  12800. if (isTargetCoordinateSpaceDisplayObject)
  12801. {
  12802. targetCoordinateSpace.worldTransform = matrixCache;
  12803. for (i = 0; i < targetCoordinateSpace.children.length; i++)
  12804. {
  12805. targetCoordinateSpace.children[i].updateTransform();
  12806. }
  12807. }
  12808. if (!isTargetCoordinateSpaceThisOrParent)
  12809. {
  12810. var targetCoordinateSpaceBounds = targetCoordinateSpace.getBounds();
  12811. bounds.x -= targetCoordinateSpaceBounds.x;
  12812. bounds.y -= targetCoordinateSpaceBounds.y;
  12813. }
  12814. return bounds;
  12815. };
  12816. /**
  12817. * Retrieves the non-global local bounds of the displayObjectContainer as a rectangle without any transformations. The calculation takes all visible children into consideration.
  12818. *
  12819. * @method PIXI.DisplayObjectContainer#getLocalBounds
  12820. * @return {Rectangle} The rectangular bounding area
  12821. */
  12822. PIXI.DisplayObjectContainer.prototype.getLocalBounds = function () {
  12823. return this.getBounds(this);
  12824. };
  12825. /**
  12826. * Determines whether the specified display object is a child of the DisplayObjectContainer instance or the instance itself.
  12827. *
  12828. * @method PIXI.DisplayObjectContainer#contains
  12829. * @param {DisplayObject} child
  12830. * @returns {boolean}
  12831. */
  12832. PIXI.DisplayObjectContainer.prototype.contains = function (child) {
  12833. if (!child)
  12834. {
  12835. return false;
  12836. }
  12837. else if (child === this)
  12838. {
  12839. return true;
  12840. }
  12841. else
  12842. {
  12843. return this.contains(child.parent);
  12844. }
  12845. };
  12846. /**
  12847. * Renders the object using the WebGL renderer
  12848. *
  12849. * @method PIXI.DisplayObjectContainer#_renderWebGL
  12850. * @param renderSession {RenderSession}
  12851. * @private
  12852. */
  12853. PIXI.DisplayObjectContainer.prototype._renderWebGL = function (renderSession) {
  12854. if (!this.visible || this.alpha <= 0)
  12855. {
  12856. return;
  12857. }
  12858. if (this._cacheAsBitmap)
  12859. {
  12860. this._renderCachedSprite(renderSession);
  12861. return;
  12862. }
  12863. var i;
  12864. if (this._mask || this._filters)
  12865. {
  12866. // push filter first as we need to ensure the stencil buffer is correct for any masking
  12867. if (this._filters)
  12868. {
  12869. renderSession.spriteBatch.flush();
  12870. renderSession.filterManager.pushFilter(this._filterBlock);
  12871. }
  12872. if (this._mask)
  12873. {
  12874. renderSession.spriteBatch.stop();
  12875. renderSession.maskManager.pushMask(this.mask, renderSession);
  12876. renderSession.spriteBatch.start();
  12877. }
  12878. // simple render children!
  12879. for (i = 0; i < this.children.length; i++)
  12880. {
  12881. this.children[i]._renderWebGL(renderSession);
  12882. }
  12883. renderSession.spriteBatch.stop();
  12884. if (this._mask) renderSession.maskManager.popMask(this._mask, renderSession);
  12885. if (this._filters) renderSession.filterManager.popFilter();
  12886. renderSession.spriteBatch.start();
  12887. }
  12888. else
  12889. {
  12890. // simple render children!
  12891. for (i = 0; i < this.children.length; i++)
  12892. {
  12893. this.children[i]._renderWebGL(renderSession);
  12894. }
  12895. }
  12896. };
  12897. /**
  12898. * Renders the object using the Canvas renderer
  12899. *
  12900. * @method PIXI.DisplayObjectContainer#_renderCanvas
  12901. * @param renderSession {RenderSession}
  12902. * @private
  12903. */
  12904. PIXI.DisplayObjectContainer.prototype._renderCanvas = function (renderSession) {
  12905. if (this.visible === false || this.alpha === 0)
  12906. {
  12907. return;
  12908. }
  12909. if (this._cacheAsBitmap)
  12910. {
  12911. this._renderCachedSprite(renderSession);
  12912. return;
  12913. }
  12914. if (this._mask)
  12915. {
  12916. renderSession.maskManager.pushMask(this._mask, renderSession);
  12917. }
  12918. for (var i = 0; i < this.children.length; i++)
  12919. {
  12920. this.children[i]._renderCanvas(renderSession);
  12921. }
  12922. if (this._mask)
  12923. {
  12924. renderSession.maskManager.popMask(renderSession);
  12925. }
  12926. };
  12927. /**
  12928. * The width of the displayObjectContainer, setting this will actually modify the scale to achieve the value set
  12929. *
  12930. * @property width
  12931. * @type Number
  12932. */
  12933. Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'width', {
  12934. get: function() {
  12935. return this.getLocalBounds().width * this.scale.x;
  12936. },
  12937. set: function(value) {
  12938. var width = this.getLocalBounds().width;
  12939. if (width !== 0)
  12940. {
  12941. this.scale.x = value / width;
  12942. }
  12943. else
  12944. {
  12945. this.scale.x = 1;
  12946. }
  12947. this._width = value;
  12948. }
  12949. });
  12950. /**
  12951. * The height of the displayObjectContainer, setting this will actually modify the scale to achieve the value set
  12952. *
  12953. * @property height
  12954. * @type Number
  12955. */
  12956. Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'height', {
  12957. get: function() {
  12958. return this.getLocalBounds().height * this.scale.y;
  12959. },
  12960. set: function(value) {
  12961. var height = this.getLocalBounds().height;
  12962. if (height !== 0)
  12963. {
  12964. this.scale.y = value / height;
  12965. }
  12966. else
  12967. {
  12968. this.scale.y = 1;
  12969. }
  12970. this._height = value;
  12971. }
  12972. });
  12973. /**
  12974. * @author Mat Groves http://matgroves.com/ @Doormat23
  12975. */
  12976. /**
  12977. * The Sprite object is the base for all textured objects that are rendered to the screen
  12978. *
  12979. * @class PIXI.Sprite
  12980. * @extends PIXI.DisplayObjectContainer
  12981. * @constructor
  12982. * @param texture {Texture} The texture for this sprite
  12983. */
  12984. PIXI.Sprite = function (texture) {
  12985. PIXI.DisplayObjectContainer.call(this);
  12986. /**
  12987. * The anchor sets the origin point of the texture.
  12988. * The default (0, 0) is the top left.
  12989. * (0.5, 0.5) is the center.
  12990. * (1, 1) is the bottom right.
  12991. *
  12992. * You can modify the default values in PIXI.Sprite.defaultAnchor.
  12993. *
  12994. * @property anchor
  12995. * @type Point
  12996. */
  12997. this.anchor = new PIXI.Point(PIXI.Sprite.defaultAnchor.x, PIXI.Sprite.defaultAnchor.y);
  12998. /**
  12999. * The texture that the sprite is using
  13000. *
  13001. * @property texture
  13002. * @type Texture
  13003. */
  13004. this.texture = texture || PIXI.Texture.emptyTexture;
  13005. /**
  13006. * The width of the sprite (this is initially set by the texture)
  13007. *
  13008. * @property _width
  13009. * @type Number
  13010. * @private
  13011. */
  13012. this._width = 0;
  13013. /**
  13014. * The height of the sprite (this is initially set by the texture)
  13015. *
  13016. * @property _height
  13017. * @type Number
  13018. * @private
  13019. */
  13020. this._height = 0;
  13021. /**
  13022. * The tint applied to the sprite. This is a hex value. A value of 0xFFFFFF will remove any tint effect.
  13023. *
  13024. * @property tint
  13025. * @type Number
  13026. * @default 0xFFFFFF
  13027. */
  13028. this.tint = 0xFFFFFF;
  13029. /**
  13030. * The tint applied to the sprite. This is a hex value. A value of 0xFFFFFF will remove any tint effect.
  13031. *
  13032. * @property cachedTint
  13033. * @private
  13034. * @type Number
  13035. * @default -1
  13036. */
  13037. this.cachedTint = -1;
  13038. /**
  13039. * A canvas that contains the tinted version of the Sprite (in Canvas mode, WebGL doesn't populate this)
  13040. *
  13041. * @property tintedTexture
  13042. * @type Canvas
  13043. * @default null
  13044. */
  13045. this.tintedTexture = null;
  13046. /**
  13047. * The blend mode to be applied to the sprite. Set to PIXI.blendModes.NORMAL to remove any blend mode.
  13048. *
  13049. * Warning: You cannot have a blend mode and a filter active on the same Sprite. Doing so will render the sprite invisible.
  13050. *
  13051. * @property blendMode
  13052. * @type Number
  13053. * @default PIXI.blendModes.NORMAL;
  13054. */
  13055. this.blendMode = PIXI.blendModes.NORMAL;
  13056. /**
  13057. * The shader that will be used to render this Sprite.
  13058. * Set to null to remove a current shader.
  13059. *
  13060. * @property shader
  13061. * @type Phaser.Filter
  13062. * @default null
  13063. */
  13064. this.shader = null;
  13065. /**
  13066. * Controls if this Sprite is processed by the core Phaser game loops and Group loops (except {@link Phaser.Group#update}).
  13067. *
  13068. * @property exists
  13069. * @type Boolean
  13070. * @default true
  13071. */
  13072. this.exists = true;
  13073. if (this.texture.baseTexture.hasLoaded)
  13074. {
  13075. this.onTextureUpdate();
  13076. }
  13077. this.renderable = true;
  13078. };
  13079. /**
  13080. * @property PIXI.Sprite.defaultAnchor - A Point-like object.
  13081. * @type {{x: number, y: number}}
  13082. * @default
  13083. */
  13084. PIXI.Sprite.defaultAnchor = {x: 0, y: 0};
  13085. // constructor
  13086. PIXI.Sprite.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  13087. PIXI.Sprite.prototype.constructor = PIXI.Sprite;
  13088. /**
  13089. * The width of the sprite, setting this will actually modify the scale to achieve the value set
  13090. *
  13091. * @property width
  13092. * @type Number
  13093. */
  13094. Object.defineProperty(PIXI.Sprite.prototype, 'width', {
  13095. get: function() {
  13096. return this.scale.x * this.texture.frame.width;
  13097. },
  13098. set: function(value) {
  13099. this.scale.x = value / this.texture.frame.width;
  13100. this._width = value;
  13101. }
  13102. });
  13103. /**
  13104. * The height of the sprite, setting this will actually modify the scale to achieve the value set
  13105. *
  13106. * @property height
  13107. * @type Number
  13108. */
  13109. Object.defineProperty(PIXI.Sprite.prototype, 'height', {
  13110. get: function() {
  13111. return this.scale.y * this.texture.frame.height;
  13112. },
  13113. set: function(value) {
  13114. this.scale.y = value / this.texture.frame.height;
  13115. this._height = value;
  13116. }
  13117. });
  13118. /**
  13119. * Sets the texture of the sprite. Be warned that this doesn't remove or destroy the previous
  13120. * texture this Sprite was using.
  13121. *
  13122. * @method PIXI.Sprite#setTexture
  13123. * @param texture {Texture} The PIXI texture that is displayed by the sprite
  13124. * @param [destroy=false] {boolean} Call Texture.destroy on the current texture before replacing it with the new one?
  13125. */
  13126. PIXI.Sprite.prototype.setTexture = function(texture, destroyBase)
  13127. {
  13128. if (destroyBase)
  13129. {
  13130. this.texture.baseTexture.destroy();
  13131. }
  13132. // Over-ridden by loadTexture as needed
  13133. this.texture.baseTexture.skipRender = false;
  13134. this.texture = texture;
  13135. this.texture.valid = true;
  13136. this.cachedTint = -1;
  13137. };
  13138. /**
  13139. * When the texture is updated, this event will fire to update the scale and frame
  13140. *
  13141. * @method PIXI.Sprite#onTextureUpdate
  13142. * @param event
  13143. * @private
  13144. */
  13145. PIXI.Sprite.prototype.onTextureUpdate = function()
  13146. {
  13147. // so if _width is 0 then width was not set..
  13148. if (this._width) this.scale.x = this._width / this.texture.frame.width;
  13149. if (this._height) this.scale.y = this._height / this.texture.frame.height;
  13150. };
  13151. /**
  13152. * Returns the bounds of the Sprite as a rectangle.
  13153. * The bounds calculation takes the worldTransform into account.
  13154. *
  13155. * It is important to note that the transform is not updated when you call this method.
  13156. * So if this Sprite is the child of a Display Object which has had its transform
  13157. * updated since the last render pass, those changes will not yet have been applied
  13158. * to this Sprites worldTransform. If you need to ensure that all parent transforms
  13159. * are factored into this getBounds operation then you should call `updateTransform`
  13160. * on the root most object in this Sprites display list first.
  13161. *
  13162. * @method PIXI.Sprite#getBounds
  13163. * @param matrix {Matrix} the transformation matrix of the sprite
  13164. * @return {Rectangle} the framing rectangle
  13165. */
  13166. PIXI.Sprite.prototype.getBounds = function(matrix)
  13167. {
  13168. var width = this.texture.frame.width;
  13169. var height = this.texture.frame.height;
  13170. var w0 = width * (1-this.anchor.x);
  13171. var w1 = width * -this.anchor.x;
  13172. var h0 = height * (1-this.anchor.y);
  13173. var h1 = height * -this.anchor.y;
  13174. var worldTransform = matrix || this.worldTransform;
  13175. var a = worldTransform.a;
  13176. var b = worldTransform.b;
  13177. var c = worldTransform.c;
  13178. var d = worldTransform.d;
  13179. var tx = worldTransform.tx;
  13180. var ty = worldTransform.ty;
  13181. var maxX = -Infinity;
  13182. var maxY = -Infinity;
  13183. var minX = Infinity;
  13184. var minY = Infinity;
  13185. if (b === 0 && c === 0)
  13186. {
  13187. // scale may be negative!
  13188. if (a < 0)
  13189. {
  13190. a *= -1;
  13191. var temp = w0;
  13192. w0 = -w1;
  13193. w1 = -temp;
  13194. }
  13195. if (d < 0)
  13196. {
  13197. d *= -1;
  13198. var temp = h0;
  13199. h0 = -h1;
  13200. h1 = -temp;
  13201. }
  13202. // this means there is no rotation going on right? RIGHT?
  13203. // if thats the case then we can avoid checking the bound values! yay
  13204. minX = a * w1 + tx;
  13205. maxX = a * w0 + tx;
  13206. minY = d * h1 + ty;
  13207. maxY = d * h0 + ty;
  13208. }
  13209. else
  13210. {
  13211. var x1 = a * w1 + c * h1 + tx;
  13212. var y1 = d * h1 + b * w1 + ty;
  13213. var x2 = a * w0 + c * h1 + tx;
  13214. var y2 = d * h1 + b * w0 + ty;
  13215. var x3 = a * w0 + c * h0 + tx;
  13216. var y3 = d * h0 + b * w0 + ty;
  13217. var x4 = a * w1 + c * h0 + tx;
  13218. var y4 = d * h0 + b * w1 + ty;
  13219. minX = x1 < minX ? x1 : minX;
  13220. minX = x2 < minX ? x2 : minX;
  13221. minX = x3 < minX ? x3 : minX;
  13222. minX = x4 < minX ? x4 : minX;
  13223. minY = y1 < minY ? y1 : minY;
  13224. minY = y2 < minY ? y2 : minY;
  13225. minY = y3 < minY ? y3 : minY;
  13226. minY = y4 < minY ? y4 : minY;
  13227. maxX = x1 > maxX ? x1 : maxX;
  13228. maxX = x2 > maxX ? x2 : maxX;
  13229. maxX = x3 > maxX ? x3 : maxX;
  13230. maxX = x4 > maxX ? x4 : maxX;
  13231. maxY = y1 > maxY ? y1 : maxY;
  13232. maxY = y2 > maxY ? y2 : maxY;
  13233. maxY = y3 > maxY ? y3 : maxY;
  13234. maxY = y4 > maxY ? y4 : maxY;
  13235. }
  13236. var bounds = this._bounds;
  13237. bounds.x = minX;
  13238. bounds.width = maxX - minX;
  13239. bounds.y = minY;
  13240. bounds.height = maxY - minY;
  13241. // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
  13242. this._currentBounds = bounds;
  13243. return bounds;
  13244. };
  13245. /**
  13246. * Retrieves the non-global local bounds of the Sprite as a rectangle. The calculation takes all visible children into consideration.
  13247. *
  13248. * @method PIXI.Sprite#getLocalBounds
  13249. * @return {Rectangle} The rectangular bounding area
  13250. */
  13251. PIXI.Sprite.prototype.getLocalBounds = function () {
  13252. var matrixCache = this.worldTransform;
  13253. this.worldTransform = Phaser.identityMatrix;
  13254. for (var i = 0; i < this.children.length; i++)
  13255. {
  13256. this.children[i].updateTransform();
  13257. }
  13258. var bounds = this.getBounds();
  13259. this.worldTransform = matrixCache;
  13260. for (i = 0; i < this.children.length; i++)
  13261. {
  13262. this.children[i].updateTransform();
  13263. }
  13264. return bounds;
  13265. };
  13266. /**
  13267. * Renders the object using the WebGL renderer
  13268. *
  13269. * @method PIXI.Sprite#_renderWebGL
  13270. * @param renderSession {RenderSession}
  13271. * @param {Matrix} [matrix] - Optional matrix. If provided the Display Object will be rendered using this matrix, otherwise it will use its worldTransform.
  13272. * @private
  13273. */
  13274. PIXI.Sprite.prototype._renderWebGL = function(renderSession, matrix)
  13275. {
  13276. // if the sprite is not visible or the alpha is 0 then no need to render this element
  13277. if (!this.visible || this.alpha <= 0 || !this.renderable) return;
  13278. // They provided an alternative rendering matrix, so use it
  13279. var wt = this.worldTransform;
  13280. if (matrix)
  13281. {
  13282. wt = matrix;
  13283. }
  13284. // A quick check to see if this element has a mask or a filter.
  13285. if (this._mask || this._filters)
  13286. {
  13287. var spriteBatch = renderSession.spriteBatch;
  13288. // push filter first as we need to ensure the stencil buffer is correct for any masking
  13289. if (this._filters)
  13290. {
  13291. spriteBatch.flush();
  13292. renderSession.filterManager.pushFilter(this._filterBlock);
  13293. }
  13294. if (this._mask)
  13295. {
  13296. spriteBatch.stop();
  13297. renderSession.maskManager.pushMask(this.mask, renderSession);
  13298. spriteBatch.start();
  13299. }
  13300. // add this sprite to the batch
  13301. spriteBatch.render(this);
  13302. // now loop through the children and make sure they get rendered
  13303. for (var i = 0; i < this.children.length; i++)
  13304. {
  13305. this.children[i]._renderWebGL(renderSession);
  13306. }
  13307. // time to stop the sprite batch as either a mask element or a filter draw will happen next
  13308. spriteBatch.stop();
  13309. if (this._mask) renderSession.maskManager.popMask(this._mask, renderSession);
  13310. if (this._filters) renderSession.filterManager.popFilter();
  13311. spriteBatch.start();
  13312. }
  13313. else
  13314. {
  13315. renderSession.spriteBatch.render(this);
  13316. // Render children!
  13317. for (var i = 0; i < this.children.length; i++)
  13318. {
  13319. this.children[i]._renderWebGL(renderSession, wt);
  13320. }
  13321. }
  13322. };
  13323. /**
  13324. * Renders the object using the Canvas renderer
  13325. *
  13326. * @method PIXI.Sprite#_renderCanvas
  13327. * @param renderSession {RenderSession}
  13328. * @param {Matrix} [matrix] - Optional matrix. If provided the Display Object will be rendered using this matrix, otherwise it will use its worldTransform.
  13329. * @private
  13330. */
  13331. PIXI.Sprite.prototype._renderCanvas = function(renderSession, matrix)
  13332. {
  13333. // If the sprite is not visible or the alpha is 0 then no need to render this element
  13334. if (!this.visible || this.alpha === 0 || !this.renderable || this.texture.crop.width <= 0 || this.texture.crop.height <= 0)
  13335. {
  13336. return;
  13337. }
  13338. var wt = this.worldTransform;
  13339. // If they provided an alternative rendering matrix then use it
  13340. if (matrix)
  13341. {
  13342. wt = matrix;
  13343. }
  13344. if (this.blendMode !== renderSession.currentBlendMode)
  13345. {
  13346. renderSession.currentBlendMode = this.blendMode;
  13347. renderSession.context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
  13348. }
  13349. if (this._mask)
  13350. {
  13351. renderSession.maskManager.pushMask(this._mask, renderSession);
  13352. }
  13353. // Ignore null sources
  13354. if (!this.texture.valid)
  13355. {
  13356. // Update the children and leave
  13357. for (var i = 0; i < this.children.length; i++)
  13358. {
  13359. this.children[i]._renderCanvas(renderSession);
  13360. }
  13361. if (this._mask)
  13362. {
  13363. renderSession.maskManager.popMask(renderSession);
  13364. }
  13365. return;
  13366. }
  13367. var resolution = this.texture.baseTexture.resolution / renderSession.resolution;
  13368. renderSession.context.globalAlpha = this.worldAlpha;
  13369. // If smoothingEnabled is supported and we need to change the smoothing property for this texture
  13370. if (renderSession.smoothProperty && renderSession.scaleMode !== this.texture.baseTexture.scaleMode)
  13371. {
  13372. renderSession.scaleMode = this.texture.baseTexture.scaleMode;
  13373. renderSession.context[renderSession.smoothProperty] = (renderSession.scaleMode === PIXI.scaleModes.LINEAR);
  13374. }
  13375. // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions
  13376. var dx = (this.texture.trim) ? this.texture.trim.x - this.anchor.x * this.texture.trim.width : this.anchor.x * -this.texture.frame.width;
  13377. var dy = (this.texture.trim) ? this.texture.trim.y - this.anchor.y * this.texture.trim.height : this.anchor.y * -this.texture.frame.height;
  13378. var tx = (wt.tx * renderSession.resolution) + renderSession.shakeX;
  13379. var ty = (wt.ty * renderSession.resolution) + renderSession.shakeY;
  13380. var cw = this.texture.crop.width;
  13381. var ch = this.texture.crop.height;
  13382. if (this.texture.rotated)
  13383. {
  13384. var a = wt.a;
  13385. var b = wt.b;
  13386. var c = wt.c;
  13387. var d = wt.d;
  13388. var e = cw;
  13389. // Offset before rotating
  13390. tx = wt.c * ch + tx;
  13391. ty = wt.d * ch + ty;
  13392. // Rotate matrix by 90 degrees
  13393. // We use precalculated values for sine and cosine of rad(90)
  13394. wt.a = a * 6.123233995736766e-17 + -c;
  13395. wt.b = b * 6.123233995736766e-17 + -d;
  13396. wt.c = a + c * 6.123233995736766e-17;
  13397. wt.d = b + d * 6.123233995736766e-17;
  13398. // Update cropping dimensions.
  13399. cw = ch;
  13400. ch = e;
  13401. }
  13402. // Allow for pixel rounding
  13403. if (renderSession.roundPixels)
  13404. {
  13405. renderSession.context.setTransform(wt.a, wt.b, wt.c, wt.d, tx | 0, ty | 0);
  13406. dx |= 0;
  13407. dy |= 0;
  13408. }
  13409. else
  13410. {
  13411. renderSession.context.setTransform(wt.a, wt.b, wt.c, wt.d, tx, ty);
  13412. }
  13413. dx /= resolution;
  13414. dy /= resolution;
  13415. if (this.tint !== 0xFFFFFF)
  13416. {
  13417. if (this.texture.requiresReTint || this.cachedTint !== this.tint)
  13418. {
  13419. this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint);
  13420. this.cachedTint = this.tint;
  13421. this.texture.requiresReTint = false;
  13422. }
  13423. renderSession.context.drawImage(this.tintedTexture, 0, 0, cw, ch, dx, dy, cw / resolution, ch / resolution);
  13424. }
  13425. else
  13426. {
  13427. var cx = this.texture.crop.x;
  13428. var cy = this.texture.crop.y;
  13429. cw = Math.floor(cw)
  13430. ch = Math.floor(ch)
  13431. renderSession.context.drawImage(this.texture.baseTexture.source, cx, cy, cw, ch, dx, dy, cw / resolution, ch / resolution);
  13432. }
  13433. for (var i = 0; i < this.children.length; i++)
  13434. {
  13435. this.children[i]._renderCanvas(renderSession);
  13436. }
  13437. if (this._mask)
  13438. {
  13439. renderSession.maskManager.popMask(renderSession);
  13440. }
  13441. };
  13442. /**
  13443. * @author Mat Groves http://matgroves.com/ @Doormat23
  13444. */
  13445. /**
  13446. * @method PIXI.initDefaultShaders
  13447. * @static
  13448. * @private
  13449. */
  13450. PIXI.initDefaultShaders = function()
  13451. {
  13452. };
  13453. /**
  13454. * @method PIXI.CompileVertexShader
  13455. * @static
  13456. * @param gl {WebGLContext} the current WebGL drawing context
  13457. * @param shaderSrc {Array}
  13458. * @return {Any}
  13459. */
  13460. PIXI.CompileVertexShader = function(gl, shaderSrc)
  13461. {
  13462. return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER);
  13463. };
  13464. /**
  13465. * @method PIXI.CompileFragmentShader
  13466. * @static
  13467. * @param gl {WebGLContext} the current WebGL drawing context
  13468. * @param shaderSrc {Array}
  13469. * @return {Any}
  13470. */
  13471. PIXI.CompileFragmentShader = function(gl, shaderSrc)
  13472. {
  13473. return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER);
  13474. };
  13475. /**
  13476. * @method PIXI._CompileShader
  13477. * @static
  13478. * @private
  13479. * @param gl {WebGLContext} the current WebGL drawing context
  13480. * @param shaderSrc {Array}
  13481. * @param shaderType {Number}
  13482. * @return {Any}
  13483. */
  13484. PIXI._CompileShader = function(gl, shaderSrc, shaderType)
  13485. {
  13486. var src = shaderSrc;
  13487. if (Array.isArray(shaderSrc))
  13488. {
  13489. src = shaderSrc.join("\n");
  13490. }
  13491. var shader = gl.createShader(shaderType);
  13492. gl.shaderSource(shader, src);
  13493. gl.compileShader(shader);
  13494. if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
  13495. {
  13496. window.console.log(gl.getShaderInfoLog(shader));
  13497. return null;
  13498. }
  13499. return shader;
  13500. };
  13501. /**
  13502. * @method PIXI.compileProgram
  13503. * @static
  13504. * @param gl {WebGLContext} the current WebGL drawing context
  13505. * @param vertexSrc {Array}
  13506. * @param fragmentSrc {Array}
  13507. * @return {Any}
  13508. */
  13509. PIXI.compileProgram = function(gl, vertexSrc, fragmentSrc)
  13510. {
  13511. var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc);
  13512. var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc);
  13513. var shaderProgram = gl.createProgram();
  13514. gl.attachShader(shaderProgram, vertexShader);
  13515. gl.attachShader(shaderProgram, fragmentShader);
  13516. gl.linkProgram(shaderProgram);
  13517. if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
  13518. {
  13519. window.console.log(gl.getProgramInfoLog(shaderProgram));
  13520. window.console.log("Could not initialise shaders");
  13521. }
  13522. return shaderProgram;
  13523. };
  13524. /**
  13525. * @author Mat Groves http://matgroves.com/ @Doormat23
  13526. * @author Richard Davey http://www.photonstorm.com @photonstorm
  13527. */
  13528. /**
  13529. * @class PIXI.PixiShader
  13530. * @constructor
  13531. * @param gl {WebGLContext} the current WebGL drawing context
  13532. */
  13533. PIXI.PixiShader = function(gl)
  13534. {
  13535. /**
  13536. * @property _UID
  13537. * @type Number
  13538. * @private
  13539. */
  13540. this._UID = Phaser._UID++;
  13541. /**
  13542. * @property gl
  13543. * @type WebGLContext
  13544. */
  13545. this.gl = gl;
  13546. /**
  13547. * The WebGL program.
  13548. * @property program
  13549. * @type Any
  13550. */
  13551. this.program = null;
  13552. /**
  13553. * The fragment shader.
  13554. * @property fragmentSrc
  13555. * @type Array
  13556. */
  13557. this.fragmentSrc = null;
  13558. /**
  13559. * A local texture counter for multi-texture shaders.
  13560. * @property textureCount
  13561. * @type Number
  13562. */
  13563. this.textureCount = 0;
  13564. /**
  13565. * A local flag
  13566. * @property firstRun
  13567. * @type Boolean
  13568. * @private
  13569. */
  13570. this.firstRun = true;
  13571. /**
  13572. * A dirty flag
  13573. * @property dirty
  13574. * @type Boolean
  13575. */
  13576. this.dirty = true;
  13577. /**
  13578. * Uniform attributes cache.
  13579. * @property attributes
  13580. * @type Array
  13581. * @private
  13582. */
  13583. this.attributes = [];
  13584. this.init();
  13585. };
  13586. PIXI.PixiShader.prototype.constructor = PIXI.PixiShader;
  13587. PIXI.PixiShader.prototype.initMultitexShader = function () {
  13588. var gl = this.gl;
  13589. this.MAX_TEXTURES = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  13590. var dynamicIfs = '\tif (vTextureIndex == 0.0) { gl_FragColor = texture2D(uSamplerArray[0], vTextureCoord) * vColor;return;}\n'
  13591. for (var index = 1; index < this.MAX_TEXTURES; ++index)
  13592. {
  13593. dynamicIfs += '\tif (vTextureIndex == ' +
  13594. index + '.0) {gl_FragColor = texture2D(uSamplerArray[' +
  13595. index + '], vTextureCoord) * vColor;return;}\n'
  13596. }
  13597. this.fragmentSrc = [
  13598. '// PixiShader Fragment Shader.',
  13599. 'precision lowp float;',
  13600. 'bool isnan( float val ) { return ( val < 0.0 || 0.0 < val || val == 0.0 ) ? false : true; }',
  13601. 'varying vec2 vTextureCoord;',
  13602. 'varying vec4 vColor;',
  13603. 'varying float vTextureIndex;',
  13604. 'uniform sampler2D uSamplerArray[' + this.MAX_TEXTURES + '];',
  13605. // Blue color means that you are trying to bound
  13606. // a texture out of the limits of the hardware.
  13607. 'const vec4 BLUE = vec4(1.0, 0.0, 1.0, 1.0);',
  13608. // If you get a red color means you are out of memory
  13609. // or in some way corrupted the vertex buffer.
  13610. 'const vec4 RED = vec4(1.0, 0.0, 0.0, 1.0);',
  13611. 'void main(void) {',
  13612. dynamicIfs,
  13613. ' if(vTextureIndex >= ' + this.MAX_TEXTURES + '.0) { gl_FragColor = BLUE;return;}',
  13614. ' if(isnan(vTextureIndex)) { gl_FragColor = RED;return;}',
  13615. '}'
  13616. ];
  13617. var program = PIXI.compileProgram(gl, this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc);
  13618. gl.useProgram(program);
  13619. // get and store the uniforms for the shader
  13620. //this.uSampler = gl.getUniformLocation(program, 'uSampler');
  13621. this.uSamplerArray = gl.getUniformLocation(program, 'uSamplerArray[0]');
  13622. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  13623. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  13624. this.dimensions = gl.getUniformLocation(program, 'dimensions');
  13625. // get and store the attributes
  13626. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  13627. this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
  13628. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  13629. this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');
  13630. var indices = [];
  13631. // HACK: we bind an empty texture to avoid WebGL warning spam.
  13632. var tempTexture = gl.createTexture();
  13633. gl.activeTexture(gl.TEXTURE0);
  13634. gl.bindTexture(gl.TEXTURE_2D, tempTexture);
  13635. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, null);
  13636. for (var i = 0; i < this.MAX_TEXTURES; ++i) {
  13637. gl.activeTexture(gl.TEXTURE0 + i);
  13638. gl.bindTexture(gl.TEXTURE_2D, tempTexture);
  13639. indices.push(i);
  13640. }
  13641. gl.activeTexture(gl.TEXTURE0);
  13642. gl.uniform1iv(this.uSamplerArray, indices);
  13643. // Begin worst hack eva //
  13644. // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
  13645. // maybe its something to do with the current state of the gl context.
  13646. // I'm convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
  13647. // If theres any webGL people that know why could happen please help :)
  13648. if(this.colorAttribute === -1)
  13649. {
  13650. this.colorAttribute = 2;
  13651. }
  13652. this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute, this.aTextureIndex];
  13653. // End worst hack eva //
  13654. // add those custom shaders!
  13655. for (var key in this.uniforms)
  13656. {
  13657. // get the uniform locations..
  13658. this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key);
  13659. }
  13660. this.initUniforms();
  13661. this.program = program;
  13662. };
  13663. PIXI.PixiShader.prototype.initDefaultShader = function () {
  13664. if (this.fragmentSrc === null) {
  13665. this.fragmentSrc = [
  13666. 'precision lowp float;',
  13667. 'varying vec2 vTextureCoord;',
  13668. 'varying vec4 vColor;',
  13669. 'varying float vTextureIndex;',
  13670. 'uniform sampler2D uSampler;',
  13671. 'void main(void) {',
  13672. ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
  13673. '}'
  13674. ];
  13675. }
  13676. var gl = this.gl;
  13677. var program = PIXI.compileProgram(gl, this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc);
  13678. gl.useProgram(program);
  13679. // get and store the uniforms for the shader
  13680. this.uSampler = gl.getUniformLocation(program, 'uSampler');
  13681. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  13682. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  13683. this.dimensions = gl.getUniformLocation(program, 'dimensions');
  13684. // get and store the attributes
  13685. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  13686. this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
  13687. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  13688. this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');
  13689. // Begin worst hack eva //
  13690. // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
  13691. // maybe its something to do with the current state of the gl context.
  13692. // I'm convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
  13693. // If theres any webGL people that know why could happen please help :)
  13694. if(this.colorAttribute === -1)
  13695. {
  13696. this.colorAttribute = 2;
  13697. }
  13698. this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute, this.aTextureIndex];
  13699. // End worst hack eva //
  13700. // add those custom shaders!
  13701. for (var key in this.uniforms)
  13702. {
  13703. // get the uniform locations..
  13704. this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key);
  13705. }
  13706. this.initUniforms();
  13707. this.program = program;
  13708. };
  13709. /**
  13710. * Initialises the shader.
  13711. *
  13712. * @method PIXI.PixiShader#init
  13713. */
  13714. PIXI.PixiShader.prototype.init = function(usingFilter)
  13715. {
  13716. if (PIXI._enableMultiTextureToggle && !usingFilter) {
  13717. this.initMultitexShader();
  13718. } else {
  13719. this.initDefaultShader();
  13720. }
  13721. };
  13722. /**
  13723. * Initialises the shader uniform values.
  13724. *
  13725. * Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/
  13726. * http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
  13727. *
  13728. * @method PIXI.PixiShader#initUniforms
  13729. */
  13730. PIXI.PixiShader.prototype.initUniforms = function()
  13731. {
  13732. this.textureCount = 1;
  13733. var gl = this.gl;
  13734. var uniform;
  13735. for (var key in this.uniforms)
  13736. {
  13737. uniform = this.uniforms[key];
  13738. var type = uniform.type;
  13739. if (type === 'sampler2D')
  13740. {
  13741. uniform._init = false;
  13742. if (uniform.value !== null)
  13743. {
  13744. this.initSampler2D(uniform);
  13745. }
  13746. }
  13747. else if (type === 'mat2' || type === 'mat3' || type === 'mat4')
  13748. {
  13749. // These require special handling
  13750. uniform.glMatrix = true;
  13751. uniform.glValueLength = 1;
  13752. if (type === 'mat2')
  13753. {
  13754. uniform.glFunc = gl.uniformMatrix2fv;
  13755. }
  13756. else if (type === 'mat3')
  13757. {
  13758. uniform.glFunc = gl.uniformMatrix3fv;
  13759. }
  13760. else if (type === 'mat4')
  13761. {
  13762. uniform.glFunc = gl.uniformMatrix4fv;
  13763. }
  13764. }
  13765. else
  13766. {
  13767. // GL function reference
  13768. uniform.glFunc = gl['uniform' + type];
  13769. if (type === '2f' || type === '2i')
  13770. {
  13771. uniform.glValueLength = 2;
  13772. }
  13773. else if (type === '3f' || type === '3i')
  13774. {
  13775. uniform.glValueLength = 3;
  13776. }
  13777. else if (type === '4f' || type === '4i')
  13778. {
  13779. uniform.glValueLength = 4;
  13780. }
  13781. else
  13782. {
  13783. uniform.glValueLength = 1;
  13784. }
  13785. }
  13786. }
  13787. };
  13788. /**
  13789. * Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture has loaded)
  13790. *
  13791. * @method PIXI.PixiShader#initSampler2D
  13792. */
  13793. PIXI.PixiShader.prototype.initSampler2D = function(uniform)
  13794. {
  13795. if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded)
  13796. {
  13797. return;
  13798. }
  13799. var gl = this.gl;
  13800. // No need to do string manipulation for this.
  13801. gl.activeTexture(gl.TEXTURE0 + this.textureCount);
  13802. gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id]);
  13803. // Extended texture data
  13804. if (uniform.textureData)
  13805. {
  13806. var data = uniform.textureData;
  13807. // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D);
  13808. // GLTextureLinear = mag/min linear, wrap clamp
  13809. // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat
  13810. // GLTextureNearest = mag/min nearest, wrap clamp
  13811. // AudioTexture = whatever + luminance + width 512, height 2, border 0
  13812. // KeyTexture = whatever + luminance + width 256, height 2, border 0
  13813. // magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST
  13814. // wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT
  13815. var magFilter = (data.magFilter) ? data.magFilter : gl.LINEAR;
  13816. var minFilter = (data.minFilter) ? data.minFilter : gl.LINEAR;
  13817. var wrapS = (data.wrapS) ? data.wrapS : gl.CLAMP_TO_EDGE;
  13818. var wrapT = (data.wrapT) ? data.wrapT : gl.CLAMP_TO_EDGE;
  13819. var format = (data.luminance) ? gl.LUMINANCE : gl.RGBA;
  13820. if (data.repeat)
  13821. {
  13822. wrapS = gl.REPEAT;
  13823. wrapT = gl.REPEAT;
  13824. }
  13825. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, !!data.flipY);
  13826. if (data.width)
  13827. {
  13828. var width = (data.width) ? data.width : 512;
  13829. var height = (data.height) ? data.height : 2;
  13830. var border = (data.border) ? data.border : 0;
  13831. // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
  13832. gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null);
  13833. }
  13834. else
  13835. {
  13836. // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels);
  13837. gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, uniform.value.baseTexture.source);
  13838. }
  13839. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
  13840. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
  13841. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
  13842. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
  13843. }
  13844. gl.uniform1i(uniform.uniformLocation, this.textureCount);
  13845. uniform._init = true;
  13846. this.textureCount++;
  13847. };
  13848. /**
  13849. * Updates the shader uniform values.
  13850. *
  13851. * @method PIXI.PixiShader#syncUniforms
  13852. */
  13853. PIXI.PixiShader.prototype.syncUniforms = function()
  13854. {
  13855. this.textureCount = 1;
  13856. var uniform;
  13857. var gl = this.gl;
  13858. // This would probably be faster in an array and it would guarantee key order
  13859. for (var key in this.uniforms)
  13860. {
  13861. uniform = this.uniforms[key];
  13862. if (uniform.glValueLength === 1)
  13863. {
  13864. if (uniform.glMatrix === true)
  13865. {
  13866. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.transpose, uniform.value);
  13867. }
  13868. else
  13869. {
  13870. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value);
  13871. }
  13872. }
  13873. else if (uniform.glValueLength === 2)
  13874. {
  13875. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y);
  13876. }
  13877. else if (uniform.glValueLength === 3)
  13878. {
  13879. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z);
  13880. }
  13881. else if (uniform.glValueLength === 4)
  13882. {
  13883. uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w);
  13884. }
  13885. else if (uniform.type === 'sampler2D')
  13886. {
  13887. if (uniform._init)
  13888. {
  13889. gl.activeTexture(gl['TEXTURE' + this.textureCount]);
  13890. if(uniform.value.baseTexture._dirty[gl.id])
  13891. {
  13892. PIXI.instances[gl.id].updateTexture(uniform.value.baseTexture);
  13893. }
  13894. else
  13895. {
  13896. // bind the current texture
  13897. gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id]);
  13898. }
  13899. // gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture( uniform.value.baseTexture, gl));
  13900. gl.uniform1i(uniform.uniformLocation, this.textureCount);
  13901. this.textureCount++;
  13902. }
  13903. else
  13904. {
  13905. this.initSampler2D(uniform);
  13906. }
  13907. }
  13908. }
  13909. };
  13910. /**
  13911. * Destroys the shader.
  13912. *
  13913. * @method PIXI.PixiShader#destroy
  13914. */
  13915. PIXI.PixiShader.prototype.destroy = function()
  13916. {
  13917. this.gl.deleteProgram( this.program );
  13918. this.uniforms = null;
  13919. this.gl = null;
  13920. this.attributes = null;
  13921. };
  13922. /**
  13923. * The Default Vertex shader source.
  13924. *
  13925. * @property defaultVertexSrc
  13926. * @type String
  13927. */
  13928. PIXI.PixiShader.defaultVertexSrc = [
  13929. '// PixiShader Vertex Shader',
  13930. '// With multi-texture rendering',
  13931. 'attribute vec2 aVertexPosition;',
  13932. 'attribute vec2 aTextureCoord;',
  13933. 'attribute vec4 aColor;',
  13934. 'attribute float aTextureIndex;',
  13935. 'uniform vec2 projectionVector;',
  13936. 'uniform vec2 offsetVector;',
  13937. 'varying vec2 vTextureCoord;',
  13938. 'varying vec4 vColor;',
  13939. 'varying float vTextureIndex;',
  13940. 'const vec2 center = vec2(-1.0, 1.0);',
  13941. 'void main(void) {',
  13942. ' if (aTextureIndex > 0.0) gl_Position = vec4(0.0);',
  13943. ' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);',
  13944. ' vTextureCoord = aTextureCoord;',
  13945. ' vColor = vec4(aColor.rgb * aColor.a, aColor.a);',
  13946. ' vTextureIndex = aTextureIndex;',
  13947. '}'
  13948. ];
  13949. /**
  13950. * @author Mat Groves http://matgroves.com/ @Doormat23
  13951. */
  13952. /**
  13953. * @class PIXI.PixiFastShader
  13954. * @constructor
  13955. * @param gl {WebGLContext} the current WebGL drawing context
  13956. */
  13957. PIXI.PixiFastShader = function (gl) {
  13958. /**
  13959. * @property _UID
  13960. * @type Number
  13961. * @private
  13962. */
  13963. this._UID = Phaser._UID++;
  13964. /**
  13965. * @property gl
  13966. * @type WebGLContext
  13967. */
  13968. this.gl = gl;
  13969. /**
  13970. * The WebGL program.
  13971. * @property program
  13972. * @type Any
  13973. */
  13974. this.program = null;
  13975. if (PIXI._enableMultiTextureToggle) {
  13976. var gl = this.gl;
  13977. this.MAX_TEXTURES = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  13978. var dynamicIfs = '\tif (vTextureIndex == 0.0) { gl_FragColor = texture2D(uSamplerArray[0], vTextureCoord) * vColor;return;}\n'
  13979. for (var index = 1; index < this.MAX_TEXTURES; ++index)
  13980. {
  13981. dynamicIfs += '\tif (vTextureIndex == ' +
  13982. index + '.0) { gl_FragColor = texture2D(uSamplerArray[' +
  13983. index + '], vTextureCoord) * vColor;return;}\n'
  13984. }
  13985. /**
  13986. * The fragment shader.
  13987. * @property fragmentSrc
  13988. * @type Array
  13989. */
  13990. this.fragmentSrc = [
  13991. '// PixiFastShader Fragment Shader.',
  13992. 'precision lowp float;',
  13993. 'bool isnan( float val ) { return ( val < 0.0 || 0.0 < val || val == 0.0 ) ? false : true; }',
  13994. 'varying vec2 vTextureCoord;',
  13995. 'varying float vColor;',
  13996. 'varying float vTextureIndex;',
  13997. 'uniform sampler2D uSamplerArray[' + this.MAX_TEXTURES + '];',
  13998. // Blue color means that you are trying to bound
  13999. // a texture out of the limits of the hardware.
  14000. 'const vec4 BLUE = vec4(1.0, 0.0, 1.0, 1.0);',
  14001. // If you get a red color means you are out of memory
  14002. // or in some way corrupted the vertex buffer.
  14003. 'const vec4 RED = vec4(1.0, 0.0, 0.0, 1.0);',
  14004. 'void main(void) {',
  14005. dynamicIfs,
  14006. ' if(vTextureIndex >= ' + this.MAX_TEXTURES + '.0) { gl_FragColor = BLUE;return;}',
  14007. ' if(isnan(vTextureIndex)) {gl_FragColor = RED;return;}',
  14008. '}'
  14009. ];
  14010. } else {
  14011. this.fragmentSrc = [
  14012. '// PixiFastShader Fragment Shader.',
  14013. 'precision lowp float;',
  14014. 'varying vec2 vTextureCoord;',
  14015. 'varying float vColor;',
  14016. 'varying float vTextureIndex;',
  14017. 'uniform sampler2D uSampler;',
  14018. 'void main(void) {',
  14019. ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;',
  14020. '}'
  14021. ];
  14022. }
  14023. /**
  14024. * The vertex shader.
  14025. * @property vertexSrc
  14026. * @type Array
  14027. */
  14028. this.vertexSrc = [
  14029. '// PixiFastShader Vertex Shader.',
  14030. 'attribute vec2 aVertexPosition;',
  14031. 'attribute vec2 aPositionCoord;',
  14032. 'attribute vec2 aScale;',
  14033. 'attribute float aRotation;',
  14034. 'attribute vec2 aTextureCoord;',
  14035. 'attribute float aColor;',
  14036. 'attribute float aTextureIndex;',
  14037. 'uniform vec2 projectionVector;',
  14038. 'uniform vec2 offsetVector;',
  14039. 'uniform mat3 uMatrix;',
  14040. 'varying vec2 vTextureCoord;',
  14041. 'varying float vColor;',
  14042. 'varying float vTextureIndex;',
  14043. 'const vec2 center = vec2(-1.0, 1.0);',
  14044. 'void main(void) {',
  14045. ' vec2 v;',
  14046. ' vec2 sv = aVertexPosition * aScale;',
  14047. ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);',
  14048. ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);',
  14049. ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;',
  14050. ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);',
  14051. ' vTextureCoord = aTextureCoord;',
  14052. ' vTextureIndex = aTextureIndex;',
  14053. // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;',
  14054. ' vColor = aColor;',
  14055. '}'
  14056. ];
  14057. /**
  14058. * A local texture counter for multi-texture shaders.
  14059. * @property textureCount
  14060. * @type Number
  14061. */
  14062. this.textureCount = 0;
  14063. this.init();
  14064. };
  14065. PIXI.PixiFastShader.prototype.constructor = PIXI.PixiFastShader;
  14066. /**
  14067. * Initialises the shader.
  14068. *
  14069. * @method PIXI.PixiFastShader#init
  14070. */
  14071. PIXI.PixiFastShader.prototype.init = function () {
  14072. var gl = this.gl;
  14073. var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
  14074. gl.useProgram(program);
  14075. // get and store the uniforms for the shader
  14076. this.uSampler = PIXI._enableMultiTextureToggle ?
  14077. gl.getUniformLocation(program, 'uSamplerArray[0]') :
  14078. gl.getUniformLocation(program, 'uSampler');
  14079. if (PIXI._enableMultiTextureToggle) {
  14080. var indices = [];
  14081. // HACK: we bind an empty texture to avoid WebGL warning spam.
  14082. var tempTexture = gl.createTexture();
  14083. gl.activeTexture(gl.TEXTURE0);
  14084. gl.bindTexture(gl.TEXTURE_2D, tempTexture);
  14085. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, null);
  14086. for (var i = 0; i < this.MAX_TEXTURES; ++i) {
  14087. gl.activeTexture(gl.TEXTURE0 + i);
  14088. gl.bindTexture(gl.TEXTURE_2D, tempTexture);
  14089. indices.push(i);
  14090. }
  14091. gl.activeTexture(gl.TEXTURE0);
  14092. gl.uniform1iv(this.uSampler, indices);
  14093. }
  14094. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  14095. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  14096. this.dimensions = gl.getUniformLocation(program, 'dimensions');
  14097. this.uMatrix = gl.getUniformLocation(program, 'uMatrix');
  14098. // get and store the attributes
  14099. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  14100. this.aPositionCoord = gl.getAttribLocation(program, 'aPositionCoord');
  14101. this.aScale = gl.getAttribLocation(program, 'aScale');
  14102. this.aRotation = gl.getAttribLocation(program, 'aRotation');
  14103. this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
  14104. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  14105. this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');
  14106. // Begin worst hack eva //
  14107. // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
  14108. // maybe its somthing to do with the current state of the gl context.
  14109. // Im convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
  14110. // If theres any webGL people that know why could happen please help :)
  14111. if (this.colorAttribute === -1) {
  14112. this.colorAttribute = 2;
  14113. }
  14114. this.attributes = [
  14115. this.aVertexPosition,
  14116. this.aPositionCoord,
  14117. this.aScale,
  14118. this.aRotation,
  14119. this.aTextureCoord,
  14120. this.colorAttribute,
  14121. this.aTextureIndex
  14122. ];
  14123. // End worst hack eva //
  14124. this.program = program;
  14125. };
  14126. /**
  14127. * Destroys the shader.
  14128. *
  14129. * @method PIXI.PixiFastShader#destroy
  14130. */
  14131. PIXI.PixiFastShader.prototype.destroy = function () {
  14132. this.gl.deleteProgram(this.program);
  14133. this.uniforms = null;
  14134. this.gl = null;
  14135. this.attributes = null;
  14136. };
  14137. /**
  14138. * @author Mat Groves http://matgroves.com/ @Doormat23
  14139. */
  14140. /**
  14141. * @class PIXI.StripShader
  14142. * @constructor
  14143. * @param gl {WebGLContext} the current WebGL drawing context
  14144. */
  14145. PIXI.StripShader = function(gl)
  14146. {
  14147. /**
  14148. * @property _UID
  14149. * @type Number
  14150. * @private
  14151. */
  14152. this._UID = Phaser._UID++;
  14153. /**
  14154. * @property gl
  14155. * @type WebGLContext
  14156. */
  14157. this.gl = gl;
  14158. /**
  14159. * The WebGL program.
  14160. * @property program
  14161. * @type Any
  14162. */
  14163. this.program = null;
  14164. if (PIXI._enableMultiTextureToggle) {
  14165. var gl = this.gl;
  14166. this.MAX_TEXTURES = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  14167. var dynamicIfs = '\tif (vTextureIndex == 0.0) { gl_FragColor = texture2D(uSamplerArray[0], vTextureCoord);return;}\n'
  14168. for (var index = 1; index < this.MAX_TEXTURES; ++index)
  14169. {
  14170. dynamicIfs += '\tif (vTextureIndex == ' +
  14171. index + '.0) { gl_FragColor = texture2D(uSamplerArray[' +
  14172. index + '], vTextureCoord) ;return;}\n'
  14173. }
  14174. /**
  14175. * The fragment shader.
  14176. * @property fragmentSrc
  14177. * @type Array
  14178. */
  14179. this.fragmentSrc = [
  14180. '//StripShader Fragment Shader.',
  14181. 'precision mediump float;',
  14182. 'bool isnan( float val ) { return ( val < 0.0 || 0.0 < val || val == 0.0 ) ? false : true; }',
  14183. 'varying vec2 vTextureCoord;',
  14184. 'varying float vTextureIndex;',
  14185. // 'varying float vColor;',
  14186. 'uniform float alpha;',
  14187. 'uniform sampler2D uSamplerArray[' + this.MAX_TEXTURES + '];',
  14188. // Blue color means that you are trying to bound
  14189. // a texture out of the limits of the hardware.
  14190. 'const vec4 BLUE = vec4(1.0, 0.0, 1.0, 1.0);',
  14191. // If you get a red color means you are out of memory
  14192. // or in some way corrupted the vertex buffer.
  14193. 'const vec4 RED = vec4(1.0, 0.0, 0.0, 1.0);',
  14194. 'void main(void) {',
  14195. dynamicIfs,
  14196. ' if(vTextureIndex >= ' + this.MAX_TEXTURES + '.0) { gl_FragColor = BLUE;return;}',
  14197. ' if(isnan(vTextureIndex)) {gl_FragColor = RED;return;}',
  14198. '}'
  14199. ];
  14200. } else {
  14201. /**
  14202. * The fragment shader.
  14203. * @property fragmentSrc
  14204. * @type Array
  14205. */
  14206. this.fragmentSrc = [
  14207. '//StripShader Fragment Shader.',
  14208. 'precision mediump float;',
  14209. 'varying vec2 vTextureCoord;',
  14210. 'varying float vTextureIndex;',
  14211. // 'varying float vColor;',
  14212. 'uniform float alpha;',
  14213. 'uniform sampler2D uSampler;',
  14214. 'void main(void) {',
  14215. ' gl_FragColor = texture2D(uSampler, vTextureCoord);',
  14216. '}'
  14217. ];
  14218. }
  14219. /**
  14220. * The vertex shader.
  14221. * @property vertexSrc
  14222. * @type Array
  14223. */
  14224. this.vertexSrc = [
  14225. '//StripShader Vertex Shader.',
  14226. 'attribute vec2 aVertexPosition;',
  14227. 'attribute vec2 aTextureCoord;',
  14228. 'attribute float aTextureIndex;',
  14229. 'uniform mat3 translationMatrix;',
  14230. 'uniform vec2 projectionVector;',
  14231. 'uniform vec2 offsetVector;',
  14232. // 'uniform float alpha;',
  14233. // 'uniform vec3 tint;',
  14234. 'varying vec2 vTextureCoord;',
  14235. 'varying float vTextureIndex;',
  14236. // 'varying vec4 vColor;',
  14237. 'void main(void) {',
  14238. ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);',
  14239. ' v -= offsetVector.xyx;',
  14240. ' gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);',
  14241. ' vTextureCoord = aTextureCoord;',
  14242. ' vTextureIndex = aTextureIndex;',
  14243. // ' vColor = aColor * vec4(tint * alpha, alpha);',
  14244. '}'
  14245. ];
  14246. this.init();
  14247. };
  14248. PIXI.StripShader.prototype.constructor = PIXI.StripShader;
  14249. /**
  14250. * Initialises the shader.
  14251. *
  14252. * @method PIXI.StripShader#init
  14253. */
  14254. PIXI.StripShader.prototype.init = function()
  14255. {
  14256. var gl = this.gl;
  14257. var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
  14258. gl.useProgram(program);
  14259. // get and store the uniforms for the shader
  14260. this.uSampler = PIXI._enableMultiTextureToggle ?
  14261. gl.getUniformLocation(program, 'uSamplerArray[0]') :
  14262. gl.getUniformLocation(program, 'uSampler');
  14263. if (PIXI._enableMultiTextureToggle) {
  14264. var indices = [];
  14265. // HACK: we bind an empty texture to avoid WebGL warning spam.
  14266. var tempTexture = gl.createTexture();
  14267. gl.activeTexture(gl.TEXTURE0);
  14268. gl.bindTexture(gl.TEXTURE_2D, tempTexture);
  14269. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, null);
  14270. for (var i = 0; i < this.MAX_TEXTURES; ++i) {
  14271. gl.activeTexture(gl.TEXTURE0 + i);
  14272. gl.bindTexture(gl.TEXTURE_2D, tempTexture);
  14273. indices.push(i);
  14274. }
  14275. gl.activeTexture(gl.TEXTURE0);
  14276. gl.uniform1iv(this.uSampler, indices);
  14277. }
  14278. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  14279. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  14280. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  14281. this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');
  14282. //this.dimensions = gl.getUniformLocation(this.program, 'dimensions');
  14283. // get and store the attributes
  14284. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  14285. this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
  14286. this.attributes = [this.aVertexPosition, this.aTextureCoord, this.aTextureIndex];
  14287. this.translationMatrix = gl.getUniformLocation(program, 'translationMatrix');
  14288. this.alpha = gl.getUniformLocation(program, 'alpha');
  14289. this.program = program;
  14290. };
  14291. /**
  14292. * Destroys the shader.
  14293. *
  14294. * @method PIXI.StripShader#destroy
  14295. */
  14296. PIXI.StripShader.prototype.destroy = function()
  14297. {
  14298. this.gl.deleteProgram( this.program );
  14299. this.uniforms = null;
  14300. this.gl = null;
  14301. this.attribute = null;
  14302. };
  14303. /**
  14304. * @author Mat Groves http://matgroves.com/ @Doormat23
  14305. */
  14306. /**
  14307. * @class PIXI.PrimitiveShader
  14308. * @constructor
  14309. * @param gl {WebGLContext} the current WebGL drawing context
  14310. */
  14311. PIXI.PrimitiveShader = function(gl)
  14312. {
  14313. /**
  14314. * @property _UID
  14315. * @type Number
  14316. * @private
  14317. */
  14318. this._UID = Phaser._UID++;
  14319. /**
  14320. * @property gl
  14321. * @type WebGLContext
  14322. */
  14323. this.gl = gl;
  14324. /**
  14325. * The WebGL program.
  14326. * @property program
  14327. * @type Any
  14328. */
  14329. this.program = null;
  14330. /**
  14331. * The fragment shader.
  14332. * @property fragmentSrc
  14333. * @type Array
  14334. */
  14335. this.fragmentSrc = [
  14336. 'precision mediump float;',
  14337. 'varying vec4 vColor;',
  14338. 'void main(void) {',
  14339. ' gl_FragColor = vColor;',
  14340. '}'
  14341. ];
  14342. /**
  14343. * The vertex shader.
  14344. * @property vertexSrc
  14345. * @type Array
  14346. */
  14347. this.vertexSrc = [
  14348. 'attribute vec2 aVertexPosition;',
  14349. 'attribute vec4 aColor;',
  14350. 'uniform mat3 translationMatrix;',
  14351. 'uniform vec2 projectionVector;',
  14352. 'uniform vec2 offsetVector;',
  14353. 'uniform float alpha;',
  14354. 'uniform float flipY;',
  14355. 'uniform vec3 tint;',
  14356. 'varying vec4 vColor;',
  14357. 'void main(void) {',
  14358. ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);',
  14359. ' v -= offsetVector.xyx;',
  14360. ' gl_Position = vec4( v.x / projectionVector.x -1.0, (v.y / projectionVector.y * -flipY) + flipY , 0.0, 1.0);',
  14361. ' vColor = aColor * vec4(tint * alpha, alpha);',
  14362. '}'
  14363. ];
  14364. this.init();
  14365. };
  14366. PIXI.PrimitiveShader.prototype.constructor = PIXI.PrimitiveShader;
  14367. /**
  14368. * Initialises the shader.
  14369. *
  14370. * @method PIXI.PrimitiveShader#init
  14371. */
  14372. PIXI.PrimitiveShader.prototype.init = function()
  14373. {
  14374. var gl = this.gl;
  14375. var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
  14376. gl.useProgram(program);
  14377. // get and store the uniforms for the shader
  14378. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  14379. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  14380. this.tintColor = gl.getUniformLocation(program, 'tint');
  14381. this.flipY = gl.getUniformLocation(program, 'flipY');
  14382. // get and store the attributes
  14383. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  14384. this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  14385. this.attributes = [this.aVertexPosition, this.colorAttribute];
  14386. this.translationMatrix = gl.getUniformLocation(program, 'translationMatrix');
  14387. this.alpha = gl.getUniformLocation(program, 'alpha');
  14388. this.program = program;
  14389. };
  14390. /**
  14391. * Destroys the shader.
  14392. *
  14393. * @method PIXI.PrimitiveShader#destroy
  14394. */
  14395. PIXI.PrimitiveShader.prototype.destroy = function()
  14396. {
  14397. this.gl.deleteProgram( this.program );
  14398. this.uniforms = null;
  14399. this.gl = null;
  14400. this.attributes = null;
  14401. };
  14402. /**
  14403. * @author Mat Groves http://matgroves.com/ @Doormat23
  14404. */
  14405. /**
  14406. * @class PIXI.ComplexPrimitiveShader
  14407. * @constructor
  14408. * @param gl {WebGLContext} the current WebGL drawing context
  14409. */
  14410. PIXI.ComplexPrimitiveShader = function(gl)
  14411. {
  14412. /**
  14413. * @property _UID
  14414. * @type Number
  14415. * @private
  14416. */
  14417. this._UID = Phaser._UID++;
  14418. /**
  14419. * @property gl
  14420. * @type WebGLContext
  14421. */
  14422. this.gl = gl;
  14423. /**
  14424. * The WebGL program.
  14425. * @property program
  14426. * @type Any
  14427. */
  14428. this.program = null;
  14429. /**
  14430. * The fragment shader.
  14431. * @property fragmentSrc
  14432. * @type Array
  14433. */
  14434. this.fragmentSrc = [
  14435. 'precision mediump float;',
  14436. 'varying vec4 vColor;',
  14437. 'void main(void) {',
  14438. ' gl_FragColor = vColor;',
  14439. '}'
  14440. ];
  14441. /**
  14442. * The vertex shader.
  14443. * @property vertexSrc
  14444. * @type Array
  14445. */
  14446. this.vertexSrc = [
  14447. 'attribute vec2 aVertexPosition;',
  14448. //'attribute vec4 aColor;',
  14449. 'uniform mat3 translationMatrix;',
  14450. 'uniform vec2 projectionVector;',
  14451. 'uniform vec2 offsetVector;',
  14452. 'uniform vec3 tint;',
  14453. 'uniform float alpha;',
  14454. 'uniform vec3 color;',
  14455. 'uniform float flipY;',
  14456. 'varying vec4 vColor;',
  14457. 'void main(void) {',
  14458. ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);',
  14459. ' v -= offsetVector.xyx;',
  14460. ' gl_Position = vec4( v.x / projectionVector.x -1.0, (v.y / projectionVector.y * -flipY) + flipY , 0.0, 1.0);',
  14461. ' vColor = vec4(color * alpha * tint, alpha);',//" * vec4(tint * alpha, alpha);',
  14462. '}'
  14463. ];
  14464. this.init();
  14465. };
  14466. PIXI.ComplexPrimitiveShader.prototype.constructor = PIXI.ComplexPrimitiveShader;
  14467. /**
  14468. * Initialises the shader.
  14469. *
  14470. * @method PIXI.ComplexPrimitiveShader#init
  14471. */
  14472. PIXI.ComplexPrimitiveShader.prototype.init = function()
  14473. {
  14474. var gl = this.gl;
  14475. var program = PIXI.compileProgram(gl, this.vertexSrc, this.fragmentSrc);
  14476. gl.useProgram(program);
  14477. // get and store the uniforms for the shader
  14478. this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
  14479. this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
  14480. this.tintColor = gl.getUniformLocation(program, 'tint');
  14481. this.color = gl.getUniformLocation(program, 'color');
  14482. this.flipY = gl.getUniformLocation(program, 'flipY');
  14483. // get and store the attributes
  14484. this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  14485. // this.colorAttribute = gl.getAttribLocation(program, 'aColor');
  14486. this.attributes = [this.aVertexPosition, this.colorAttribute];
  14487. this.translationMatrix = gl.getUniformLocation(program, 'translationMatrix');
  14488. this.alpha = gl.getUniformLocation(program, 'alpha');
  14489. this.program = program;
  14490. };
  14491. /**
  14492. * Destroys the shader.
  14493. *
  14494. * @method PIXI.ComplexPrimitiveShader#destroy
  14495. */
  14496. PIXI.ComplexPrimitiveShader.prototype.destroy = function()
  14497. {
  14498. this.gl.deleteProgram( this.program );
  14499. this.uniforms = null;
  14500. this.gl = null;
  14501. this.attribute = null;
  14502. };
  14503. /**
  14504. * @author Mat Groves http://matgroves.com/ @Doormat23
  14505. */
  14506. PIXI.glContexts = []; // this is where we store the webGL contexts for easy access.
  14507. PIXI.instances = [];
  14508. PIXI._enableMultiTextureToggle = false;
  14509. /**
  14510. * The WebGLRenderer draws the stage and all its content onto a webGL enabled canvas. This renderer
  14511. * should be used for browsers that support webGL. This Render works by automatically managing webGLBatchs.
  14512. * So no need for Sprite Batches or Sprite Clouds.
  14513. * Don't forget to add the view to your DOM or you will not see anything :)
  14514. *
  14515. * @class PIXI.WebGLRenderer
  14516. * @constructor
  14517. * @param game {Phaser.Game} A reference to the Phaser Game instance
  14518. */
  14519. PIXI.WebGLRenderer = function(game) {
  14520. /**
  14521. * @property {Phaser.Game} game - A reference to the Phaser Game instance.
  14522. */
  14523. this.game = game;
  14524. if (!PIXI.defaultRenderer)
  14525. {
  14526. PIXI.defaultRenderer = this;
  14527. }
  14528. this.extensions = {};
  14529. /**
  14530. * @property type
  14531. * @type Number
  14532. */
  14533. this.type = Phaser.WEBGL;
  14534. /**
  14535. * The resolution of the renderer
  14536. *
  14537. * @property resolution
  14538. * @type Number
  14539. * @default 1
  14540. */
  14541. this.resolution = game.resolution;
  14542. /**
  14543. * Whether the render view is transparent
  14544. *
  14545. * @property transparent
  14546. * @type Boolean
  14547. */
  14548. this.transparent = game.transparent;
  14549. /**
  14550. * Whether the render view should be resized automatically
  14551. *
  14552. * @property autoResize
  14553. * @type Boolean
  14554. */
  14555. this.autoResize = false;
  14556. /**
  14557. * The value of the preserveDrawingBuffer flag affects whether or not the contents of the stencil buffer is retained after rendering.
  14558. *
  14559. * @property preserveDrawingBuffer
  14560. * @type Boolean
  14561. */
  14562. this.preserveDrawingBuffer = game.preserveDrawingBuffer;
  14563. /**
  14564. * This sets if the WebGLRenderer will clear the context texture or not before the new render pass. If true:
  14565. * If the Stage is NOT transparent, Pixi will clear to alpha (0, 0, 0, 0).
  14566. * If the Stage is transparent, Pixi will clear to the target Stage's background color.
  14567. * Disable this by setting this to false. For example: if your game has a canvas filling background image, you often don't need this set.
  14568. *
  14569. * @property clearBeforeRender
  14570. * @type Boolean
  14571. * @default
  14572. */
  14573. this.clearBeforeRender = game.clearBeforeRender;
  14574. /**
  14575. * The width of the canvas view
  14576. *
  14577. * @property width
  14578. * @type Number
  14579. */
  14580. this.width = game.width;
  14581. /**
  14582. * The height of the canvas view
  14583. *
  14584. * @property height
  14585. * @type Number
  14586. */
  14587. this.height = game.height;
  14588. /**
  14589. * The canvas element that everything is drawn to
  14590. *
  14591. * @property view
  14592. * @type HTMLCanvasElement
  14593. */
  14594. this.view = game.canvas;
  14595. /**
  14596. * @property _contextOptions
  14597. * @type Object
  14598. * @private
  14599. */
  14600. this._contextOptions = {
  14601. alpha: this.transparent,
  14602. antialias: game.antialias,
  14603. premultipliedAlpha: this.transparent && this.transparent !== 'notMultiplied',
  14604. stencil: true,
  14605. preserveDrawingBuffer: this.preserveDrawingBuffer
  14606. };
  14607. /**
  14608. * @property projection
  14609. * @type Point
  14610. */
  14611. this.projection = new PIXI.Point();
  14612. /**
  14613. * @property offset
  14614. * @type Point
  14615. */
  14616. this.offset = new PIXI.Point();
  14617. // time to create the render managers! each one focuses on managing a state in webGL
  14618. /**
  14619. * Deals with managing the shader programs and their attribs
  14620. * @property shaderManager
  14621. * @type WebGLShaderManager
  14622. */
  14623. this.shaderManager = new PIXI.WebGLShaderManager();
  14624. /**
  14625. * Manages the rendering of sprites
  14626. * @property spriteBatch
  14627. * @type WebGLSpriteBatch
  14628. */
  14629. this.spriteBatch = new PIXI.WebGLSpriteBatch(game);
  14630. /**
  14631. * Manages the masks using the stencil buffer
  14632. * @property maskManager
  14633. * @type WebGLMaskManager
  14634. */
  14635. this.maskManager = new PIXI.WebGLMaskManager();
  14636. /**
  14637. * Manages the filters
  14638. * @property filterManager
  14639. * @type WebGLFilterManager
  14640. */
  14641. this.filterManager = new PIXI.WebGLFilterManager();
  14642. /**
  14643. * Manages the stencil buffer
  14644. * @property stencilManager
  14645. * @type WebGLStencilManager
  14646. */
  14647. this.stencilManager = new PIXI.WebGLStencilManager();
  14648. /**
  14649. * Manages the blendModes
  14650. * @property blendModeManager
  14651. * @type WebGLBlendModeManager
  14652. */
  14653. this.blendModeManager = new PIXI.WebGLBlendModeManager();
  14654. /**
  14655. * @property renderSession
  14656. * @type Object
  14657. */
  14658. this.renderSession = {};
  14659. /**
  14660. * @property currentBatchedTextures
  14661. * @type Array
  14662. */
  14663. this.currentBatchedTextures = [];
  14664. // Needed?
  14665. this.renderSession.game = this.game;
  14666. this.renderSession.gl = this.gl;
  14667. this.renderSession.drawCount = 0;
  14668. this.renderSession.shaderManager = this.shaderManager;
  14669. this.renderSession.maskManager = this.maskManager;
  14670. this.renderSession.filterManager = this.filterManager;
  14671. this.renderSession.blendModeManager = this.blendModeManager;
  14672. this.renderSession.spriteBatch = this.spriteBatch;
  14673. this.renderSession.stencilManager = this.stencilManager;
  14674. this.renderSession.renderer = this;
  14675. this.renderSession.resolution = this.resolution;
  14676. this.renderSession.roundPixels = false;
  14677. this.renderSession.maxTextureAvailableSpace = null; // filled in setTexturePriority()
  14678. // time init the context..
  14679. this.initContext();
  14680. // map some webGL blend modes..
  14681. this.mapBlendModes();
  14682. };
  14683. // constructor
  14684. PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer;
  14685. /**
  14686. * @method PIXI.WebGLRenderer#initContext
  14687. */
  14688. PIXI.WebGLRenderer.prototype.initContext = function()
  14689. {
  14690. var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions);
  14691. this.gl = gl;
  14692. if (!gl) {
  14693. // fail, not able to get a context
  14694. throw new Error('This browser does not support webGL. Try using the canvas renderer');
  14695. }
  14696. this.maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  14697. this.maxTextureSize = this.gl.getParameter(gl.MAX_TEXTURE_SIZE);
  14698. this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId++;
  14699. PIXI.glContexts[this.glContextId] = gl;
  14700. PIXI.instances[this.glContextId] = this;
  14701. // set up the default pixi settings..
  14702. gl.disable(gl.DEPTH_TEST);
  14703. gl.disable(gl.CULL_FACE);
  14704. gl.enable(gl.BLEND);
  14705. // need to set the context for all the managers...
  14706. this.shaderManager.setContext(gl);
  14707. this.spriteBatch.setContext(gl);
  14708. this.maskManager.setContext(gl);
  14709. this.filterManager.setContext(gl);
  14710. this.blendModeManager.setContext(gl);
  14711. this.stencilManager.setContext(gl);
  14712. this.renderSession.gl = this.gl;
  14713. // now resize and we are good to go!
  14714. this.resize(this.width, this.height);
  14715. // Load WebGL extension
  14716. this.extensions.compression = {};
  14717. var etc1 = gl.getExtension('WEBGL_compressed_texture_etc1') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc1');
  14718. var pvrtc = gl.getExtension('WEBGL_compressed_texture_pvrtc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
  14719. var s3tc = gl.getExtension('WEBGL_compressed_texture_s3tc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
  14720. if (etc1) { this.extensions.compression.ETC1 = etc1; }
  14721. if (pvrtc) { this.extensions.compression.PVRTC = pvrtc; }
  14722. if (s3tc) { this.extensions.compression.S3TC = s3tc; }
  14723. };
  14724. /**
  14725. * If Multi Texture support has been enabled, then calling this method will enable batching on the given
  14726. * textures. The texture collection is an array of keys, that map to Phaser.Cache image entries.
  14727. *
  14728. * The number of textures that can be batched is dependent on hardware. If you provide more textures
  14729. * than can be batched by the GPU, then only those at the start of the array will be used. Generally
  14730. * you shouldn't provide more than 16 textures to this method. You can check the hardware limit via the
  14731. * `maxTextures` property.
  14732. *
  14733. * You can also check the property `currentBatchedTextures` at any time, to see which textures are currently
  14734. * being batched.
  14735. *
  14736. * To stop all textures from being batched, call this method again with an empty array.
  14737. *
  14738. * To change the textures being batched, call this method with a new array of image keys. The old ones
  14739. * will all be purged out and no-longer batched, and the new ones enabled.
  14740. *
  14741. * Note: Throws a warning if you haven't enabled Multiple Texture batching support in the Phaser Game config.
  14742. *
  14743. * @method PIXI.WebGLRenderer#setTexturePriority
  14744. * @param textureNameCollection {Array} An Array of Texture Cache keys to use for multi-texture batching.
  14745. * @return {Array} An array containing the texture keys that were enabled for batching.
  14746. */
  14747. PIXI.WebGLRenderer.prototype.setTexturePriority = function (textureNameCollection) {
  14748. if (!PIXI._enableMultiTextureToggle)
  14749. {
  14750. console.warn('setTexturePriority error: Multi Texture support hasn\'t been enabled in the Phaser Game Config.');
  14751. return;
  14752. }
  14753. var clampPot = function (potSize) {
  14754. --potSize;
  14755. potSize |= potSize >> 1;
  14756. potSize |= potSize >> 2;
  14757. potSize |= potSize >> 4;
  14758. potSize |= potSize >> 8;
  14759. potSize |= potSize >> 16;
  14760. return ++potSize;
  14761. };
  14762. var gl = this.gl;
  14763. var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  14764. var maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
  14765. var imageCache = this.game.cache._cache.image;
  14766. var imageName = null;
  14767. // Clear out all previously batched textures and reset their flags.
  14768. // If the array has been modified, then the developer will have to
  14769. // deal with that in their own way.
  14770. for (var i = 0; i < this.currentBatchedTextures.length; i++)
  14771. {
  14772. imageName = this.currentBatchedTextures[i];
  14773. if (!(imageName in imageCache))
  14774. {
  14775. console.warn('setTexturePriority: There is no image "%s" in the image cache.', imageName);
  14776. continue;
  14777. }
  14778. imageCache[imageName].base.textureIndex = 0;
  14779. }
  14780. var maxTextureAvailableSpace = (maxTextureSize) - clampPot(Math.max(this.width, this.height));
  14781. this.currentBatchedTextures.length = 0;
  14782. // We start from 1 because framebuffer texture uses unit 0.
  14783. for (var j = 0; j < textureNameCollection.length; ++j)
  14784. {
  14785. imageName = textureNameCollection[j];
  14786. if (!(imageName in imageCache))
  14787. {
  14788. console.warn('setTexturePriority: There is no image "%s" in the image cache.', imageName);
  14789. continue;
  14790. }
  14791. // Unit 0 is reserved for Pixi's framebuffer
  14792. var base = imageCache[imageName].base;
  14793. maxTextureAvailableSpace -= clampPot(Math.max(base.width, base.height));
  14794. if (maxTextureAvailableSpace <= 0) {
  14795. base.textureIndex = 0;
  14796. console.warn('setTexturePriority: Image "%s" was given textureIndex=0 because there is no available texture space (%s).',
  14797. imageName, maxTextureAvailableSpace);
  14798. } else {
  14799. base.textureIndex = (1 + (j % (maxTextures - 1)));
  14800. }
  14801. this.currentBatchedTextures.push(imageName);
  14802. }
  14803. this.renderSession.maxTextureAvailableSpace = maxTextureAvailableSpace;
  14804. return this.currentBatchedTextures;
  14805. };
  14806. /**
  14807. * Renders the stage to its webGL view
  14808. *
  14809. * @method PIXI.WebGLRenderer#render
  14810. * @param stage {Stage} the Stage element to be rendered
  14811. */
  14812. PIXI.WebGLRenderer.prototype.render = function(stage)
  14813. {
  14814. // no point rendering if our context has been blown up!
  14815. if (this.contextLost)
  14816. {
  14817. return;
  14818. }
  14819. var gl = this.gl;
  14820. // -- Does this need to be set every frame? -- //
  14821. gl.viewport(0, 0, this.width, this.height);
  14822. // make sure we are bound to the main frame buffer
  14823. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  14824. if (this.game.clearBeforeRender)
  14825. {
  14826. gl.clearColor(stage._bgColor.r, stage._bgColor.g, stage._bgColor.b, stage._bgColor.a);
  14827. gl.clear(gl.COLOR_BUFFER_BIT);
  14828. }
  14829. this.offset.x = this.game.camera._shake.x;
  14830. this.offset.y = this.game.camera._shake.y;
  14831. this.renderDisplayObject(stage, this.projection);
  14832. };
  14833. /**
  14834. * Renders a Display Object.
  14835. *
  14836. * @method PIXI.WebGLRenderer#renderDisplayObject
  14837. * @param displayObject {DisplayObject} The DisplayObject to render
  14838. * @param projection {Point} The projection
  14839. * @param buffer {Array} a standard WebGL buffer
  14840. */
  14841. PIXI.WebGLRenderer.prototype.renderDisplayObject = function(displayObject, projection, buffer, matrix)
  14842. {
  14843. this.renderSession.blendModeManager.setBlendMode(PIXI.blendModes.NORMAL);
  14844. // reset the render session data..
  14845. this.renderSession.drawCount = 0;
  14846. // make sure to flip the Y if using a render texture..
  14847. this.renderSession.flipY = buffer ? -1 : 1;
  14848. // set the default projection
  14849. this.renderSession.projection = projection;
  14850. //set the default offset
  14851. this.renderSession.offset = this.offset;
  14852. // start the sprite batch
  14853. this.spriteBatch.begin(this.renderSession);
  14854. // start the filter manager
  14855. this.filterManager.begin(this.renderSession, buffer);
  14856. // render the scene!
  14857. displayObject._renderWebGL(this.renderSession, matrix);
  14858. // finish the sprite batch
  14859. this.spriteBatch.end();
  14860. };
  14861. /**
  14862. * Resizes the webGL view to the specified width and height.
  14863. *
  14864. * @method PIXI.WebGLRenderer#resize
  14865. * @param width {Number} the new width of the webGL view
  14866. * @param height {Number} the new height of the webGL view
  14867. */
  14868. PIXI.WebGLRenderer.prototype.resize = function(width, height)
  14869. {
  14870. this.width = width * this.resolution;
  14871. this.height = height * this.resolution;
  14872. this.view.width = this.width;
  14873. this.view.height = this.height;
  14874. if (this.autoResize) {
  14875. this.view.style.width = this.width / this.resolution + 'px';
  14876. this.view.style.height = this.height / this.resolution + 'px';
  14877. }
  14878. this.gl.viewport(0, 0, this.width, this.height);
  14879. this.projection.x = this.width / 2 / this.resolution;
  14880. this.projection.y = -this.height / 2 / this.resolution;
  14881. };
  14882. /**
  14883. * Updates and creates a WebGL compressed texture for the renderers context.
  14884. *
  14885. * @method PIXI.WebGLRenderer#updateCompressedTexture
  14886. * @param texture {Texture} the texture to update
  14887. * @return {boolean} True if the texture was successfully bound, otherwise false.
  14888. */
  14889. PIXI.WebGLRenderer.prototype.updateCompressedTexture = function (texture) {
  14890. if (!texture.hasLoaded)
  14891. {
  14892. return false;
  14893. }
  14894. var gl = this.gl;
  14895. var textureMetaData = texture.source;
  14896. if (!texture._glTextures[gl.id])
  14897. {
  14898. texture._glTextures[gl.id] = gl.createTexture();
  14899. }
  14900. gl.activeTexture(gl.TEXTURE0 + texture.textureIndex);
  14901. gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]);
  14902. gl.compressedTexImage2D(
  14903. gl.TEXTURE_2D,
  14904. 0,
  14905. textureMetaData.glExtensionFormat,
  14906. textureMetaData.width,
  14907. textureMetaData.height,
  14908. 0,
  14909. textureMetaData.textureData
  14910. );
  14911. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  14912. if (texture.mipmap && Phaser.Math.isPowerOfTwo(texture.width, texture.height))
  14913. {
  14914. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
  14915. gl.generateMipmap(gl.TEXTURE_2D);
  14916. }
  14917. else
  14918. {
  14919. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  14920. }
  14921. if (!texture._powerOf2)
  14922. {
  14923. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  14924. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  14925. }
  14926. else
  14927. {
  14928. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
  14929. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
  14930. }
  14931. texture._dirty[gl.id] = false;
  14932. return true;
  14933. };
  14934. /**
  14935. * Updates and Creates a WebGL texture for the renderers context.
  14936. *
  14937. * @method PIXI.WebGLRenderer#updateTexture
  14938. * @param texture {Texture} the texture to update
  14939. * @return {boolean} True if the texture was successfully bound, otherwise false.
  14940. */
  14941. PIXI.WebGLRenderer.prototype.updateTexture = function(texture)
  14942. {
  14943. if (!texture.hasLoaded)
  14944. {
  14945. return false;
  14946. }
  14947. if (texture.source.compressionAlgorithm) {
  14948. return this.updateCompressedTexture(texture);
  14949. }
  14950. var gl = this.gl;
  14951. if (!texture._glTextures[gl.id])
  14952. {
  14953. texture._glTextures[gl.id] = gl.createTexture();
  14954. }
  14955. gl.activeTexture(gl.TEXTURE0 + texture.textureIndex);
  14956. gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]);
  14957. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha);
  14958. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source);
  14959. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  14960. if (texture.mipmap && Phaser.Math.isPowerOfTwo(texture.width, texture.height))
  14961. {
  14962. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
  14963. gl.generateMipmap(gl.TEXTURE_2D);
  14964. }
  14965. else
  14966. {
  14967. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  14968. }
  14969. if (!texture._powerOf2)
  14970. {
  14971. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  14972. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  14973. }
  14974. else
  14975. {
  14976. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
  14977. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
  14978. }
  14979. texture._dirty[gl.id] = false;
  14980. // return texture._glTextures[gl.id];
  14981. return true;
  14982. };
  14983. /**
  14984. * Removes everything from the renderer (event listeners, spritebatch, etc...)
  14985. *
  14986. * @method PIXI.WebGLRenderer#destroy
  14987. */
  14988. PIXI.WebGLRenderer.prototype.destroy = function()
  14989. {
  14990. PIXI.glContexts[this.glContextId] = null;
  14991. this.projection = null;
  14992. this.offset = null;
  14993. this.shaderManager.destroy();
  14994. this.spriteBatch.destroy();
  14995. this.maskManager.destroy();
  14996. this.filterManager.destroy();
  14997. this.shaderManager = null;
  14998. this.spriteBatch = null;
  14999. this.maskManager = null;
  15000. this.filterManager = null;
  15001. this.gl = null;
  15002. this.renderSession = null;
  15003. Phaser.CanvasPool.remove(this);
  15004. PIXI.instances[this.glContextId] = null;
  15005. PIXI.WebGLRenderer.glContextId--;
  15006. };
  15007. /**
  15008. * Maps Pixi blend modes to WebGL blend modes.
  15009. *
  15010. * @method PIXI.WebGLRenderer#mapBlendModes
  15011. */
  15012. PIXI.WebGLRenderer.prototype.mapBlendModes = function()
  15013. {
  15014. var gl = this.gl;
  15015. if (!PIXI.blendModesWebGL)
  15016. {
  15017. var b = [];
  15018. var modes = PIXI.blendModes;
  15019. b[modes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15020. b[modes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA];
  15021. b[modes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA];
  15022. b[modes.SCREEN] = [gl.SRC_ALPHA, gl.ONE];
  15023. b[modes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15024. b[modes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15025. b[modes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15026. b[modes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15027. b[modes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15028. b[modes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15029. b[modes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15030. b[modes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15031. b[modes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15032. b[modes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15033. b[modes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15034. b[modes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15035. b[modes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];
  15036. PIXI.blendModesWebGL = b;
  15037. }
  15038. };
  15039. PIXI.WebGLRenderer.prototype.getMaxTextureUnit = function() {
  15040. var gl = this.gl;
  15041. return gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  15042. };
  15043. PIXI.enableMultiTexture = function() {
  15044. PIXI._enableMultiTextureToggle = true;
  15045. };
  15046. PIXI.WebGLRenderer.glContextId = 0;
  15047. PIXI.WebGLRenderer.textureArray = [];
  15048. /**
  15049. * @author Mat Groves http://matgroves.com/ @Doormat23
  15050. */
  15051. /**
  15052. * @class PIXI.WebGLBlendModeManager
  15053. * @constructor
  15054. * @param gl {WebGLContext} the current WebGL drawing context
  15055. */
  15056. PIXI.WebGLBlendModeManager = function()
  15057. {
  15058. /**
  15059. * @property currentBlendMode
  15060. * @type Number
  15061. */
  15062. this.currentBlendMode = 99999;
  15063. };
  15064. PIXI.WebGLBlendModeManager.prototype.constructor = PIXI.WebGLBlendModeManager;
  15065. /**
  15066. * Sets the WebGL Context.
  15067. *
  15068. * @method PIXI.WebGLBlendModeManager#setContext
  15069. * @param gl {WebGLContext} the current WebGL drawing context
  15070. */
  15071. PIXI.WebGLBlendModeManager.prototype.setContext = function(gl)
  15072. {
  15073. this.gl = gl;
  15074. };
  15075. /**
  15076. * Sets-up the given blendMode from WebGL's point of view.
  15077. *
  15078. * @method PIXI.WebGLBlendModeManager#setBlendMode
  15079. * @param blendMode {Number} the blendMode, should be a Pixi const, such as PIXI.BlendModes.ADD
  15080. */
  15081. PIXI.WebGLBlendModeManager.prototype.setBlendMode = function(blendMode)
  15082. {
  15083. if(this.currentBlendMode === blendMode)return false;
  15084. this.currentBlendMode = blendMode;
  15085. var blendModeWebGL = PIXI.blendModesWebGL[this.currentBlendMode];
  15086. if (blendModeWebGL)
  15087. {
  15088. this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
  15089. }
  15090. return true;
  15091. };
  15092. /**
  15093. * Destroys this object.
  15094. *
  15095. * @method PIXI.WebGLBlendModeManager#destroy
  15096. */
  15097. PIXI.WebGLBlendModeManager.prototype.destroy = function()
  15098. {
  15099. this.gl = null;
  15100. };
  15101. /**
  15102. * @author Mat Groves http://matgroves.com/ @Doormat23
  15103. */
  15104. /**
  15105. * @class PIXI.WebGLMaskManager
  15106. * @constructor
  15107. * @private
  15108. */
  15109. PIXI.WebGLMaskManager = function()
  15110. {
  15111. };
  15112. PIXI.WebGLMaskManager.prototype.constructor = PIXI.WebGLMaskManager;
  15113. /**
  15114. * Sets the drawing context to the one given in parameter.
  15115. *
  15116. * @method PIXI.WebGLMaskManager#setContext
  15117. * @param gl {WebGLContext} the current WebGL drawing context
  15118. */
  15119. PIXI.WebGLMaskManager.prototype.setContext = function(gl)
  15120. {
  15121. this.gl = gl;
  15122. };
  15123. /**
  15124. * Applies the Mask and adds it to the current filter stack.
  15125. *
  15126. * @method PIXI.WebGLMaskManager#pushMask
  15127. * @param maskData {Array}
  15128. * @param renderSession {Object}
  15129. */
  15130. PIXI.WebGLMaskManager.prototype.pushMask = function(maskData, renderSession)
  15131. {
  15132. var gl = renderSession.gl;
  15133. if (maskData.dirty)
  15134. {
  15135. PIXI.WebGLGraphics.updateGraphics(maskData, gl);
  15136. }
  15137. if (maskData._webGL[gl.id] === undefined || maskData._webGL[gl.id].data === undefined || maskData._webGL[gl.id].data.length === 0)
  15138. {
  15139. return;
  15140. }
  15141. renderSession.stencilManager.pushStencil(maskData, maskData._webGL[gl.id].data[0], renderSession);
  15142. };
  15143. /**
  15144. * Removes the last filter from the filter stack and doesn't return it.
  15145. *
  15146. * @method PIXI.WebGLMaskManager#popMask
  15147. * @param maskData {Array}
  15148. * @param renderSession {Object} an object containing all the useful parameters
  15149. */
  15150. PIXI.WebGLMaskManager.prototype.popMask = function(maskData, renderSession)
  15151. {
  15152. var gl = this.gl;
  15153. if (maskData._webGL[gl.id] === undefined || maskData._webGL[gl.id].data === undefined || maskData._webGL[gl.id].data.length === 0)
  15154. {
  15155. return;
  15156. }
  15157. renderSession.stencilManager.popStencil(maskData, maskData._webGL[gl.id].data[0], renderSession);
  15158. };
  15159. /**
  15160. * Destroys the mask stack.
  15161. *
  15162. * @method PIXI.WebGLMaskManager#destroy
  15163. */
  15164. PIXI.WebGLMaskManager.prototype.destroy = function()
  15165. {
  15166. this.gl = null;
  15167. };
  15168. /**
  15169. * @author Mat Groves http://matgroves.com/ @Doormat23
  15170. */
  15171. /**
  15172. * @class PIXI.WebGLStencilManager
  15173. * @constructor
  15174. * @private
  15175. */
  15176. PIXI.WebGLStencilManager = function()
  15177. {
  15178. this.stencilStack = [];
  15179. this.reverse = true;
  15180. this.count = 0;
  15181. };
  15182. /**
  15183. * Sets the drawing context to the one given in parameter.
  15184. *
  15185. * @method PIXI.WebGLStencilManager#setContext
  15186. * @param gl {WebGLContext} the current WebGL drawing context
  15187. */
  15188. PIXI.WebGLStencilManager.prototype.setContext = function(gl)
  15189. {
  15190. this.gl = gl;
  15191. };
  15192. /**
  15193. * Applies the Mask and adds it to the current filter stack.
  15194. *
  15195. * @method PIXI.WebGLStencilManager#pushMask
  15196. * @param graphics {Graphics}
  15197. * @param webGLData {Array}
  15198. * @param renderSession {Object}
  15199. */
  15200. PIXI.WebGLStencilManager.prototype.pushStencil = function(graphics, webGLData, renderSession)
  15201. {
  15202. var gl = this.gl;
  15203. this.bindGraphics(graphics, webGLData, renderSession);
  15204. if(this.stencilStack.length === 0)
  15205. {
  15206. gl.enable(gl.STENCIL_TEST);
  15207. gl.clear(gl.STENCIL_BUFFER_BIT);
  15208. this.reverse = true;
  15209. this.count = 0;
  15210. }
  15211. this.stencilStack.push(webGLData);
  15212. var level = this.count;
  15213. gl.colorMask(false, false, false, false);
  15214. gl.stencilFunc(gl.ALWAYS,0,0xFF);
  15215. gl.stencilOp(gl.KEEP,gl.KEEP,gl.INVERT);
  15216. // draw the triangle strip!
  15217. if(webGLData.mode === 1)
  15218. {
  15219. gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 );
  15220. if(this.reverse)
  15221. {
  15222. gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF);
  15223. gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR);
  15224. }
  15225. else
  15226. {
  15227. gl.stencilFunc(gl.EQUAL,level, 0xFF);
  15228. gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR);
  15229. }
  15230. // draw a quad to increment..
  15231. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 );
  15232. if(this.reverse)
  15233. {
  15234. gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF);
  15235. }
  15236. else
  15237. {
  15238. gl.stencilFunc(gl.EQUAL,level+1, 0xFF);
  15239. }
  15240. this.reverse = !this.reverse;
  15241. }
  15242. else
  15243. {
  15244. if(!this.reverse)
  15245. {
  15246. gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF);
  15247. gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR);
  15248. }
  15249. else
  15250. {
  15251. gl.stencilFunc(gl.EQUAL,level, 0xFF);
  15252. gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR);
  15253. }
  15254. gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 );
  15255. if(!this.reverse)
  15256. {
  15257. gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF);
  15258. }
  15259. else
  15260. {
  15261. gl.stencilFunc(gl.EQUAL,level+1, 0xFF);
  15262. }
  15263. }
  15264. gl.colorMask(true, true, true, true);
  15265. gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
  15266. this.count++;
  15267. };
  15268. /**
  15269. * TODO this does not belong here!
  15270. *
  15271. * @method PIXI.WebGLStencilManager#bindGraphics
  15272. * @param graphics {Graphics}
  15273. * @param webGLData {Array}
  15274. * @param renderSession {Object}
  15275. */
  15276. PIXI.WebGLStencilManager.prototype.bindGraphics = function(graphics, webGLData, renderSession)
  15277. {
  15278. //if(this._currentGraphics === graphics)return;
  15279. this._currentGraphics = graphics;
  15280. var gl = this.gl;
  15281. // bind the graphics object..
  15282. var projection = renderSession.projection,
  15283. offset = renderSession.offset,
  15284. shader;// = renderSession.shaderManager.primitiveShader;
  15285. if(webGLData.mode === 1)
  15286. {
  15287. shader = renderSession.shaderManager.complexPrimitiveShader;
  15288. renderSession.shaderManager.setShader( shader );
  15289. gl.uniform1f(shader.flipY, renderSession.flipY);
  15290. gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true));
  15291. gl.uniform2f(shader.projectionVector, projection.x, -projection.y);
  15292. gl.uniform2f(shader.offsetVector, -offset.x, -offset.y);
  15293. gl.uniform3fv(shader.tintColor, Phaser.Color.hexToRGBArray(graphics.tint));
  15294. gl.uniform3fv(shader.color, webGLData.color);
  15295. gl.uniform1f(shader.alpha, graphics.worldAlpha * webGLData.alpha);
  15296. gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer);
  15297. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 2, 0);
  15298. // now do the rest..
  15299. // set the index buffer!
  15300. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer);
  15301. }
  15302. else
  15303. {
  15304. //renderSession.shaderManager.activatePrimitiveShader();
  15305. shader = renderSession.shaderManager.primitiveShader;
  15306. renderSession.shaderManager.setShader( shader );
  15307. gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true));
  15308. gl.uniform1f(shader.flipY, renderSession.flipY);
  15309. gl.uniform2f(shader.projectionVector, projection.x, -projection.y);
  15310. gl.uniform2f(shader.offsetVector, -offset.x, -offset.y);
  15311. gl.uniform3fv(shader.tintColor, Phaser.Color.hexToRGBArray(graphics.tint));
  15312. gl.uniform1f(shader.alpha, graphics.worldAlpha);
  15313. gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer);
  15314. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0);
  15315. gl.vertexAttribPointer(shader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4);
  15316. // set the index buffer!
  15317. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer);
  15318. }
  15319. };
  15320. /**
  15321. * @method PIXI.WebGLStencilManager#popStencil
  15322. * @param graphics {Graphics}
  15323. * @param webGLData {Array}
  15324. * @param renderSession {Object}
  15325. */
  15326. PIXI.WebGLStencilManager.prototype.popStencil = function(graphics, webGLData, renderSession)
  15327. {
  15328. var gl = this.gl;
  15329. this.stencilStack.pop();
  15330. this.count--;
  15331. if(this.stencilStack.length === 0)
  15332. {
  15333. // the stack is empty!
  15334. gl.disable(gl.STENCIL_TEST);
  15335. }
  15336. else
  15337. {
  15338. var level = this.count;
  15339. this.bindGraphics(graphics, webGLData, renderSession);
  15340. gl.colorMask(false, false, false, false);
  15341. if(webGLData.mode === 1)
  15342. {
  15343. this.reverse = !this.reverse;
  15344. if(this.reverse)
  15345. {
  15346. gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF);
  15347. gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR);
  15348. }
  15349. else
  15350. {
  15351. gl.stencilFunc(gl.EQUAL,level+1, 0xFF);
  15352. gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR);
  15353. }
  15354. // draw a quad to increment..
  15355. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 );
  15356. gl.stencilFunc(gl.ALWAYS,0,0xFF);
  15357. gl.stencilOp(gl.KEEP,gl.KEEP,gl.INVERT);
  15358. // draw the triangle strip!
  15359. gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 );
  15360. if(!this.reverse)
  15361. {
  15362. gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF);
  15363. }
  15364. else
  15365. {
  15366. gl.stencilFunc(gl.EQUAL,level, 0xFF);
  15367. }
  15368. }
  15369. else
  15370. {
  15371. // console.log("<<>>")
  15372. if(!this.reverse)
  15373. {
  15374. gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF);
  15375. gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR);
  15376. }
  15377. else
  15378. {
  15379. gl.stencilFunc(gl.EQUAL,level+1, 0xFF);
  15380. gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR);
  15381. }
  15382. gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 );
  15383. if(!this.reverse)
  15384. {
  15385. gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF);
  15386. }
  15387. else
  15388. {
  15389. gl.stencilFunc(gl.EQUAL,level, 0xFF);
  15390. }
  15391. }
  15392. gl.colorMask(true, true, true, true);
  15393. gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
  15394. }
  15395. };
  15396. /**
  15397. * Destroys the mask stack.
  15398. *
  15399. * @method PIXI.WebGLStencilManager#destroy
  15400. */
  15401. PIXI.WebGLStencilManager.prototype.destroy = function()
  15402. {
  15403. this.stencilStack = null;
  15404. this.gl = null;
  15405. };
  15406. /**
  15407. * @author Mat Groves http://matgroves.com/ @Doormat23
  15408. */
  15409. /**
  15410. * @class PIXI.WebGLShaderManager
  15411. * @constructor
  15412. * @private
  15413. */
  15414. PIXI.WebGLShaderManager = function()
  15415. {
  15416. /**
  15417. * @property maxAttibs
  15418. * @type Number
  15419. */
  15420. this.maxAttibs = 10;
  15421. /**
  15422. * @property attribState
  15423. * @type Array
  15424. */
  15425. this.attribState = [];
  15426. /**
  15427. * @property tempAttribState
  15428. * @type Array
  15429. */
  15430. this.tempAttribState = [];
  15431. for (var i = 0; i < this.maxAttibs; i++)
  15432. {
  15433. this.attribState[i] = false;
  15434. }
  15435. /**
  15436. * @property stack
  15437. * @type Array
  15438. */
  15439. this.stack = [];
  15440. };
  15441. PIXI.WebGLShaderManager.prototype.constructor = PIXI.WebGLShaderManager;
  15442. /**
  15443. * Initialises the context and the properties.
  15444. *
  15445. * @method PIXI.WebGLShaderManager#setContext
  15446. * @param gl {WebGLContext} the current WebGL drawing context
  15447. */
  15448. PIXI.WebGLShaderManager.prototype.setContext = function(gl)
  15449. {
  15450. this.gl = gl;
  15451. // the next one is used for rendering primitives
  15452. this.primitiveShader = new PIXI.PrimitiveShader(gl);
  15453. // the next one is used for rendering triangle strips
  15454. this.complexPrimitiveShader = new PIXI.ComplexPrimitiveShader(gl);
  15455. // this shader is used for the default sprite rendering
  15456. this.defaultShader = new PIXI.PixiShader(gl);
  15457. // this shader is used for the fast sprite rendering
  15458. this.fastShader = new PIXI.PixiFastShader(gl);
  15459. // the next one is used for rendering triangle strips
  15460. this.stripShader = new PIXI.StripShader(gl);
  15461. // the next one is used for rendering creature meshes
  15462. this.creatureShader = PIXI.CreatureShader ? new PIXI.CreatureShader(gl) : null;
  15463. this.setShader(this.defaultShader);
  15464. };
  15465. /**
  15466. * Takes the attributes given in parameters.
  15467. *
  15468. * @method PIXI.WebGLShaderManager#setAttribs
  15469. * @param attribs {Array} attribs
  15470. */
  15471. PIXI.WebGLShaderManager.prototype.setAttribs = function(attribs)
  15472. {
  15473. // reset temp state
  15474. var i;
  15475. for (i = 0; i < this.tempAttribState.length; i++)
  15476. {
  15477. this.tempAttribState[i] = false;
  15478. }
  15479. // set the new attribs
  15480. for (i = 0; i < attribs.length; i++)
  15481. {
  15482. var attribId = attribs[i];
  15483. this.tempAttribState[attribId] = true;
  15484. }
  15485. var gl = this.gl;
  15486. for (i = 0; i < this.attribState.length; i++)
  15487. {
  15488. if(this.attribState[i] !== this.tempAttribState[i])
  15489. {
  15490. this.attribState[i] = this.tempAttribState[i];
  15491. if(this.tempAttribState[i])
  15492. {
  15493. gl.enableVertexAttribArray(i);
  15494. }
  15495. else
  15496. {
  15497. gl.disableVertexAttribArray(i);
  15498. }
  15499. }
  15500. }
  15501. };
  15502. /**
  15503. * Sets the current shader.
  15504. *
  15505. * @method PIXI.WebGLShaderManager#setShader
  15506. * @param shader {Any}
  15507. */
  15508. PIXI.WebGLShaderManager.prototype.setShader = function(shader)
  15509. {
  15510. if(this._currentId === shader._UID)return false;
  15511. this._currentId = shader._UID;
  15512. this.currentShader = shader;
  15513. this.gl.useProgram(shader.program);
  15514. this.setAttribs(shader.attributes);
  15515. return true;
  15516. };
  15517. /**
  15518. * Destroys this object.
  15519. *
  15520. * @method PIXI.WebGLShaderManager#destroy
  15521. */
  15522. PIXI.WebGLShaderManager.prototype.destroy = function()
  15523. {
  15524. this.attribState = null;
  15525. this.tempAttribState = null;
  15526. this.primitiveShader.destroy();
  15527. this.complexPrimitiveShader.destroy();
  15528. this.defaultShader.destroy();
  15529. this.fastShader.destroy();
  15530. this.stripShader.destroy();
  15531. if (this.creatureShader) {
  15532. this.creatureShader.destroy();
  15533. }
  15534. this.gl = null;
  15535. };
  15536. /**
  15537. * @author Mat Groves
  15538. *
  15539. * Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/
  15540. * for creating the original pixi version!
  15541. * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they now share 4 bytes on the vertex buffer
  15542. *
  15543. * Heavily inspired by LibGDX's WebGLSpriteBatch:
  15544. * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
  15545. */
  15546. /**
  15547. *
  15548. * @class PIXI.WebGLSpriteBatch
  15549. * @private
  15550. * @constructor
  15551. */
  15552. PIXI.WebGLSpriteBatch = function (game) {
  15553. /**
  15554. * @property {Phaser.Game} game - A reference to the currently running game.
  15555. */
  15556. this.game = game;
  15557. /**
  15558. * @property vertSize
  15559. * @type Number
  15560. */
  15561. this.vertSize = 5;
  15562. /**
  15563. * The number of images in the SpriteBatch before it flushes
  15564. * @property size
  15565. * @type Number
  15566. */
  15567. this.size = 2000; //Math.pow(2, 16) / this.vertSize;
  15568. //the total number of bytes in our batch
  15569. // Including texture index:
  15570. // position + uv + color + textureIndex
  15571. // vec2 + vec2 + (char * 4) + float
  15572. this.vertexSize = (4 * 2) + (4 * 2) + (4) + (4);
  15573. var numVerts = this.vertexSize * this.size * 4;
  15574. //this.size * 4 * 4 * this.vertSize;
  15575. //the total number of indices in our batch
  15576. var numIndices = this.size * 6;
  15577. /**
  15578. * Holds the vertices
  15579. *
  15580. * @property vertices
  15581. * @type ArrayBuffer
  15582. */
  15583. this.vertices = new ArrayBuffer(numVerts);
  15584. /**
  15585. * View on the vertices as a Float32Array
  15586. *
  15587. * @property positions
  15588. * @type Float32Array
  15589. */
  15590. this.positions = new Float32Array(this.vertices);
  15591. /**
  15592. * View on the vertices as a Uint32Array
  15593. *
  15594. * @property colors
  15595. * @type Uint32Array
  15596. */
  15597. this.colors = new Uint32Array(this.vertices);
  15598. /**
  15599. * Holds the indices
  15600. *
  15601. * @property indices
  15602. * @type Uint16Array
  15603. */
  15604. this.indices = new Uint16Array(numIndices);
  15605. /**
  15606. * @property lastIndexCount
  15607. * @type Number
  15608. */
  15609. this.lastIndexCount = 0;
  15610. for (var i = 0, j = 0; i < numIndices; i += 6, j += 4) {
  15611. this.indices[i + 0] = j + 0;
  15612. this.indices[i + 1] = j + 1;
  15613. this.indices[i + 2] = j + 2;
  15614. this.indices[i + 3] = j + 0;
  15615. this.indices[i + 4] = j + 2;
  15616. this.indices[i + 5] = j + 3;
  15617. }
  15618. /**
  15619. * @property drawing
  15620. * @type Boolean
  15621. */
  15622. this.drawing = false;
  15623. /**
  15624. * @property currentBatchSize
  15625. * @type Number
  15626. */
  15627. this.currentBatchSize = 0;
  15628. /**
  15629. * @property currentBaseTexture
  15630. * @type BaseTexture
  15631. */
  15632. this.currentBaseTexture = null;
  15633. /**
  15634. * @property dirty
  15635. * @type Boolean
  15636. */
  15637. this.dirty = true;
  15638. /**
  15639. * @property textures
  15640. * @type Array
  15641. */
  15642. this.textures = [];
  15643. /**
  15644. * @property blendModes
  15645. * @type Array
  15646. */
  15647. this.blendModes = [];
  15648. /**
  15649. * @property shaders
  15650. * @type Array
  15651. */
  15652. this.shaders = [];
  15653. /**
  15654. * @property sprites
  15655. * @type Array
  15656. */
  15657. this.sprites = [];
  15658. /**
  15659. * @property defaultShader
  15660. * @type Phaser.Filter
  15661. */
  15662. this.defaultShader = null;
  15663. };
  15664. /**
  15665. * @method PIXI.WebGLSpriteBatch#setContext
  15666. * @param gl {WebGLContext} the current WebGL drawing context
  15667. */
  15668. PIXI.WebGLSpriteBatch.prototype.setContext = function (gl) {
  15669. this.MAX_TEXTURES = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  15670. this.gl = gl;
  15671. if (PIXI._enableMultiTextureToggle) {
  15672. var dynamicIfs = '\tif (vTextureIndex == 0.0) {gl_FragColor = texture2D(uSamplerArray[0], vTextureCoord) * vColor;return;}\n'
  15673. for (var index = 1; index < this.MAX_TEXTURES; ++index) {
  15674. dynamicIfs += '\tif (vTextureIndex == ' +
  15675. index + '.0) {gl_FragColor = texture2D(uSamplerArray[' +
  15676. index + '], vTextureCoord) * vColor;return;}\n'
  15677. }
  15678. this.defaultShader = new Phaser.Filter(
  15679. this.game,
  15680. undefined,
  15681. [
  15682. '//WebGLSpriteBatch Fragment Shader.',
  15683. 'precision lowp float;',
  15684. 'varying vec2 vTextureCoord;',
  15685. 'varying vec4 vColor;',
  15686. 'varying float vTextureIndex;',
  15687. 'uniform sampler2D uSamplerArray[' + this.MAX_TEXTURES + '];',
  15688. 'void main(void) {',
  15689. dynamicIfs,
  15690. '\tgl_FragColor = texture2D(uSamplerArray[0], vTextureCoord) * vColor;',
  15691. '}'
  15692. ]);
  15693. }
  15694. else
  15695. {
  15696. this.defaultShader = new Phaser.Filter(
  15697. this.game,
  15698. undefined,
  15699. [
  15700. '//WebGLSpriteBatch Fragment Shader.',
  15701. 'precision lowp float;',
  15702. 'varying vec2 vTextureCoord;',
  15703. 'varying vec4 vColor;',
  15704. 'varying float vTextureIndex;',
  15705. 'uniform sampler2D uSampler;',
  15706. 'void main(void) {',
  15707. ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;',
  15708. '}'
  15709. ]);
  15710. }
  15711. // create a couple of buffers
  15712. this.vertexBuffer = gl.createBuffer();
  15713. this.indexBuffer = gl.createBuffer();
  15714. // 65535 is max index, so 65535 / 6 = 10922.
  15715. //upload the index data
  15716. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  15717. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
  15718. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  15719. gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
  15720. this.currentBlendMode = 99999;
  15721. var shader = new PIXI.PixiShader(gl);
  15722. shader.fragmentSrc = this.defaultShader.fragmentSrc;
  15723. shader.uniforms = {};
  15724. shader.init();
  15725. this.defaultShader.shaders[gl.id] = shader;
  15726. };
  15727. /**
  15728. * @method PIXI.WebGLSpriteBatch#begin
  15729. * @param renderSession {Object} The RenderSession object
  15730. */
  15731. PIXI.WebGLSpriteBatch.prototype.begin = function (renderSession) {
  15732. this.renderSession = renderSession;
  15733. this.shader = this.renderSession.shaderManager.defaultShader;
  15734. this.start();
  15735. };
  15736. /**
  15737. * @method PIXI.WebGLSpriteBatch#end
  15738. */
  15739. PIXI.WebGLSpriteBatch.prototype.end = function () {
  15740. this.flush();
  15741. };
  15742. /**
  15743. * @method PIXI.WebGLSpriteBatch#render
  15744. * @param sprite {Sprite} the sprite to render when using this spritebatch
  15745. * @param {Matrix} [matrix] - Optional matrix. If provided the Display Object will be rendered using this matrix, otherwise it will use its worldTransform.
  15746. */
  15747. PIXI.WebGLSpriteBatch.prototype.render = function (sprite, matrix) {
  15748. var texture = sprite.texture;
  15749. var baseTexture = texture.baseTexture;
  15750. var gl = this.gl;
  15751. if (PIXI.WebGLRenderer.textureArray[baseTexture.textureIndex] != baseTexture) {
  15752. this.flush();
  15753. gl.activeTexture(gl.TEXTURE0 + baseTexture.textureIndex);
  15754. gl.bindTexture(gl.TEXTURE_2D, baseTexture._glTextures[gl.id]);
  15755. PIXI.WebGLRenderer.textureArray[baseTexture.textureIndex] = baseTexture;
  15756. }
  15757. // They provided an alternative rendering matrix, so use it
  15758. var wt = sprite.worldTransform;
  15759. if (matrix) {
  15760. wt = matrix;
  15761. }
  15762. // check texture..
  15763. if (this.currentBatchSize >= this.size) {
  15764. this.flush();
  15765. this.currentBaseTexture = texture.baseTexture;
  15766. }
  15767. // get the uvs for the texture
  15768. var uvs = texture._uvs;
  15769. // if the uvs have not updated then no point rendering just yet!
  15770. if (!uvs) {
  15771. return;
  15772. }
  15773. var aX = sprite.anchor.x;
  15774. var aY = sprite.anchor.y;
  15775. var w0, w1, h0, h1;
  15776. if (texture.trim) {
  15777. // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords.
  15778. var trim = texture.trim;
  15779. w1 = trim.x - aX * trim.width;
  15780. w0 = w1 + texture.crop.width;
  15781. h1 = trim.y - aY * trim.height;
  15782. h0 = h1 + texture.crop.height;
  15783. } else {
  15784. w0 = (texture.frame.width) * (1 - aX);
  15785. w1 = (texture.frame.width) * -aX;
  15786. h0 = texture.frame.height * (1 - aY);
  15787. h1 = texture.frame.height * -aY;
  15788. }
  15789. var i = this.currentBatchSize * this.vertexSize; //4 * this.vertSize;
  15790. var tiOffset = this.currentBatchSize * 4;
  15791. var resolution = texture.baseTexture.resolution;
  15792. var textureIndex = texture.baseTexture.textureIndex;
  15793. var a = wt.a / resolution;
  15794. var b = wt.b / resolution;
  15795. var c = wt.c / resolution;
  15796. var d = wt.d / resolution;
  15797. var tx = wt.tx;
  15798. var ty = wt.ty;
  15799. var cw = texture.crop.width;
  15800. var ch = texture.crop.height;
  15801. if (texture.rotated)
  15802. {
  15803. var a0 = wt.a;
  15804. var b0 = wt.b;
  15805. var c0 = wt.c;
  15806. var d0 = wt.d;
  15807. var _w1 = w1;
  15808. var _w0 = w0;
  15809. // Offset before rotating
  15810. tx = wt.c * ch + tx;
  15811. ty = wt.d * ch + ty;
  15812. // Rotate matrix by 90 degrees
  15813. // We use precalculated values for sine and cosine of rad(90)
  15814. a = a0 * 6.123233995736766e-17 + -c0;
  15815. b = b0 * 6.123233995736766e-17 + -d0;
  15816. c = a0 + c0 * 6.123233995736766e-17;
  15817. d = b0 + d0 * 6.123233995736766e-17;
  15818. // Update UV coordinates
  15819. texture._updateUvsInverted();
  15820. // Rotate dimensions
  15821. w0 = h0;
  15822. w1 = h1;
  15823. h0 = _w0;
  15824. h1 = _w1;
  15825. }
  15826. var colors = this.colors;
  15827. var positions = this.positions;
  15828. var tint = sprite.tint;
  15829. var color = (tint >> 16) + (tint & 0xff00) + ((tint & 0xff) << 16) + (sprite.worldAlpha * 255 << 24);
  15830. if (this.renderSession.roundPixels) {
  15831. positions[i++] = a * w1 + c * h1 + tx | 0;
  15832. positions[i++] = d * h1 + b * w1 + ty | 0;
  15833. positions[i++] = uvs.x0;
  15834. positions[i++] = uvs.y0;
  15835. colors[i++] = color;
  15836. positions[i++] = textureIndex;
  15837. positions[i++] = a * w0 + c * h1 + tx | 0;
  15838. positions[i++] = d * h1 + b * w0 + ty | 0;
  15839. positions[i++] = uvs.x1;
  15840. positions[i++] = uvs.y1;
  15841. colors[i++] = color;
  15842. positions[i++] = textureIndex;
  15843. positions[i++] = a * w0 + c * h0 + tx | 0;
  15844. positions[i++] = d * h0 + b * w0 + ty | 0;
  15845. positions[i++] = uvs.x2;
  15846. positions[i++] = uvs.y2;
  15847. colors[i++] = color;
  15848. positions[i++] = textureIndex;
  15849. positions[i++] = a * w1 + c * h0 + tx | 0;
  15850. positions[i++] = d * h0 + b * w1 + ty | 0;
  15851. positions[i++] = uvs.x3;
  15852. positions[i++] = uvs.y3;
  15853. colors[i++] = color;
  15854. positions[i++] = textureIndex;
  15855. } else {
  15856. positions[i++] = a * w1 + c * h1 + tx;
  15857. positions[i++] = d * h1 + b * w1 + ty;
  15858. positions[i++] = uvs.x0;
  15859. positions[i++] = uvs.y0;
  15860. colors[i++] = color;
  15861. positions[i++] = textureIndex;
  15862. positions[i++] = a * w0 + c * h1 + tx;
  15863. positions[i++] = d * h1 + b * w0 + ty;
  15864. positions[i++] = uvs.x1;
  15865. positions[i++] = uvs.y1;
  15866. colors[i++] = color;
  15867. positions[i++] = textureIndex;
  15868. positions[i++] = a * w0 + c * h0 + tx;
  15869. positions[i++] = d * h0 + b * w0 + ty;
  15870. positions[i++] = uvs.x2;
  15871. positions[i++] = uvs.y2;
  15872. colors[i++] = color;
  15873. positions[i++] = textureIndex;
  15874. positions[i++] = a * w1 + c * h0 + tx;
  15875. positions[i++] = d * h0 + b * w1 + ty;
  15876. positions[i++] = uvs.x3;
  15877. positions[i++] = uvs.y3;
  15878. colors[i++] = color;
  15879. positions[i++] = textureIndex;
  15880. }
  15881. // increment the batchsize
  15882. this.sprites[this.currentBatchSize++] = sprite;
  15883. };
  15884. /**
  15885. * Renders a TilingSprite using the spriteBatch.
  15886. *
  15887. * @method PIXI.WebGLSpriteBatch#renderTilingSprite
  15888. * @param sprite {TilingSprite} the sprite to render
  15889. */
  15890. PIXI.WebGLSpriteBatch.prototype.renderTilingSprite = function (sprite) {
  15891. var texture = sprite.tilingTexture;
  15892. var baseTexture = texture.baseTexture;
  15893. var gl = this.gl;
  15894. var textureIndex = sprite.texture.baseTexture.textureIndex;
  15895. if (PIXI.WebGLRenderer.textureArray[textureIndex] != baseTexture) {
  15896. this.flush();
  15897. gl.activeTexture(gl.TEXTURE0 + textureIndex);
  15898. gl.bindTexture(gl.TEXTURE_2D, baseTexture._glTextures[gl.id]);
  15899. PIXI.WebGLRenderer.textureArray[textureIndex] = baseTexture;
  15900. }
  15901. // check texture..
  15902. if (this.currentBatchSize >= this.size) {
  15903. this.flush();
  15904. this.currentBaseTexture = texture.baseTexture;
  15905. }
  15906. // set the textures uvs temporarily
  15907. if (!sprite._uvs) {
  15908. sprite._uvs = new PIXI.TextureUvs();
  15909. }
  15910. var uvs = sprite._uvs;
  15911. var w = texture.baseTexture.width;
  15912. var h = texture.baseTexture.height;
  15913. // var w = sprite._frame.sourceSizeW;
  15914. // var h = sprite._frame.sourceSizeH;
  15915. // w = 16;
  15916. // h = 16;
  15917. sprite.tilePosition.x %= w * sprite.tileScaleOffset.x;
  15918. sprite.tilePosition.y %= h * sprite.tileScaleOffset.y;
  15919. var offsetX = sprite.tilePosition.x / (w * sprite.tileScaleOffset.x);
  15920. var offsetY = sprite.tilePosition.y / (h * sprite.tileScaleOffset.y);
  15921. var scaleX = (sprite.width / w) / (sprite.tileScale.x * sprite.tileScaleOffset.x);
  15922. var scaleY = (sprite.height / h) / (sprite.tileScale.y * sprite.tileScaleOffset.y);
  15923. uvs.x0 = 0 - offsetX;
  15924. uvs.y0 = 0 - offsetY;
  15925. uvs.x1 = (1 * scaleX) - offsetX;
  15926. uvs.y1 = 0 - offsetY;
  15927. uvs.x2 = (1 * scaleX) - offsetX;
  15928. uvs.y2 = (1 * scaleY) - offsetY;
  15929. uvs.x3 = 0 - offsetX;
  15930. uvs.y3 = (1 * scaleY) - offsetY;
  15931. // Get the sprites current alpha and tint and combine them into a single color
  15932. var tint = sprite.tint;
  15933. var color = (tint >> 16) + (tint & 0xff00) + ((tint & 0xff) << 16) + (sprite.worldAlpha * 255 << 24);
  15934. var positions = this.positions;
  15935. var colors = this.colors;
  15936. var width = sprite.width;
  15937. var height = sprite.height;
  15938. // TODO trim??
  15939. var aX = sprite.anchor.x;
  15940. var aY = sprite.anchor.y;
  15941. var w0 = width * (1 - aX);
  15942. var w1 = width * -aX;
  15943. var h0 = height * (1 - aY);
  15944. var h1 = height * -aY;
  15945. var i = this.currentBatchSize * this.vertexSize; //4 * this.vertSize;
  15946. var resolution = texture.baseTexture.resolution;
  15947. var wt = sprite.worldTransform;
  15948. var a = wt.a / resolution;
  15949. var b = wt.b / resolution;
  15950. var c = wt.c / resolution;
  15951. var d = wt.d / resolution;
  15952. var tx = wt.tx;
  15953. var ty = wt.ty;
  15954. // xy
  15955. positions[i++] = a * w1 + c * h1 + tx;
  15956. positions[i++] = d * h1 + b * w1 + ty;
  15957. // uv
  15958. positions[i++] = uvs.x0;
  15959. positions[i++] = uvs.y0;
  15960. // color
  15961. colors[i++] = color;
  15962. // texture index
  15963. positions[i++] = textureIndex;
  15964. // xy
  15965. positions[i++] = (a * w0 + c * h1 + tx);
  15966. positions[i++] = d * h1 + b * w0 + ty;
  15967. // uv
  15968. positions[i++] = uvs.x1;
  15969. positions[i++] = uvs.y1;
  15970. // color
  15971. colors[i++] = color;
  15972. // texture index
  15973. positions[i++] = textureIndex;
  15974. // xy
  15975. positions[i++] = a * w0 + c * h0 + tx;
  15976. positions[i++] = d * h0 + b * w0 + ty;
  15977. // uv
  15978. positions[i++] = uvs.x2;
  15979. positions[i++] = uvs.y2;
  15980. // color
  15981. colors[i++] = color;
  15982. // texture index
  15983. positions[i++] = textureIndex;
  15984. // xy
  15985. positions[i++] = a * w1 + c * h0 + tx;
  15986. positions[i++] = d * h0 + b * w1 + ty;
  15987. // uv
  15988. positions[i++] = uvs.x3;
  15989. positions[i++] = uvs.y3;
  15990. // color
  15991. colors[i++] = color;
  15992. // texture index
  15993. positions[i++] = textureIndex;
  15994. // increment the batchsize
  15995. this.sprites[this.currentBatchSize++] = sprite;
  15996. };
  15997. /**
  15998. * Renders the content and empties the current batch.
  15999. *
  16000. * @method PIXI.WebGLSpriteBatch#flush
  16001. */
  16002. PIXI.WebGLSpriteBatch.prototype.flush = function () {
  16003. // If the batch is length 0 then return as there is nothing to draw
  16004. if (this.currentBatchSize === 0) {
  16005. return;
  16006. }
  16007. var gl = this.gl;
  16008. var shader;
  16009. if (this.dirty) {
  16010. this.dirty = false;
  16011. shader = this.defaultShader.shaders[gl.id];
  16012. // bind the main texture
  16013. gl.activeTexture(gl.TEXTURE0);
  16014. // bind the buffers
  16015. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16016. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  16017. // this is the same for each shader?
  16018. var stride = this.vertexSize; //this.vertSize * 4;
  16019. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
  16020. gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, stride, 8);
  16021. // color attributes will be interpreted as unsigned bytes and normalized
  16022. gl.vertexAttribPointer(shader.colorAttribute, 4, gl.UNSIGNED_BYTE, true, stride, 16);
  16023. // Texture index
  16024. gl.vertexAttribPointer(shader.aTextureIndex, 1, gl.FLOAT, false, stride, 20);
  16025. }
  16026. // upload the verts to the buffer
  16027. if (this.currentBatchSize > (this.size * 0.5)) {
  16028. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
  16029. } else {
  16030. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16031. var view = this.positions.subarray(0, this.currentBatchSize * this.vertexSize);
  16032. gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
  16033. }
  16034. var nextTexture, nextBlendMode, nextShader;
  16035. var batchSize = 0;
  16036. var start = 0;
  16037. var currentBaseTexture = null;
  16038. var currentBlendMode = this.renderSession.blendModeManager.currentBlendMode;
  16039. var currentShader = null;
  16040. var blendSwap = false;
  16041. var shaderSwap = false;
  16042. var sprite;
  16043. var textureIndex = 0;
  16044. for (var i = 0, j = this.currentBatchSize; i < j; i++) {
  16045. sprite = this.sprites[i];
  16046. if (sprite.tilingTexture) {
  16047. nextTexture = sprite.tilingTexture.baseTexture;
  16048. } else {
  16049. nextTexture = sprite.texture.baseTexture;
  16050. }
  16051. nextBlendMode = sprite.blendMode;
  16052. nextShader = sprite.shader || this.defaultShader;
  16053. blendSwap = currentBlendMode !== nextBlendMode;
  16054. shaderSwap = currentShader !== nextShader; // should I use _UIDS???
  16055. var skip = nextTexture.skipRender;
  16056. if (skip && sprite.children.length > 0) {
  16057. skip = false;
  16058. }
  16059. //
  16060. if (/*(currentBaseTexture != nextTexture && !skip) ||*/
  16061. blendSwap ||
  16062. shaderSwap) {
  16063. this.renderBatch(currentBaseTexture, batchSize, start);
  16064. start = i;
  16065. batchSize = 0;
  16066. currentBaseTexture = nextTexture;
  16067. if (blendSwap) {
  16068. currentBlendMode = nextBlendMode;
  16069. this.renderSession.blendModeManager.setBlendMode(currentBlendMode);
  16070. }
  16071. if (shaderSwap) {
  16072. currentShader = nextShader;
  16073. shader = currentShader.shaders[gl.id];
  16074. if (!shader) {
  16075. shader = new PIXI.PixiShader(gl);
  16076. shader.fragmentSrc = currentShader.fragmentSrc;
  16077. shader.uniforms = currentShader.uniforms;
  16078. shader.init();
  16079. currentShader.shaders[gl.id] = shader;
  16080. }
  16081. // set shader function???
  16082. this.renderSession.shaderManager.setShader(shader);
  16083. if (shader.dirty) {
  16084. shader.syncUniforms();
  16085. }
  16086. // both these only need to be set if they are changing..
  16087. // set the projection
  16088. var projection = this.renderSession.projection;
  16089. gl.uniform2f(shader.projectionVector, projection.x, projection.y);
  16090. // TODO - this is temporary!
  16091. var offsetVector = this.renderSession.offset;
  16092. gl.uniform2f(shader.offsetVector, offsetVector.x, offsetVector.y);
  16093. // set the pointers
  16094. }
  16095. }
  16096. batchSize++;
  16097. }
  16098. this.renderBatch(currentBaseTexture, batchSize, start);
  16099. // then reset the batch!
  16100. this.currentBatchSize = 0;
  16101. };
  16102. /**
  16103. * @method PIXI.WebGLSpriteBatch#renderBatch
  16104. * @param texture {Texture}
  16105. * @param size {Number}
  16106. * @param startIndex {Number}
  16107. */
  16108. PIXI.WebGLSpriteBatch.prototype.renderBatch = function (texture, size, startIndex) {
  16109. if (size === 0) {
  16110. return;
  16111. }
  16112. var gl = this.gl;
  16113. // check if a texture is dirty..
  16114. if (texture._dirty[gl.id]) {
  16115. if (!this.renderSession.renderer.updateTexture(texture)) {
  16116. // If updateTexture returns false then we cannot render it, so bail out now
  16117. return;
  16118. }
  16119. }else {
  16120. gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]);
  16121. }
  16122. gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2);
  16123. // increment the draw count
  16124. this.renderSession.drawCount++;
  16125. };
  16126. /**
  16127. * @method PIXI.WebGLSpriteBatch#stop
  16128. */
  16129. PIXI.WebGLSpriteBatch.prototype.stop = function () {
  16130. this.flush();
  16131. this.dirty = true;
  16132. };
  16133. /**
  16134. * @method PIXI.WebGLSpriteBatch#start
  16135. */
  16136. PIXI.WebGLSpriteBatch.prototype.start = function () {
  16137. this.dirty = true;
  16138. };
  16139. /**
  16140. * Destroys the SpriteBatch.
  16141. *
  16142. * @method PIXI.WebGLSpriteBatch#destroy
  16143. */
  16144. PIXI.WebGLSpriteBatch.prototype.destroy = function () {
  16145. this.vertices = null;
  16146. this.indices = null;
  16147. this.gl.deleteBuffer(this.vertexBuffer);
  16148. this.gl.deleteBuffer(this.indexBuffer);
  16149. this.currentBaseTexture = null;
  16150. this.gl = null;
  16151. };
  16152. /**
  16153. * @author Mat Groves
  16154. *
  16155. * Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/
  16156. * for creating the original pixi version!
  16157. *
  16158. * Heavily inspired by LibGDX's WebGLSpriteBatch:
  16159. * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
  16160. */
  16161. /**
  16162. * @class PIXI.WebGLFastSpriteBatch
  16163. * @constructor
  16164. */
  16165. PIXI.WebGLFastSpriteBatch = function(gl)
  16166. {
  16167. /**
  16168. * @property vertSize
  16169. * @type Number
  16170. */
  16171. this.vertSize = 11;
  16172. /**
  16173. * @property maxSize
  16174. * @type Number
  16175. */
  16176. this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize;
  16177. /**
  16178. * @property size
  16179. * @type Number
  16180. */
  16181. this.size = this.maxSize;
  16182. //the total number of floats in our batch
  16183. var numVerts = this.size * 4 * this.vertSize;
  16184. //the total number of indices in our batch
  16185. var numIndices = this.maxSize * 6;
  16186. /**
  16187. * Vertex data
  16188. * @property vertices
  16189. * @type Float32Array
  16190. */
  16191. this.vertices = new Float32Array(numVerts);
  16192. /**
  16193. * Index data
  16194. * @property indices
  16195. * @type Uint16Array
  16196. */
  16197. this.indices = new Uint16Array(numIndices);
  16198. /**
  16199. * @property vertexBuffer
  16200. * @type Object
  16201. */
  16202. this.vertexBuffer = null;
  16203. /**
  16204. * @property indexBuffer
  16205. * @type Object
  16206. */
  16207. this.indexBuffer = null;
  16208. /**
  16209. * @property lastIndexCount
  16210. * @type Number
  16211. */
  16212. this.lastIndexCount = 0;
  16213. for (var i=0, j=0; i < numIndices; i += 6, j += 4)
  16214. {
  16215. this.indices[i + 0] = j + 0;
  16216. this.indices[i + 1] = j + 1;
  16217. this.indices[i + 2] = j + 2;
  16218. this.indices[i + 3] = j + 0;
  16219. this.indices[i + 4] = j + 2;
  16220. this.indices[i + 5] = j + 3;
  16221. }
  16222. /**
  16223. * @property drawing
  16224. * @type Boolean
  16225. */
  16226. this.drawing = false;
  16227. /**
  16228. * @property currentBatchSize
  16229. * @type Number
  16230. */
  16231. this.currentBatchSize = 0;
  16232. /**
  16233. * @property currentBaseTexture
  16234. * @type BaseTexture
  16235. */
  16236. this.currentBaseTexture = null;
  16237. /**
  16238. * @property currentBlendMode
  16239. * @type Number
  16240. */
  16241. this.currentBlendMode = 0;
  16242. /**
  16243. * @property renderSession
  16244. * @type Object
  16245. */
  16246. this.renderSession = null;
  16247. /**
  16248. * @property shader
  16249. * @type Object
  16250. */
  16251. this.shader = null;
  16252. /**
  16253. * @property matrix
  16254. * @type Matrix
  16255. */
  16256. this.matrix = null;
  16257. this.setContext(gl);
  16258. };
  16259. PIXI.WebGLFastSpriteBatch.prototype.constructor = PIXI.WebGLFastSpriteBatch;
  16260. /**
  16261. * Sets the WebGL Context.
  16262. *
  16263. * @method PIXI.WebGLFastSpriteBatch#setContext
  16264. * @param gl {WebGLContext} the current WebGL drawing context
  16265. */
  16266. PIXI.WebGLFastSpriteBatch.prototype.setContext = function(gl)
  16267. {
  16268. this.gl = gl;
  16269. // create a couple of buffers
  16270. this.vertexBuffer = gl.createBuffer();
  16271. this.indexBuffer = gl.createBuffer();
  16272. // 65535 is max index, so 65535 / 6 = 10922.
  16273. //upload the index data
  16274. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  16275. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
  16276. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16277. gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
  16278. };
  16279. /**
  16280. * @method PIXI.WebGLFastSpriteBatch#begin
  16281. * @param spriteBatch {WebGLSpriteBatch}
  16282. * @param renderSession {Object}
  16283. */
  16284. PIXI.WebGLFastSpriteBatch.prototype.begin = function(spriteBatch, renderSession)
  16285. {
  16286. this.renderSession = renderSession;
  16287. this.shader = this.renderSession.shaderManager.fastShader;
  16288. this.matrix = spriteBatch.worldTransform.toArray(true);
  16289. this.start();
  16290. };
  16291. /**
  16292. * @method PIXI.WebGLFastSpriteBatch#end
  16293. */
  16294. PIXI.WebGLFastSpriteBatch.prototype.end = function()
  16295. {
  16296. this.flush();
  16297. };
  16298. /**
  16299. * @method PIXI.WebGLFastSpriteBatch#render
  16300. * @param spriteBatch {WebGLSpriteBatch}
  16301. */
  16302. PIXI.WebGLFastSpriteBatch.prototype.render = function (spriteBatch)
  16303. {
  16304. var children = spriteBatch.children;
  16305. var sprite = children[0];
  16306. // if the uvs have not updated then no point rendering just yet!
  16307. // check texture.
  16308. if(!sprite.texture._uvs)return;
  16309. this.currentBaseTexture = sprite.texture.baseTexture;
  16310. // check blend mode
  16311. if(sprite.blendMode !== this.renderSession.blendModeManager.currentBlendMode)
  16312. {
  16313. this.flush();
  16314. this.renderSession.blendModeManager.setBlendMode(sprite.blendMode);
  16315. }
  16316. for(var i=0,j= children.length; i<j; i++)
  16317. {
  16318. this.renderSprite(children[i]);
  16319. }
  16320. this.flush();
  16321. };
  16322. /**
  16323. * @method PIXI.WebGLFastSpriteBatch#renderSprite
  16324. * @param sprite {Sprite}
  16325. */
  16326. PIXI.WebGLFastSpriteBatch.prototype.renderSprite = function(sprite)
  16327. {
  16328. var texture = sprite.texture;
  16329. var baseTexture = texture.baseTexture;
  16330. var gl = this.gl;
  16331. var textureIndex = sprite.texture.baseTexture.textureIndex;
  16332. if (PIXI.WebGLRenderer.textureArray[textureIndex] != baseTexture &&
  16333. baseTexture._glTextures[gl.id] && !sprite.texture.baseTexture.skipRender) {
  16334. this.flush();
  16335. gl.activeTexture(gl.TEXTURE0 + textureIndex);
  16336. gl.bindTexture(gl.TEXTURE_2D, baseTexture._glTextures[gl.id]);
  16337. PIXI.WebGLRenderer.textureArray[textureIndex] = baseTexture;
  16338. if(!sprite.texture._uvs)return;
  16339. }
  16340. //sprite = children[i];
  16341. if(!sprite.visible)return;
  16342. var uvs, vertices = this.vertices, width, height, w0, w1, h0, h1, index;
  16343. uvs = sprite.texture._uvs;
  16344. width = sprite.texture.frame.width;
  16345. height = sprite.texture.frame.height;
  16346. if (sprite.texture.trim)
  16347. {
  16348. // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords..
  16349. var trim = sprite.texture.trim;
  16350. w1 = trim.x - sprite.anchor.x * trim.width;
  16351. w0 = w1 + sprite.texture.crop.width;
  16352. h1 = trim.y - sprite.anchor.y * trim.height;
  16353. h0 = h1 + sprite.texture.crop.height;
  16354. }
  16355. else
  16356. {
  16357. w0 = (sprite.texture.frame.width ) * (1-sprite.anchor.x);
  16358. w1 = (sprite.texture.frame.width ) * -sprite.anchor.x;
  16359. h0 = sprite.texture.frame.height * (1-sprite.anchor.y);
  16360. h1 = sprite.texture.frame.height * -sprite.anchor.y;
  16361. }
  16362. index = this.currentBatchSize * 4 * this.vertSize;
  16363. // xy
  16364. vertices[index++] = w1;
  16365. vertices[index++] = h1;
  16366. vertices[index++] = sprite.position.x;
  16367. vertices[index++] = sprite.position.y;
  16368. //scale
  16369. vertices[index++] = sprite.scale.x;
  16370. vertices[index++] = sprite.scale.y;
  16371. //rotation
  16372. vertices[index++] = sprite.rotation;
  16373. // uv
  16374. vertices[index++] = uvs.x0;
  16375. vertices[index++] = uvs.y1;
  16376. // color
  16377. vertices[index++] = sprite.alpha;
  16378. // texture Index
  16379. vertices[index++] = textureIndex;
  16380. // xy
  16381. vertices[index++] = w0;
  16382. vertices[index++] = h1;
  16383. vertices[index++] = sprite.position.x;
  16384. vertices[index++] = sprite.position.y;
  16385. //scale
  16386. vertices[index++] = sprite.scale.x;
  16387. vertices[index++] = sprite.scale.y;
  16388. //rotation
  16389. vertices[index++] = sprite.rotation;
  16390. // uv
  16391. vertices[index++] = uvs.x1;
  16392. vertices[index++] = uvs.y1;
  16393. // color
  16394. vertices[index++] = sprite.alpha;
  16395. // texture Index
  16396. vertices[index++] = textureIndex;
  16397. // xy
  16398. vertices[index++] = w0;
  16399. vertices[index++] = h0;
  16400. vertices[index++] = sprite.position.x;
  16401. vertices[index++] = sprite.position.y;
  16402. //scale
  16403. vertices[index++] = sprite.scale.x;
  16404. vertices[index++] = sprite.scale.y;
  16405. //rotation
  16406. vertices[index++] = sprite.rotation;
  16407. // uv
  16408. vertices[index++] = uvs.x2;
  16409. vertices[index++] = uvs.y2;
  16410. // color
  16411. vertices[index++] = sprite.alpha;
  16412. // texture Index
  16413. vertices[index++] = textureIndex;
  16414. // xy
  16415. vertices[index++] = w1;
  16416. vertices[index++] = h0;
  16417. vertices[index++] = sprite.position.x;
  16418. vertices[index++] = sprite.position.y;
  16419. //scale
  16420. vertices[index++] = sprite.scale.x;
  16421. vertices[index++] = sprite.scale.y;
  16422. //rotation
  16423. vertices[index++] = sprite.rotation;
  16424. // uv
  16425. vertices[index++] = uvs.x3;
  16426. vertices[index++] = uvs.y3;
  16427. // color
  16428. vertices[index++] = sprite.alpha;
  16429. // texture Index
  16430. vertices[index++] = textureIndex;
  16431. // increment the batchs
  16432. this.currentBatchSize++;
  16433. if(this.currentBatchSize >= this.size)
  16434. {
  16435. this.flush();
  16436. }
  16437. };
  16438. /**
  16439. * @method PIXI.WebGLFastSpriteBatch#flush
  16440. */
  16441. PIXI.WebGLFastSpriteBatch.prototype.flush = function()
  16442. {
  16443. // If the batch is length 0 then return as there is nothing to draw
  16444. if (this.currentBatchSize===0)return;
  16445. var gl = this.gl;
  16446. // bind the current texture
  16447. if(!this.currentBaseTexture._glTextures[gl.id]) {
  16448. this.renderSession.renderer.updateTexture(this.currentBaseTexture, gl);
  16449. return;
  16450. }
  16451. //gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]);
  16452. // upload the verts to the buffer
  16453. if(this.currentBatchSize > ( this.size * 0.5 ) )
  16454. {
  16455. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
  16456. }
  16457. else
  16458. {
  16459. var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize);
  16460. gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
  16461. }
  16462. // now draw those suckas!
  16463. gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0);
  16464. // then reset the batch!
  16465. this.currentBatchSize = 0;
  16466. // increment the draw count
  16467. this.renderSession.drawCount++;
  16468. };
  16469. /**
  16470. * @method PIXI.WebGLFastSpriteBatch#stop
  16471. */
  16472. PIXI.WebGLFastSpriteBatch.prototype.stop = function()
  16473. {
  16474. this.flush();
  16475. };
  16476. /**
  16477. * @method PIXI.WebGLFastSpriteBatch#start
  16478. */
  16479. PIXI.WebGLFastSpriteBatch.prototype.start = function()
  16480. {
  16481. var gl = this.gl;
  16482. // bind the main texture
  16483. gl.activeTexture(gl.TEXTURE0);
  16484. // bind the buffers
  16485. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16486. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  16487. // set the projection
  16488. var projection = this.renderSession.projection;
  16489. gl.uniform2f(this.shader.projectionVector, projection.x, projection.y);
  16490. // set the matrix
  16491. gl.uniformMatrix3fv(this.shader.uMatrix, false, this.matrix);
  16492. // set the pointers
  16493. var stride = this.vertSize * 4;
  16494. gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
  16495. gl.vertexAttribPointer(this.shader.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4);
  16496. gl.vertexAttribPointer(this.shader.aScale, 2, gl.FLOAT, false, stride, 4 * 4);
  16497. gl.vertexAttribPointer(this.shader.aRotation, 1, gl.FLOAT, false, stride, 6 * 4);
  16498. gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4);
  16499. gl.vertexAttribPointer(this.shader.colorAttribute, 1, gl.FLOAT, false, stride, 9 * 4);
  16500. gl.vertexAttribPointer(this.shader.aTextureIndex, 1, gl.FLOAT, false, stride, 10 * 4);
  16501. };
  16502. /**
  16503. * @author Mat Groves http://matgroves.com/ @Doormat23
  16504. */
  16505. /**
  16506. * @class PIXI.WebGLFilterManager
  16507. * @constructor
  16508. */
  16509. PIXI.WebGLFilterManager = function()
  16510. {
  16511. /**
  16512. * @property filterStack
  16513. * @type Array
  16514. */
  16515. this.filterStack = [];
  16516. /**
  16517. * @property offsetX
  16518. * @type Number
  16519. */
  16520. this.offsetX = 0;
  16521. /**
  16522. * @property offsetY
  16523. * @type Number
  16524. */
  16525. this.offsetY = 0;
  16526. };
  16527. PIXI.WebGLFilterManager.prototype.constructor = PIXI.WebGLFilterManager;
  16528. /**
  16529. * Initialises the context and the properties.
  16530. *
  16531. * @method PIXI.WebGLFilterManager#setContext
  16532. * @param gl {WebGLContext} the current WebGL drawing context
  16533. */
  16534. PIXI.WebGLFilterManager.prototype.setContext = function(gl)
  16535. {
  16536. this.gl = gl;
  16537. this.texturePool = [];
  16538. this.initShaderBuffers();
  16539. };
  16540. /**
  16541. * @method PIXI.WebGLFilterManager#begin
  16542. * @param renderSession {RenderSession}
  16543. * @param buffer {ArrayBuffer}
  16544. */
  16545. PIXI.WebGLFilterManager.prototype.begin = function(renderSession, buffer)
  16546. {
  16547. this.renderSession = renderSession;
  16548. this.defaultShader = renderSession.shaderManager.defaultShader;
  16549. var projection = this.renderSession.projection;
  16550. this.width = projection.x * 2;
  16551. this.height = -projection.y * 2;
  16552. this.buffer = buffer;
  16553. };
  16554. /**
  16555. * Applies the filter and adds it to the current filter stack.
  16556. *
  16557. * @method PIXI.WebGLFilterManager#pushFilter
  16558. * @param filterBlock {Object} the filter that will be pushed to the current filter stack
  16559. */
  16560. PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock)
  16561. {
  16562. var gl = this.gl;
  16563. var projection = this.renderSession.projection;
  16564. var offset = this.renderSession.offset;
  16565. filterBlock._filterArea = filterBlock.target.filterArea || filterBlock.target.getBounds();
  16566. // >>> modify by nextht
  16567. filterBlock._previous_stencil_mgr = this.renderSession.stencilManager;
  16568. this.renderSession.stencilManager = new PIXI.WebGLStencilManager();
  16569. this.renderSession.stencilManager.setContext(gl);
  16570. gl.disable(gl.STENCIL_TEST);
  16571. // <<< modify by nextht
  16572. // filter program
  16573. // OPTIMISATION - the first filter is free if its a simple color change?
  16574. this.filterStack.push(filterBlock);
  16575. var filter = filterBlock.filterPasses[0];
  16576. this.offsetX += filterBlock._filterArea.x;
  16577. this.offsetY += filterBlock._filterArea.y;
  16578. var texture = this.texturePool.pop();
  16579. if(!texture)
  16580. {
  16581. texture = new PIXI.FilterTexture(this.gl, this.width * this.renderSession.resolution, this.height * this.renderSession.resolution);
  16582. }
  16583. else
  16584. {
  16585. texture.resize(this.width * this.renderSession.resolution, this.height * this.renderSession.resolution);
  16586. }
  16587. gl.bindTexture(gl.TEXTURE_2D, texture.texture);
  16588. var filterArea = filterBlock._filterArea;// filterBlock.target.getBounds();///filterBlock.target.filterArea;
  16589. var padding = filter.padding;
  16590. filterArea.x -= padding;
  16591. filterArea.y -= padding;
  16592. filterArea.width += padding * 2;
  16593. filterArea.height += padding * 2;
  16594. // cap filter to screen size..
  16595. if(filterArea.x < 0)filterArea.x = 0;
  16596. if(filterArea.width > this.width)filterArea.width = this.width;
  16597. if(filterArea.y < 0)filterArea.y = 0;
  16598. if(filterArea.height > this.height)filterArea.height = this.height;
  16599. //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  16600. gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer);
  16601. // set view port
  16602. gl.viewport(0, 0, filterArea.width * this.renderSession.resolution, filterArea.height * this.renderSession.resolution);
  16603. projection.x = filterArea.width/2;
  16604. projection.y = -filterArea.height/2;
  16605. offset.x = -filterArea.x;
  16606. offset.y = -filterArea.y;
  16607. // update projection
  16608. // now restore the regular shader..
  16609. // this.renderSession.shaderManager.setShader(this.defaultShader);
  16610. //gl.uniform2f(this.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2);
  16611. //gl.uniform2f(this.defaultShader.offsetVector, -filterArea.x, -filterArea.y);
  16612. gl.colorMask(true, true, true, true);
  16613. gl.clearColor(0,0,0, 0);
  16614. gl.clear(gl.COLOR_BUFFER_BIT);
  16615. filterBlock._glFilterTexture = texture;
  16616. };
  16617. /**
  16618. * Removes the last filter from the filter stack and doesn't return it.
  16619. *
  16620. * @method PIXI.WebGLFilterManager#popFilter
  16621. */
  16622. PIXI.WebGLFilterManager.prototype.popFilter = function()
  16623. {
  16624. var gl = this.gl;
  16625. var filterBlock = this.filterStack.pop();
  16626. var filterArea = filterBlock._filterArea;
  16627. var texture = filterBlock._glFilterTexture;
  16628. var projection = this.renderSession.projection;
  16629. var offset = this.renderSession.offset;
  16630. if(filterBlock.filterPasses.length > 1)
  16631. {
  16632. gl.viewport(0, 0, filterArea.width * this.renderSession.resolution, filterArea.height * this.renderSession.resolution);
  16633. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16634. this.vertexArray[0] = 0;
  16635. this.vertexArray[1] = filterArea.height;
  16636. this.vertexArray[2] = filterArea.width;
  16637. this.vertexArray[3] = filterArea.height;
  16638. this.vertexArray[4] = 0;
  16639. this.vertexArray[5] = 0;
  16640. this.vertexArray[6] = filterArea.width;
  16641. this.vertexArray[7] = 0;
  16642. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray);
  16643. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  16644. // now set the uvs..
  16645. this.uvArray[2] = filterArea.width/this.width;
  16646. this.uvArray[5] = filterArea.height/this.height;
  16647. this.uvArray[6] = filterArea.width/this.width;
  16648. this.uvArray[7] = filterArea.height/this.height;
  16649. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray);
  16650. var inputTexture = texture;
  16651. var outputTexture = this.texturePool.pop();
  16652. if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.gl, this.width * this.renderSession.resolution, this.height * this.renderSession.resolution);
  16653. outputTexture.resize(this.width * this.renderSession.resolution, this.height * this.renderSession.resolution);
  16654. // need to clear this FBO as it may have some left over elements from a previous filter.
  16655. gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer );
  16656. gl.clear(gl.COLOR_BUFFER_BIT);
  16657. gl.disable(gl.BLEND);
  16658. for (var i = 0; i < filterBlock.filterPasses.length-1; i++)
  16659. {
  16660. var filterPass = filterBlock.filterPasses[i];
  16661. gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer );
  16662. // set texture
  16663. gl.activeTexture(gl.TEXTURE0);
  16664. gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture);
  16665. // draw texture..
  16666. //filterPass.applyFilterPass(filterArea.width, filterArea.height);
  16667. this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height);
  16668. // swap the textures..
  16669. var temp = inputTexture;
  16670. inputTexture = outputTexture;
  16671. outputTexture = temp;
  16672. }
  16673. gl.enable(gl.BLEND);
  16674. texture = inputTexture;
  16675. this.texturePool.push(outputTexture);
  16676. }
  16677. var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1];
  16678. this.offsetX -= filterArea.x;
  16679. this.offsetY -= filterArea.y;
  16680. var sizeX = this.width;
  16681. var sizeY = this.height;
  16682. var offsetX = 0;
  16683. var offsetY = 0;
  16684. var buffer = this.buffer;
  16685. // time to render the filters texture to the previous scene
  16686. if(this.filterStack.length === 0)
  16687. {
  16688. gl.colorMask(true, true, true, true);//this.transparent);
  16689. }
  16690. else
  16691. {
  16692. var currentFilter = this.filterStack[this.filterStack.length-1];
  16693. filterArea = currentFilter._filterArea;
  16694. sizeX = filterArea.width;
  16695. sizeY = filterArea.height;
  16696. offsetX = filterArea.x;
  16697. offsetY = filterArea.y;
  16698. buffer = currentFilter._glFilterTexture.frameBuffer;
  16699. }
  16700. // TODO need to remove these global elements..
  16701. projection.x = sizeX/2;
  16702. projection.y = -sizeY/2;
  16703. offset.x = offsetX;
  16704. offset.y = offsetY;
  16705. filterArea = filterBlock._filterArea;
  16706. var x = filterArea.x-offsetX;
  16707. var y = filterArea.y-offsetY;
  16708. // update the buffers..
  16709. // make sure to flip the y!
  16710. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16711. this.vertexArray[0] = x;
  16712. this.vertexArray[1] = y + filterArea.height;
  16713. this.vertexArray[2] = x + filterArea.width;
  16714. this.vertexArray[3] = y + filterArea.height;
  16715. this.vertexArray[4] = x;
  16716. this.vertexArray[5] = y;
  16717. this.vertexArray[6] = x + filterArea.width;
  16718. this.vertexArray[7] = y;
  16719. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray);
  16720. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  16721. this.uvArray[2] = filterArea.width/this.width;
  16722. this.uvArray[5] = filterArea.height/this.height;
  16723. this.uvArray[6] = filterArea.width/this.width;
  16724. this.uvArray[7] = filterArea.height/this.height;
  16725. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray);
  16726. gl.viewport(0, 0, sizeX * this.renderSession.resolution, sizeY * this.renderSession.resolution);
  16727. // bind the buffer
  16728. gl.bindFramebuffer(gl.FRAMEBUFFER, buffer );
  16729. // set the blend mode!
  16730. //gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
  16731. // set texture
  16732. gl.activeTexture(gl.TEXTURE0);
  16733. gl.bindTexture(gl.TEXTURE_2D, texture.texture);
  16734. // >>> modify by nextht
  16735. if (this.renderSession.stencilManager) {
  16736. this.renderSession.stencilManager.destroy();
  16737. }
  16738. this.renderSession.stencilManager = filterBlock._previous_stencil_mgr;
  16739. filterBlock._previous_stencil_mgr = null;
  16740. if (this.renderSession.stencilManager.count > 0) {
  16741. gl.enable(gl.STENCIL_TEST);
  16742. }
  16743. else {
  16744. gl.disable(gl.STENCIL_TEST);
  16745. }
  16746. // <<< modify by nextht
  16747. // apply!
  16748. this.applyFilterPass(filter, filterArea, sizeX, sizeY);
  16749. // now restore the regular shader.. should happen automatically now..
  16750. // this.renderSession.shaderManager.setShader(this.defaultShader);
  16751. // gl.uniform2f(this.defaultShader.projectionVector, sizeX/2, -sizeY/2);
  16752. // gl.uniform2f(this.defaultShader.offsetVector, -offsetX, -offsetY);
  16753. // return the texture to the pool
  16754. this.texturePool.push(texture);
  16755. filterBlock._glFilterTexture = null;
  16756. };
  16757. /**
  16758. * Applies the filter to the specified area.
  16759. *
  16760. * @method PIXI.WebGLFilterManager#applyFilterPass
  16761. * @param filter {Phaser.Filter} the filter that needs to be applied
  16762. * @param filterArea {Texture} TODO - might need an update
  16763. * @param width {Number} the horizontal range of the filter
  16764. * @param height {Number} the vertical range of the filter
  16765. */
  16766. PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height)
  16767. {
  16768. // use program
  16769. var gl = this.gl;
  16770. var shader = filter.shaders[gl.id];
  16771. if(!shader)
  16772. {
  16773. shader = new PIXI.PixiShader(gl);
  16774. shader.fragmentSrc = filter.fragmentSrc;
  16775. shader.uniforms = filter.uniforms;
  16776. shader.init(true);
  16777. filter.shaders[gl.id] = shader;
  16778. }
  16779. // set the shader
  16780. this.renderSession.shaderManager.setShader(shader);
  16781. // gl.useProgram(shader.program);
  16782. gl.uniform2f(shader.projectionVector, width/2, -height/2);
  16783. gl.uniform2f(shader.offsetVector, 0,0);
  16784. if(filter.uniforms.dimensions)
  16785. {
  16786. filter.uniforms.dimensions.value[0] = this.width;//width;
  16787. filter.uniforms.dimensions.value[1] = this.height;//height;
  16788. filter.uniforms.dimensions.value[2] = this.vertexArray[0];
  16789. filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height;
  16790. }
  16791. shader.syncUniforms();
  16792. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16793. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
  16794. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  16795. gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
  16796. gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
  16797. gl.vertexAttribPointer(shader.colorAttribute, 2, gl.FLOAT, false, 0, 0);
  16798. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  16799. // draw the filter...
  16800. gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
  16801. this.renderSession.drawCount++;
  16802. };
  16803. /**
  16804. * Initialises the shader buffers.
  16805. *
  16806. * @method PIXI.WebGLFilterManager#initShaderBuffers
  16807. */
  16808. PIXI.WebGLFilterManager.prototype.initShaderBuffers = function()
  16809. {
  16810. var gl = this.gl;
  16811. // create some buffers
  16812. this.vertexBuffer = gl.createBuffer();
  16813. this.uvBuffer = gl.createBuffer();
  16814. this.colorBuffer = gl.createBuffer();
  16815. this.indexBuffer = gl.createBuffer();
  16816. // bind and upload the vertexs..
  16817. // keep a reference to the vertexFloatData..
  16818. this.vertexArray = new Float32Array([0.0, 0.0,
  16819. 1.0, 0.0,
  16820. 0.0, 1.0,
  16821. 1.0, 1.0]);
  16822. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
  16823. gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW);
  16824. // bind and upload the uv buffer
  16825. this.uvArray = new Float32Array([0.0, 0.0,
  16826. 1.0, 0.0,
  16827. 0.0, 1.0,
  16828. 1.0, 1.0]);
  16829. gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
  16830. gl.bufferData(gl.ARRAY_BUFFER, this.uvArray, gl.STATIC_DRAW);
  16831. this.colorArray = new Float32Array([1.0, 0xFFFFFF,
  16832. 1.0, 0xFFFFFF,
  16833. 1.0, 0xFFFFFF,
  16834. 1.0, 0xFFFFFF]);
  16835. gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
  16836. gl.bufferData(gl.ARRAY_BUFFER, this.colorArray, gl.STATIC_DRAW);
  16837. // bind and upload the index
  16838. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  16839. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 1, 3, 2]), gl.STATIC_DRAW);
  16840. };
  16841. /**
  16842. * Destroys the filter and removes it from the filter stack.
  16843. *
  16844. * @method PIXI.WebGLFilterManager#destroy
  16845. */
  16846. PIXI.WebGLFilterManager.prototype.destroy = function()
  16847. {
  16848. var gl = this.gl;
  16849. this.filterStack = null;
  16850. this.offsetX = 0;
  16851. this.offsetY = 0;
  16852. // destroy textures
  16853. for (var i = 0; i < this.texturePool.length; i++) {
  16854. this.texturePool[i].destroy();
  16855. }
  16856. this.texturePool = null;
  16857. //destroy buffers..
  16858. gl.deleteBuffer(this.vertexBuffer);
  16859. gl.deleteBuffer(this.uvBuffer);
  16860. gl.deleteBuffer(this.colorBuffer);
  16861. gl.deleteBuffer(this.indexBuffer);
  16862. };
  16863. /**
  16864. * @author Mat Groves http://matgroves.com/ @Doormat23
  16865. */
  16866. /**
  16867. * @private
  16868. */
  16869. function _CreateEmptyTexture(gl, width, height, scaleMode) {
  16870. var texture = gl.createTexture();
  16871. gl.bindTexture(gl.TEXTURE_2D, texture);
  16872. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  16873. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  16874. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  16875. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
  16876. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  16877. return texture;
  16878. }
  16879. /**
  16880. * @private
  16881. */
  16882. var _fbErrors = {
  16883. 36054: 'Incomplete attachment',
  16884. 36055: 'Missing attachment',
  16885. 36057: 'Incomplete dimensions',
  16886. 36061: 'Framebuffer unsupported'
  16887. };
  16888. /**
  16889. * @private
  16890. */
  16891. function _CreateFramebuffer(gl, width, height, scaleMode, textureUnit) {
  16892. var framebuffer = gl.createFramebuffer();
  16893. var depthStencilBuffer = gl.createRenderbuffer();
  16894. var colorBuffer = null;
  16895. var fbStatus = 0;
  16896. gl.activeTexture(gl.TEXTURE0 + textureUnit);
  16897. gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
  16898. gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
  16899. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer);
  16900. colorBuffer = _CreateEmptyTexture(gl, width, height, scaleMode);
  16901. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorBuffer, 0);
  16902. fbStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  16903. if(fbStatus !== gl.FRAMEBUFFER_COMPLETE) {
  16904. console.error('Incomplete GL framebuffer. ', _fbErrors[fbStatus]);
  16905. }
  16906. framebuffer.width = width;
  16907. framebuffer.height = height;
  16908. framebuffer.targetTexture = colorBuffer;
  16909. framebuffer.renderBuffer = depthStencilBuffer;
  16910. return framebuffer;
  16911. }
  16912. /**
  16913. * @class PIXI.FilterTexture
  16914. * @constructor
  16915. * @param gl {WebGLContext} the current WebGL drawing context
  16916. * @param width {Number} the horizontal range of the filter
  16917. * @param height {Number} the vertical range of the filter
  16918. * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values
  16919. */
  16920. PIXI.FilterTexture = function(gl, width, height, scaleMode, textureUnit)
  16921. {
  16922. textureUnit = typeof textureUnit === 'number' ? textureUnit : 0;
  16923. /**
  16924. * @property gl
  16925. * @type WebGLContext
  16926. */
  16927. this.gl = gl;
  16928. // next time to create a frame buffer and texture
  16929. /**
  16930. * @property frameBuffer
  16931. * @type Any
  16932. */
  16933. this.frameBuffer = _CreateFramebuffer(gl, width, height, scaleMode || PIXI.scaleModes.DEFAULT, textureUnit);
  16934. /**
  16935. * @property texture
  16936. * @type Any
  16937. */
  16938. this.texture = this.frameBuffer.targetTexture;
  16939. this.width = width;
  16940. this.height = height;
  16941. this.renderBuffer = this.frameBuffer.renderBuffer;
  16942. };
  16943. PIXI.FilterTexture.prototype.constructor = PIXI.FilterTexture;
  16944. /**
  16945. * Clears the filter texture.
  16946. *
  16947. * @method PIXI.FilterTexture#clear
  16948. */
  16949. PIXI.FilterTexture.prototype.clear = function()
  16950. {
  16951. var gl = this.gl;
  16952. gl.clearColor(0,0,0, 0);
  16953. gl.clear(gl.COLOR_BUFFER_BIT);
  16954. };
  16955. /**
  16956. * Resizes the texture to the specified width and height
  16957. *
  16958. * @method PIXI.FilterTexture#resize
  16959. * @param width {Number} the new width of the texture
  16960. * @param height {Number} the new height of the texture
  16961. */
  16962. PIXI.FilterTexture.prototype.resize = function(width, height)
  16963. {
  16964. if(this.width === width && this.height === height) return;
  16965. this.width = width;
  16966. this.height = height;
  16967. var gl = this.gl;
  16968. gl.bindTexture(gl.TEXTURE_2D, this.texture);
  16969. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  16970. // update the stencil buffer width and height
  16971. gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer);
  16972. gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height );
  16973. };
  16974. /**
  16975. * Destroys the filter texture.
  16976. *
  16977. * @method PIXI.FilterTexture#destroy
  16978. */
  16979. PIXI.FilterTexture.prototype.destroy = function()
  16980. {
  16981. var gl = this.gl;
  16982. gl.deleteFramebuffer( this.frameBuffer );
  16983. gl.deleteTexture( this.texture );
  16984. this.frameBuffer = null;
  16985. this.texture = null;
  16986. };
  16987. /**
  16988. * @author Mat Groves http://matgroves.com/ @Doormat23
  16989. */
  16990. /**
  16991. * Creates a Canvas element of the given size.
  16992. *
  16993. * @class PIXI.CanvasBuffer
  16994. * @constructor
  16995. * @param width {Number} the width for the newly created canvas
  16996. * @param height {Number} the height for the newly created canvas
  16997. */
  16998. PIXI.CanvasBuffer = function(width, height)
  16999. {
  17000. /**
  17001. * The width of the Canvas in pixels.
  17002. *
  17003. * @property width
  17004. * @type Number
  17005. */
  17006. this.width = width;
  17007. /**
  17008. * The height of the Canvas in pixels.
  17009. *
  17010. * @property height
  17011. * @type Number
  17012. */
  17013. this.height = height;
  17014. /**
  17015. * The Canvas object that belongs to this CanvasBuffer.
  17016. *
  17017. * @property canvas
  17018. * @type HTMLCanvasElement
  17019. */
  17020. this.canvas = Phaser.CanvasPool.create(this, this.width, this.height);
  17021. /**
  17022. * A CanvasRenderingContext2D object representing a two-dimensional rendering context.
  17023. *
  17024. * @property context
  17025. * @type CanvasRenderingContext2D
  17026. */
  17027. this.context = this.canvas.getContext("2d");
  17028. this.canvas.width = width;
  17029. this.canvas.height = height;
  17030. };
  17031. PIXI.CanvasBuffer.prototype.constructor = PIXI.CanvasBuffer;
  17032. /**
  17033. * Clears the canvas that was created by the CanvasBuffer class.
  17034. *
  17035. * @method PIXI.CanvasBuffer#clear
  17036. * @private
  17037. */
  17038. PIXI.CanvasBuffer.prototype.clear = function()
  17039. {
  17040. this.context.setTransform(1, 0, 0, 1, 0, 0);
  17041. this.context.clearRect(0,0, this.width, this.height);
  17042. };
  17043. /**
  17044. * Resizes the canvas to the specified width and height.
  17045. *
  17046. * @method PIXI.CanvasBuffer#resize
  17047. * @param width {Number} the new width of the canvas
  17048. * @param height {Number} the new height of the canvas
  17049. */
  17050. PIXI.CanvasBuffer.prototype.resize = function(width, height)
  17051. {
  17052. this.width = this.canvas.width = width;
  17053. this.height = this.canvas.height = height;
  17054. };
  17055. /**
  17056. * Frees the canvas up for use again.
  17057. *
  17058. * @method PIXI.CanvasBuffer#destroy
  17059. */
  17060. PIXI.CanvasBuffer.prototype.destroy = function()
  17061. {
  17062. Phaser.CanvasPool.remove(this);
  17063. };
  17064. /**
  17065. * @author Mat Groves http://matgroves.com/ @Doormat23
  17066. */
  17067. /**
  17068. * A set of functions used to handle masking.
  17069. *
  17070. * @class PIXI.CanvasMaskManager
  17071. * @constructor
  17072. */
  17073. PIXI.CanvasMaskManager = function()
  17074. {
  17075. };
  17076. PIXI.CanvasMaskManager.prototype.constructor = PIXI.CanvasMaskManager;
  17077. /**
  17078. * This method adds it to the current stack of masks.
  17079. *
  17080. * @method PIXI.CanvasMaskManager#pushMask
  17081. * @param maskData {Object} the maskData that will be pushed
  17082. * @param renderSession {Object} The renderSession whose context will be used for this mask manager.
  17083. */
  17084. PIXI.CanvasMaskManager.prototype.pushMask = function(maskData, renderSession) {
  17085. var context = renderSession.context;
  17086. context.save();
  17087. var cacheAlpha = maskData.alpha;
  17088. var transform = maskData.worldTransform;
  17089. var resolution = renderSession.resolution;
  17090. context.setTransform(transform.a * resolution,
  17091. transform.b * resolution,
  17092. transform.c * resolution,
  17093. transform.d * resolution,
  17094. transform.tx * resolution,
  17095. transform.ty * resolution);
  17096. PIXI.CanvasGraphics.renderGraphicsMask(maskData, context);
  17097. context.clip();
  17098. maskData.worldAlpha = cacheAlpha;
  17099. };
  17100. /**
  17101. * Restores the current drawing context to the state it was before the mask was applied.
  17102. *
  17103. * @method PIXI.CanvasMaskManager#popMask
  17104. * @param renderSession {Object} The renderSession whose context will be used for this mask manager.
  17105. */
  17106. PIXI.CanvasMaskManager.prototype.popMask = function(renderSession)
  17107. {
  17108. renderSession.context.restore();
  17109. };
  17110. /**
  17111. * @author Mat Groves http://matgroves.com/ @Doormat23
  17112. */
  17113. /**
  17114. * Utility methods for Sprite/Texture tinting.
  17115. *
  17116. * @class PIXI.CanvasTinter
  17117. * @static
  17118. */
  17119. PIXI.CanvasTinter = function() {};
  17120. /**
  17121. * Basically this method just needs a sprite and a color and tints the sprite with the given color.
  17122. *
  17123. * @method PIXI.CanvasTinter#getTintedTexture
  17124. * @static
  17125. * @param sprite {Sprite} the sprite to tint
  17126. * @param color {Number} the color to use to tint the sprite with
  17127. * @return {HTMLCanvasElement} The tinted canvas
  17128. */
  17129. PIXI.CanvasTinter.getTintedTexture = function(sprite, color)
  17130. {
  17131. var canvas = sprite.tintedTexture || Phaser.CanvasPool.create(this);
  17132. PIXI.CanvasTinter.tintMethod(sprite.texture, color, canvas);
  17133. return canvas;
  17134. };
  17135. /**
  17136. * Tint a texture using the "multiply" operation.
  17137. *
  17138. * @method PIXI.CanvasTinter#tintWithMultiply
  17139. * @static
  17140. * @param texture {Texture} the texture to tint
  17141. * @param color {Number} the color to use to tint the sprite with
  17142. * @param canvas {HTMLCanvasElement} the current canvas
  17143. */
  17144. PIXI.CanvasTinter.tintWithMultiply = function(texture, color, canvas)
  17145. {
  17146. var context = canvas.getContext("2d");
  17147. var crop = texture.crop;
  17148. var w = crop.width;
  17149. var h = crop.height;
  17150. if (texture.rotated)
  17151. {
  17152. w = h;
  17153. h = crop.width;
  17154. }
  17155. if (canvas.width !== w || canvas.height !== h)
  17156. {
  17157. canvas.width = w;
  17158. canvas.height = h;
  17159. }
  17160. context.clearRect(0, 0, w, h);
  17161. context.fillStyle = "#" + ("00000" + (color | 0).toString(16)).substr(-6);
  17162. context.fillRect(0, 0, w, h);
  17163. context.globalCompositeOperation = "multiply";
  17164. context.drawImage(texture.baseTexture.source, crop.x, crop.y, w, h, 0, 0, w, h);
  17165. context.globalCompositeOperation = "destination-atop";
  17166. context.drawImage(texture.baseTexture.source, crop.x, crop.y, w, h, 0, 0, w, h);
  17167. };
  17168. /**
  17169. * Tint a texture pixel per pixel.
  17170. *
  17171. * @method PIXI.CanvasTinter#tintPerPixel
  17172. * @static
  17173. * @param texture {Texture} the texture to tint
  17174. * @param color {Number} the color to use to tint the sprite with
  17175. * @param canvas {HTMLCanvasElement} the current canvas
  17176. */
  17177. PIXI.CanvasTinter.tintWithPerPixel = function(texture, color, canvas)
  17178. {
  17179. var context = canvas.getContext("2d");
  17180. var crop = texture.crop;
  17181. var w = crop.width;
  17182. var h = crop.height;
  17183. if (texture.rotated)
  17184. {
  17185. w = h;
  17186. h = crop.width;
  17187. }
  17188. if (canvas.width !== w || canvas.height !== h)
  17189. {
  17190. canvas.width = w;
  17191. canvas.height = h;
  17192. }
  17193. context.globalCompositeOperation = "copy";
  17194. context.drawImage(texture.baseTexture.source, crop.x, crop.y, w, h, 0, 0, w, h);
  17195. var rgbValues = Phaser.Color.hexToRGBArray(color);
  17196. var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2];
  17197. var pixelData = context.getImageData(0, 0, w, h);
  17198. var pixels = pixelData.data;
  17199. for (var i = 0; i < pixels.length; i += 4)
  17200. {
  17201. pixels[i + 0] *= r;
  17202. pixels[i + 1] *= g;
  17203. pixels[i + 2] *= b;
  17204. if (!PIXI.CanvasTinter.canHandleAlpha)
  17205. {
  17206. var alpha = pixels[i + 3];
  17207. pixels[i + 0] /= 255 / alpha;
  17208. pixels[i + 1] /= 255 / alpha;
  17209. pixels[i + 2] /= 255 / alpha;
  17210. }
  17211. }
  17212. context.putImageData(pixelData, 0, 0);
  17213. };
  17214. /**
  17215. * @author Mat Groves http://matgroves.com/ @Doormat23
  17216. */
  17217. /**
  17218. * The CanvasRenderer draws the Stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL.
  17219. * Don't forget to add the CanvasRenderer.view to your DOM or you will not see anything :)
  17220. *
  17221. * @class PIXI.CanvasRenderer
  17222. * @constructor
  17223. * @param game {Phaser.Game} A reference to the Phaser Game instance
  17224. */
  17225. PIXI.CanvasRenderer = function (game) {
  17226. /**
  17227. * @property {Phaser.Game} game - A reference to the Phaser Game instance.
  17228. */
  17229. this.game = game;
  17230. if (!PIXI.defaultRenderer)
  17231. {
  17232. PIXI.defaultRenderer = this;
  17233. }
  17234. /**
  17235. * The renderer type.
  17236. *
  17237. * @property type
  17238. * @type Number
  17239. */
  17240. this.type = Phaser.CANVAS;
  17241. /**
  17242. * The resolution of the canvas.
  17243. *
  17244. * @property resolution
  17245. * @type Number
  17246. */
  17247. this.resolution = game.resolution;
  17248. /**
  17249. * This sets if the CanvasRenderer will clear the canvas or not before the new render pass.
  17250. * If the Stage is NOT transparent Pixi will use a canvas sized fillRect operation every frame to set the canvas background color.
  17251. * If the Stage is transparent Pixi will use clearRect to clear the canvas every frame.
  17252. * Disable this by setting this to false. For example if your game has a canvas filling background image you often don't need this set.
  17253. *
  17254. * @property clearBeforeRender
  17255. * @type Boolean
  17256. * @default
  17257. */
  17258. this.clearBeforeRender = game.clearBeforeRender;
  17259. /**
  17260. * Whether the render view is transparent
  17261. *
  17262. * @property transparent
  17263. * @type Boolean
  17264. */
  17265. this.transparent = game.transparent;
  17266. /**
  17267. * Whether the render view should be resized automatically
  17268. *
  17269. * @property autoResize
  17270. * @type Boolean
  17271. */
  17272. this.autoResize = false;
  17273. /**
  17274. * The width of the canvas view
  17275. *
  17276. * @property width
  17277. * @type Number
  17278. * @default 800
  17279. */
  17280. this.width = game.width * this.resolution;
  17281. /**
  17282. * The height of the canvas view
  17283. *
  17284. * @property height
  17285. * @type Number
  17286. * @default 600
  17287. */
  17288. this.height = game.height * this.resolution;
  17289. /**
  17290. * The canvas element that everything is drawn to.
  17291. *
  17292. * @property view
  17293. * @type HTMLCanvasElement
  17294. */
  17295. this.view = game.canvas;
  17296. /**
  17297. * The canvas 2d context that everything is drawn with
  17298. * @property context
  17299. * @type CanvasRenderingContext2D
  17300. */
  17301. this.context = this.view.getContext("2d", { alpha: this.transparent } );
  17302. /**
  17303. * Boolean flag controlling canvas refresh.
  17304. *
  17305. * @property refresh
  17306. * @type Boolean
  17307. */
  17308. this.refresh = true;
  17309. /**
  17310. * Internal var.
  17311. *
  17312. * @property count
  17313. * @type Number
  17314. */
  17315. this.count = 0;
  17316. /**
  17317. * Instance of a PIXI.CanvasMaskManager, handles masking when using the canvas renderer
  17318. * @property CanvasMaskManager
  17319. * @type CanvasMaskManager
  17320. */
  17321. this.maskManager = new PIXI.CanvasMaskManager();
  17322. /**
  17323. * The render session is just a bunch of parameter used for rendering
  17324. * @property renderSession
  17325. * @type Object
  17326. */
  17327. this.renderSession = {
  17328. context: this.context,
  17329. maskManager: this.maskManager,
  17330. scaleMode: null,
  17331. smoothProperty: Phaser.Canvas.getSmoothingPrefix(this.context),
  17332. /**
  17333. * If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation.
  17334. * Handy for crisp pixel art and speed on legacy devices.
  17335. */
  17336. roundPixels: false
  17337. };
  17338. this.mapBlendModes();
  17339. this.resize(this.width, this.height);
  17340. };
  17341. // constructor
  17342. PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer;
  17343. /**
  17344. * Renders the DisplayObjectContainer, usually the Phaser.Stage, to this canvas view.
  17345. *
  17346. * @method PIXI.CanvasRenderer#render
  17347. * @param root {Phaser.Stage|PIXI.DisplayObjectContainer} The root element to be rendered.
  17348. */
  17349. PIXI.CanvasRenderer.prototype.render = function (root) {
  17350. this.context.setTransform(1, 0, 0, 1, 0, 0);
  17351. this.context.globalAlpha = 1;
  17352. this.renderSession.currentBlendMode = 0;
  17353. this.renderSession.shakeX = this.game.camera._shake.x;
  17354. this.renderSession.shakeY = this.game.camera._shake.y;
  17355. this.context.globalCompositeOperation = 'source-over';
  17356. if (navigator.isCocoonJS && this.view.screencanvas)
  17357. {
  17358. this.context.fillStyle = "black";
  17359. this.context.clear();
  17360. }
  17361. if (this.clearBeforeRender)
  17362. {
  17363. if (this.transparent)
  17364. {
  17365. this.context.clearRect(0, 0, this.width, this.height);
  17366. }
  17367. else if (root._bgColor)
  17368. {
  17369. this.context.fillStyle = root._bgColor.rgba;
  17370. this.context.fillRect(0, 0, this.width , this.height);
  17371. }
  17372. }
  17373. this.renderDisplayObject(root);
  17374. };
  17375. PIXI.CanvasRenderer.prototype.setTexturePriority = function (textureNameCollection) {
  17376. // Does nothing on Canvas, but here to allow you to simply set
  17377. // `game.renderer.setTexturePriority()` without having to worry about
  17378. // running in WebGL or not.
  17379. };
  17380. /**
  17381. * Removes everything from the renderer and optionally removes the Canvas DOM element.
  17382. *
  17383. * @method PIXI.CanvasRenderer#destroy
  17384. * @param [removeView=true] {boolean} Removes the Canvas element from the DOM.
  17385. */
  17386. PIXI.CanvasRenderer.prototype.destroy = function (removeView) {
  17387. if (removeView === undefined) { removeView = true; }
  17388. if (removeView && this.view.parent)
  17389. {
  17390. this.view.parent.removeChild(this.view);
  17391. }
  17392. this.view = null;
  17393. this.context = null;
  17394. this.maskManager = null;
  17395. this.renderSession = null;
  17396. };
  17397. /**
  17398. * Resizes the canvas view to the specified width and height
  17399. *
  17400. * @method PIXI.CanvasRenderer#resize
  17401. * @param width {Number} the new width of the canvas view
  17402. * @param height {Number} the new height of the canvas view
  17403. */
  17404. PIXI.CanvasRenderer.prototype.resize = function (width, height) {
  17405. this.width = width * this.resolution;
  17406. this.height = height * this.resolution;
  17407. this.view.width = this.width;
  17408. this.view.height = this.height;
  17409. if (this.autoResize)
  17410. {
  17411. this.view.style.width = this.width / this.resolution + "px";
  17412. this.view.style.height = this.height / this.resolution + "px";
  17413. }
  17414. if (this.renderSession.smoothProperty)
  17415. {
  17416. this.context[this.renderSession.smoothProperty] = (this.renderSession.scaleMode === PIXI.scaleModes.LINEAR);
  17417. }
  17418. };
  17419. /**
  17420. * Renders a display object
  17421. *
  17422. * @method PIXI.CanvasRenderer#renderDisplayObject
  17423. * @param displayObject {DisplayObject} The displayObject to render
  17424. * @param context {CanvasRenderingContext2D} the context 2d method of the canvas
  17425. * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
  17426. * @private
  17427. */
  17428. PIXI.CanvasRenderer.prototype.renderDisplayObject = function (displayObject, context, matrix) {
  17429. this.renderSession.context = context || this.context;
  17430. this.renderSession.resolution = this.resolution;
  17431. displayObject._renderCanvas(this.renderSession, matrix);
  17432. };
  17433. /**
  17434. * Maps Pixi blend modes to canvas blend modes.
  17435. *
  17436. * @method PIXI.CanvasRenderer#mapBlendModes
  17437. * @private
  17438. */
  17439. PIXI.CanvasRenderer.prototype.mapBlendModes = function () {
  17440. if (!PIXI.blendModesCanvas)
  17441. {
  17442. var b = [];
  17443. var modes = PIXI.blendModes;
  17444. var useNew = this.game.device.canUseMultiply;
  17445. b[modes.NORMAL] = 'source-over';
  17446. b[modes.ADD] = 'lighter';
  17447. b[modes.MULTIPLY] = (useNew) ? 'multiply' : 'source-over';
  17448. b[modes.SCREEN] = (useNew) ? 'screen' : 'source-over';
  17449. b[modes.OVERLAY] = (useNew) ? 'overlay' : 'source-over';
  17450. b[modes.DARKEN] = (useNew) ? 'darken' : 'source-over';
  17451. b[modes.LIGHTEN] = (useNew) ? 'lighten' : 'source-over';
  17452. b[modes.COLOR_DODGE] = (useNew) ? 'color-dodge' : 'source-over';
  17453. b[modes.COLOR_BURN] = (useNew) ? 'color-burn' : 'source-over';
  17454. b[modes.HARD_LIGHT] = (useNew) ? 'hard-light' : 'source-over';
  17455. b[modes.SOFT_LIGHT] = (useNew) ? 'soft-light' : 'source-over';
  17456. b[modes.DIFFERENCE] = (useNew) ? 'difference' : 'source-over';
  17457. b[modes.EXCLUSION] = (useNew) ? 'exclusion' : 'source-over';
  17458. b[modes.HUE] = (useNew) ? 'hue' : 'source-over';
  17459. b[modes.SATURATION] = (useNew) ? 'saturation' : 'source-over';
  17460. b[modes.COLOR] = (useNew) ? 'color' : 'source-over';
  17461. b[modes.LUMINOSITY] = (useNew) ? 'luminosity' : 'source-over';
  17462. PIXI.blendModesCanvas = b;
  17463. }
  17464. };
  17465. /**
  17466. * @author Mat Groves http://matgroves.com/ @Doormat23
  17467. */
  17468. /**
  17469. * A texture stores the information that represents an image. All textures have a base texture.
  17470. *
  17471. * @class PIXI.BaseTexture
  17472. * @constructor
  17473. * @param source {String|Canvas} the source object (image or canvas)
  17474. * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values
  17475. * @param [resolution] {Number} the resolution of the texture (for HiDPI displays)
  17476. */
  17477. PIXI.BaseTexture = function(source, scaleMode, resolution)
  17478. {
  17479. /**
  17480. * The Resolution of the texture.
  17481. *
  17482. * @property resolution
  17483. * @type Number
  17484. */
  17485. this.resolution = resolution || 1;
  17486. /**
  17487. * [read-only] The width of the base texture set when the image has loaded
  17488. *
  17489. * @property width
  17490. * @type Number
  17491. * @readOnly
  17492. */
  17493. this.width = 100;
  17494. /**
  17495. * [read-only] The height of the base texture set when the image has loaded
  17496. *
  17497. * @property height
  17498. * @type Number
  17499. * @readOnly
  17500. */
  17501. this.height = 100;
  17502. /**
  17503. * The scale mode to apply when scaling this texture
  17504. *
  17505. * @property scaleMode
  17506. * @type {Number}
  17507. * @default PIXI.scaleModes.LINEAR
  17508. */
  17509. this.scaleMode = scaleMode || PIXI.scaleModes.DEFAULT;
  17510. /**
  17511. * [read-only] Set to true once the base texture has loaded
  17512. *
  17513. * @property hasLoaded
  17514. * @type Boolean
  17515. * @readOnly
  17516. */
  17517. this.hasLoaded = false;
  17518. /**
  17519. * The image source that is used to create the texture.
  17520. *
  17521. * @property source
  17522. * @type Image
  17523. */
  17524. this.source = source;
  17525. /**
  17526. * Controls if RGB channels should be pre-multiplied by Alpha (WebGL only)
  17527. *
  17528. * @property premultipliedAlpha
  17529. * @type Boolean
  17530. * @default true
  17531. */
  17532. this.premultipliedAlpha = true;
  17533. // used for webGL
  17534. /**
  17535. * @property _glTextures
  17536. * @type Array
  17537. * @private
  17538. */
  17539. this._glTextures = [];
  17540. /**
  17541. * Set this to true if a mipmap of this texture needs to be generated. This value needs to be set before the texture is used
  17542. * Also the texture must be a power of two size to work
  17543. *
  17544. * @property mipmap
  17545. * @type {Boolean}
  17546. */
  17547. this.mipmap = false;
  17548. /**
  17549. * The multi texture batching index number.
  17550. * @property textureIndex
  17551. * @type Number
  17552. */
  17553. this.textureIndex = 0;
  17554. /**
  17555. * @property _dirty
  17556. * @type Array
  17557. * @private
  17558. */
  17559. this._dirty = [true, true, true, true];
  17560. if (!source)
  17561. {
  17562. return;
  17563. }
  17564. if ((this.source.complete || this.source.getContext) && this.source.width && this.source.height)
  17565. {
  17566. this.hasLoaded = true;
  17567. this.width = this.source.naturalWidth || this.source.width;
  17568. this.height = this.source.naturalHeight || this.source.height;
  17569. this.dirty();
  17570. }
  17571. /**
  17572. * A BaseTexture can be set to skip the rendering phase in the WebGL Sprite Batch.
  17573. *
  17574. * You may want to do this if you have a parent Sprite with no visible texture (i.e. uses the internal `__default` texture)
  17575. * that has children that you do want to render, without causing a batch flush in the process.
  17576. *
  17577. * @property skipRender
  17578. * @type Boolean
  17579. */
  17580. this.skipRender = false;
  17581. /**
  17582. * @property _powerOf2
  17583. * @type Boolean
  17584. * @private
  17585. */
  17586. this._powerOf2 = false;
  17587. };
  17588. PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture;
  17589. /**
  17590. * Forces this BaseTexture to be set as loaded, with the given width and height.
  17591. * Then calls BaseTexture.dirty.
  17592. * Important for when you don't want to modify the source object by forcing in `complete` or dimension properties it may not have.
  17593. *
  17594. * @method PIXI.BaseTexture#forceLoaded
  17595. * @param {number} width - The new width to force the BaseTexture to be.
  17596. * @param {number} height - The new height to force the BaseTexture to be.
  17597. */
  17598. PIXI.BaseTexture.prototype.forceLoaded = function(width, height)
  17599. {
  17600. this.hasLoaded = true;
  17601. this.width = width;
  17602. this.height = height;
  17603. this.dirty();
  17604. };
  17605. /**
  17606. * Destroys this base texture
  17607. *
  17608. * @method PIXI.BaseTexture#destroy
  17609. */
  17610. PIXI.BaseTexture.prototype.destroy = function()
  17611. {
  17612. if (this.source)
  17613. {
  17614. Phaser.CanvasPool.removeByCanvas(this.source);
  17615. }
  17616. this.source = null;
  17617. this.unloadFromGPU();
  17618. };
  17619. /**
  17620. * Changes the source image of the texture
  17621. *
  17622. * @method PIXI.BaseTexture#updateSourceImage
  17623. * @param newSrc {String} the path of the image
  17624. * @deprecated This method is deprecated. Please use Phaser.Sprite.loadTexture instead.
  17625. */
  17626. PIXI.BaseTexture.prototype.updateSourceImage = function(newSrc)
  17627. {
  17628. console.warn("PIXI.BaseTexture.updateSourceImage is deprecated. Use Phaser.Sprite.loadTexture instead.");
  17629. };
  17630. /**
  17631. * Sets all glTextures to be dirty.
  17632. *
  17633. * @method PIXI.BaseTexture#dirty
  17634. */
  17635. PIXI.BaseTexture.prototype.dirty = function()
  17636. {
  17637. for (var i = 0; i < this._glTextures.length; i++)
  17638. {
  17639. this._dirty[i] = true;
  17640. }
  17641. };
  17642. /**
  17643. * Removes the base texture from the GPU, useful for managing resources on the GPU.
  17644. * Atexture is still 100% usable and will simply be reuploaded if there is a sprite on screen that is using it.
  17645. *
  17646. * @method PIXI.BaseTexture#unloadFromGPU
  17647. */
  17648. PIXI.BaseTexture.prototype.unloadFromGPU = function()
  17649. {
  17650. this.dirty();
  17651. // delete the webGL textures if any.
  17652. for (var i = this._glTextures.length - 1; i >= 0; i--)
  17653. {
  17654. var glTexture = this._glTextures[i];
  17655. var gl = PIXI.glContexts[i];
  17656. if(gl && glTexture)
  17657. {
  17658. gl.deleteTexture(glTexture);
  17659. }
  17660. }
  17661. this._glTextures.length = 0;
  17662. this.dirty();
  17663. };
  17664. /**
  17665. * Helper function that creates a base texture from the given canvas element.
  17666. *
  17667. * @static
  17668. * @method PIXI.BaseTexture#fromCanvas
  17669. * @param canvas {Canvas} The canvas element source of the texture
  17670. * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values
  17671. * @param [resolution] {Number} the resolution of the texture (for HiDPI displays)
  17672. * @return {BaseTexture}
  17673. */
  17674. PIXI.BaseTexture.fromCanvas = function(canvas, scaleMode, resolution)
  17675. {
  17676. if (canvas.width === 0)
  17677. {
  17678. canvas.width = 1;
  17679. }
  17680. if (canvas.height === 0)
  17681. {
  17682. canvas.height = 1;
  17683. }
  17684. resolution = resolution || 1;
  17685. return new PIXI.BaseTexture(canvas, scaleMode, resolution);
  17686. };
  17687. /**
  17688. * @author Mat Groves http://matgroves.com/ @Doormat23
  17689. */
  17690. /**
  17691. * TextureSilentFail is a boolean that defaults to `false`.
  17692. * If `true` then {@link PIXI.Texture#setFrame} will no longer throw an error if the texture dimensions are incorrect.
  17693. * Instead {@link PIXI.Texture#valid} will be set to `false` (#1556)
  17694. *
  17695. * @type {boolean}
  17696. */
  17697. PIXI.TextureSilentFail = false;
  17698. /**
  17699. * A texture stores the information that represents an image or part of an image. It cannot be added
  17700. * to the display list directly. Instead use it as the texture for a PIXI.Sprite. If no frame is provided then the whole image is used.
  17701. *
  17702. * @class PIXI.Texture
  17703. * @constructor
  17704. * @param baseTexture {BaseTexture} The base texture source to create the texture from
  17705. * @param frame {Rectangle} The rectangle frame of the texture to show
  17706. * @param [crop] {Rectangle} The area of original texture
  17707. * @param [trim] {Rectangle} Trimmed texture rectangle
  17708. */
  17709. PIXI.Texture = function(baseTexture, frame, crop, trim)
  17710. {
  17711. /**
  17712. * Does this Texture have any frame data assigned to it?
  17713. *
  17714. * @property noFrame
  17715. * @type Boolean
  17716. */
  17717. this.noFrame = false;
  17718. if (!frame)
  17719. {
  17720. this.noFrame = true;
  17721. frame = new PIXI.Rectangle(0,0,1,1);
  17722. }
  17723. if (baseTexture instanceof PIXI.Texture)
  17724. {
  17725. baseTexture = baseTexture.baseTexture;
  17726. }
  17727. /**
  17728. * The base texture that this texture uses.
  17729. *
  17730. * @property baseTexture
  17731. * @type BaseTexture
  17732. */
  17733. this.baseTexture = baseTexture;
  17734. /**
  17735. * The frame specifies the region of the base texture that this texture uses
  17736. *
  17737. * @property frame
  17738. * @type Rectangle
  17739. */
  17740. this.frame = frame;
  17741. /**
  17742. * The texture trim data.
  17743. *
  17744. * @property trim
  17745. * @type Rectangle
  17746. */
  17747. this.trim = trim;
  17748. /**
  17749. * This will let the renderer know if the texture is valid. If it's not then it cannot be rendered.
  17750. *
  17751. * @property valid
  17752. * @type Boolean
  17753. */
  17754. this.valid = false;
  17755. /**
  17756. * Is this a tiling texture? As used by the likes of a TilingSprite.
  17757. *
  17758. * @property isTiling
  17759. * @type Boolean
  17760. */
  17761. this.isTiling = false;
  17762. /**
  17763. * This will let a renderer know that a texture has been updated (used mainly for webGL uv updates)
  17764. *
  17765. * @property requiresUpdate
  17766. * @type Boolean
  17767. */
  17768. this.requiresUpdate = false;
  17769. /**
  17770. * This will let a renderer know that a tinted parent has updated its texture.
  17771. *
  17772. * @property requiresReTint
  17773. * @type Boolean
  17774. */
  17775. this.requiresReTint = false;
  17776. /**
  17777. * The WebGL UV data cache.
  17778. *
  17779. * @property _uvs
  17780. * @type Object
  17781. * @private
  17782. */
  17783. this._uvs = null;
  17784. /**
  17785. * The width of the Texture in pixels.
  17786. *
  17787. * @property width
  17788. * @type Number
  17789. */
  17790. this.width = 0;
  17791. /**
  17792. * The height of the Texture in pixels.
  17793. *
  17794. * @property height
  17795. * @type Number
  17796. */
  17797. this.height = 0;
  17798. /**
  17799. * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering,
  17800. * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases)
  17801. *
  17802. * @property crop
  17803. * @type Rectangle
  17804. */
  17805. this.crop = crop || new PIXI.Rectangle(0, 0, 1, 1);
  17806. /**
  17807. * A flag that controls if this frame is rotated or not.
  17808. * Rotation allows you to use rotated frames in texture atlas packing, it has nothing to do with
  17809. * Sprite rotation.
  17810. *
  17811. * @property rotated
  17812. * @type Boolean
  17813. */
  17814. this.rotated = false;
  17815. if (baseTexture.hasLoaded)
  17816. {
  17817. if (this.noFrame) frame = new PIXI.Rectangle(0, 0, baseTexture.width, baseTexture.height);
  17818. this.setFrame(frame);
  17819. }
  17820. };
  17821. PIXI.Texture.prototype.constructor = PIXI.Texture;
  17822. /**
  17823. * Called when the base texture is loaded
  17824. *
  17825. * @method PIXI.Texture#onBaseTextureLoaded
  17826. * @private
  17827. */
  17828. PIXI.Texture.prototype.onBaseTextureLoaded = function()
  17829. {
  17830. var baseTexture = this.baseTexture;
  17831. if (this.noFrame)
  17832. {
  17833. this.frame = new PIXI.Rectangle(0, 0, baseTexture.width, baseTexture.height);
  17834. }
  17835. this.setFrame(this.frame);
  17836. };
  17837. /**
  17838. * Destroys this texture
  17839. *
  17840. * @method PIXI.Texture#destroy
  17841. * @param destroyBase {Boolean} Whether to destroy the base texture as well
  17842. */
  17843. PIXI.Texture.prototype.destroy = function(destroyBase)
  17844. {
  17845. if (destroyBase) this.baseTexture.destroy();
  17846. this.valid = false;
  17847. };
  17848. /**
  17849. * Specifies the region of the baseTexture that this texture will use.
  17850. *
  17851. * @method PIXI.Texture#setFrame
  17852. * @param frame {Rectangle} The frame of the texture to set it to
  17853. */
  17854. PIXI.Texture.prototype.setFrame = function(frame)
  17855. {
  17856. this.noFrame = false;
  17857. this.frame = frame;
  17858. this.width = frame.width;
  17859. this.height = frame.height;
  17860. this.crop.x = frame.x;
  17861. this.crop.y = frame.y;
  17862. this.crop.width = frame.width;
  17863. this.crop.height = frame.height;
  17864. if (!this.trim && (frame.x + frame.width > this.baseTexture.width || frame.y + frame.height > this.baseTexture.height))
  17865. {
  17866. if (!PIXI.TextureSilentFail)
  17867. {
  17868. throw new Error('Texture Error: frame does not fit inside the base Texture dimensions ' + this);
  17869. }
  17870. this.valid = false;
  17871. return;
  17872. }
  17873. this.valid = frame && frame.width && frame.height && this.baseTexture.source && this.baseTexture.hasLoaded;
  17874. if (this.trim)
  17875. {
  17876. this.width = this.trim.width;
  17877. this.height = this.trim.height;
  17878. this.frame.width = this.trim.width;
  17879. this.frame.height = this.trim.height;
  17880. }
  17881. if (this.valid) this._updateUvs();
  17882. };
  17883. /**
  17884. * Updates the internal WebGL UV cache.
  17885. *
  17886. * @method PIXI.Texture#_updateUvs
  17887. * @private
  17888. */
  17889. PIXI.Texture.prototype._updateUvs = function()
  17890. {
  17891. if(!this._uvs)this._uvs = new PIXI.TextureUvs();
  17892. var frame = this.crop;
  17893. var tw = this.baseTexture.width;
  17894. var th = this.baseTexture.height;
  17895. this._uvs.x0 = frame.x / tw;
  17896. this._uvs.y0 = frame.y / th;
  17897. this._uvs.x1 = (frame.x + frame.width) / tw;
  17898. this._uvs.y1 = frame.y / th;
  17899. this._uvs.x2 = (frame.x + frame.width) / tw;
  17900. this._uvs.y2 = (frame.y + frame.height) / th;
  17901. this._uvs.x3 = frame.x / tw;
  17902. this._uvs.y3 = (frame.y + frame.height) / th;
  17903. };
  17904. /**
  17905. * Updates the internal WebGL UV cache.
  17906. *
  17907. * @method PIXI.Texture#_updateUvsInverted
  17908. * @private
  17909. */
  17910. PIXI.Texture.prototype._updateUvsInverted = function () {
  17911. if (!this._uvs) { this._uvs = new PIXI.TextureUvs(); }
  17912. var frame = this.crop;
  17913. var tw = this.baseTexture.width;
  17914. var th = this.baseTexture.height;
  17915. this._uvs.x0 = frame.x / tw;
  17916. this._uvs.y0 = frame.y / th;
  17917. this._uvs.x1 = (frame.x + frame.height) / tw;
  17918. this._uvs.y1 = frame.y / th;
  17919. this._uvs.x2 = (frame.x + frame.height) / tw;
  17920. this._uvs.y2 = (frame.y + frame.width) / th;
  17921. this._uvs.x3 = frame.x / tw;
  17922. this._uvs.y3 = (frame.y + frame.width) / th;
  17923. };
  17924. /**
  17925. * Helper function that creates a new a Texture based on the given canvas element.
  17926. *
  17927. * @static
  17928. * @method PIXI.Texture#fromCanvas
  17929. * @param canvas {Canvas} The canvas element source of the texture
  17930. * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values
  17931. * @return {Texture}
  17932. */
  17933. PIXI.Texture.fromCanvas = function(canvas, scaleMode)
  17934. {
  17935. var baseTexture = PIXI.BaseTexture.fromCanvas(canvas, scaleMode);
  17936. return new PIXI.Texture(baseTexture);
  17937. };
  17938. PIXI.TextureUvs = function()
  17939. {
  17940. this.x0 = 0;
  17941. this.y0 = 0;
  17942. this.x1 = 0;
  17943. this.y1 = 0;
  17944. this.x2 = 0;
  17945. this.y2 = 0;
  17946. this.x3 = 0;
  17947. this.y3 = 0;
  17948. };
  17949. /**
  17950. * @author Mat Groves http://matgroves.com/ @Doormat23
  17951. */
  17952. if (typeof exports !== 'undefined') {
  17953. if (typeof module !== 'undefined' && module.exports) {
  17954. exports = module.exports = PIXI;
  17955. }
  17956. exports.PIXI = PIXI;
  17957. } else if (typeof define !== 'undefined' && define.amd) {
  17958. define('PIXI', (function() { return root.PIXI = PIXI; })() );
  17959. } else {
  17960. root.PIXI = PIXI;
  17961. }
  17962. return PIXI;
  17963. }).call(this);
  17964. /**
  17965. * @author Richard Davey <rich@photonstorm.com>
  17966. * @copyright 2016 Photon Storm Ltd.
  17967. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  17968. */
  17969. (function(){
  17970. var root = this;
  17971. /**
  17972. * @author Richard Davey <rich@photonstorm.com>
  17973. * @copyright 2016 Photon Storm Ltd.
  17974. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  17975. */
  17976. /**
  17977. * @namespace Phaser
  17978. */
  17979. var Phaser = Phaser || { // jshint ignore:line
  17980. /**
  17981. * The Phaser version number.
  17982. * @constant Phaser.VERSION
  17983. * @type {string}
  17984. */
  17985. VERSION: '2.9.1',
  17986. /**
  17987. * An array of Phaser game instances.
  17988. * @constant Phaser.GAMES
  17989. * @type {array}
  17990. */
  17991. GAMES: [],
  17992. /**
  17993. * AUTO renderer - picks between WebGL or Canvas based on device.
  17994. * @constant Phaser.AUTO
  17995. * @type {integer}
  17996. */
  17997. AUTO: 0,
  17998. /**
  17999. * Canvas Renderer.
  18000. * @constant Phaser.CANVAS
  18001. * @type {integer}
  18002. */
  18003. CANVAS: 1,
  18004. /**
  18005. * WebGL Renderer.
  18006. * @constant Phaser.WEBGL
  18007. * @type {integer}
  18008. */
  18009. WEBGL: 2,
  18010. /**
  18011. * Headless renderer (not visual output)
  18012. * @constant Phaser.HEADLESS
  18013. * @type {integer}
  18014. */
  18015. HEADLESS: 3,
  18016. /**
  18017. * WebGL Renderer with MultiTexture support enabled.
  18018. * @constant Phaser.WEBGL_MULTI
  18019. * @type {integer}
  18020. */
  18021. WEBGL_MULTI: 4,
  18022. /**
  18023. * Direction constant.
  18024. * @constant Phaser.NONE
  18025. * @type {integer}
  18026. */
  18027. NONE: 0,
  18028. /**
  18029. * Direction constant.
  18030. * @constant Phaser.LEFT
  18031. * @type {integer}
  18032. */
  18033. LEFT: 1,
  18034. /**
  18035. * Direction constant.
  18036. * @constant Phaser.RIGHT
  18037. * @type {integer}
  18038. */
  18039. RIGHT: 2,
  18040. /**
  18041. * Direction constant.
  18042. * @constant Phaser.UP
  18043. * @type {integer}
  18044. */
  18045. UP: 3,
  18046. /**
  18047. * Direction constant.
  18048. * @constant Phaser.DOWN
  18049. * @type {integer}
  18050. */
  18051. DOWN: 4,
  18052. /**
  18053. * Game Object type.
  18054. * @constant Phaser.SPRITE
  18055. * @type {integer}
  18056. */
  18057. SPRITE: 0,
  18058. /**
  18059. * Game Object type.
  18060. * @constant Phaser.BUTTON
  18061. * @type {integer}
  18062. */
  18063. BUTTON: 1,
  18064. /**
  18065. * Game Object type.
  18066. * @constant Phaser.IMAGE
  18067. * @type {integer}
  18068. */
  18069. IMAGE: 2,
  18070. /**
  18071. * Game Object type.
  18072. * @constant Phaser.GRAPHICS
  18073. * @type {integer}
  18074. */
  18075. GRAPHICS: 3,
  18076. /**
  18077. * Game Object type.
  18078. * @constant Phaser.TEXT
  18079. * @type {integer}
  18080. */
  18081. TEXT: 4,
  18082. /**
  18083. * Game Object type.
  18084. * @constant Phaser.TILESPRITE
  18085. * @type {integer}
  18086. */
  18087. TILESPRITE: 5,
  18088. /**
  18089. * Game Object type.
  18090. * @constant Phaser.BITMAPTEXT
  18091. * @type {integer}
  18092. */
  18093. BITMAPTEXT: 6,
  18094. /**
  18095. * Game Object type.
  18096. * @constant Phaser.GROUP
  18097. * @type {integer}
  18098. */
  18099. GROUP: 7,
  18100. /**
  18101. * Game Object type.
  18102. * @constant Phaser.RENDERTEXTURE
  18103. * @type {integer}
  18104. */
  18105. RENDERTEXTURE: 8,
  18106. /**
  18107. * Game Object type.
  18108. * @constant Phaser.TILEMAP
  18109. * @type {integer}
  18110. */
  18111. TILEMAP: 9,
  18112. /**
  18113. * Game Object type.
  18114. * @constant Phaser.TILEMAPLAYER
  18115. * @type {integer}
  18116. */
  18117. TILEMAPLAYER: 10,
  18118. /**
  18119. * Game Object type.
  18120. * @constant Phaser.EMITTER
  18121. * @type {integer}
  18122. */
  18123. EMITTER: 11,
  18124. /**
  18125. * Game Object type.
  18126. * @constant Phaser.POLYGON
  18127. * @type {integer}
  18128. */
  18129. POLYGON: 12,
  18130. /**
  18131. * Game Object type.
  18132. * @constant Phaser.BITMAPDATA
  18133. * @type {integer}
  18134. */
  18135. BITMAPDATA: 13,
  18136. /**
  18137. * Game Object type.
  18138. * @constant Phaser.CANVAS_FILTER
  18139. * @type {integer}
  18140. */
  18141. CANVAS_FILTER: 14,
  18142. /**
  18143. * Game Object type.
  18144. * @constant Phaser.WEBGL_FILTER
  18145. * @type {integer}
  18146. */
  18147. WEBGL_FILTER: 15,
  18148. /**
  18149. * Game Object type.
  18150. * @constant Phaser.ELLIPSE
  18151. * @type {integer}
  18152. */
  18153. ELLIPSE: 16,
  18154. /**
  18155. * Game Object type.
  18156. * @constant Phaser.SPRITEBATCH
  18157. * @type {integer}
  18158. */
  18159. SPRITEBATCH: 17,
  18160. /**
  18161. * Game Object type.
  18162. * @constant Phaser.RETROFONT
  18163. * @type {integer}
  18164. */
  18165. RETROFONT: 18,
  18166. /**
  18167. * Game Object type.
  18168. * @constant Phaser.POINTER
  18169. * @type {integer}
  18170. */
  18171. POINTER: 19,
  18172. /**
  18173. * Game Object type.
  18174. * @constant Phaser.ROPE
  18175. * @type {integer}
  18176. */
  18177. ROPE: 20,
  18178. /**
  18179. * Game Object type.
  18180. * @constant Phaser.CIRCLE
  18181. * @type {integer}
  18182. */
  18183. CIRCLE: 21,
  18184. /**
  18185. * Game Object type.
  18186. * @constant Phaser.RECTANGLE
  18187. * @type {integer}
  18188. */
  18189. RECTANGLE: 22,
  18190. /**
  18191. * Game Object type.
  18192. * @constant Phaser.LINE
  18193. * @type {integer}
  18194. */
  18195. LINE: 23,
  18196. /**
  18197. * Game Object type.
  18198. * @constant Phaser.MATRIX
  18199. * @type {integer}
  18200. */
  18201. MATRIX: 24,
  18202. /**
  18203. * Game Object type.
  18204. * @constant Phaser.POINT
  18205. * @type {integer}
  18206. */
  18207. POINT: 25,
  18208. /**
  18209. * Game Object type.
  18210. * @constant Phaser.ROUNDEDRECTANGLE
  18211. * @type {integer}
  18212. */
  18213. ROUNDEDRECTANGLE: 26,
  18214. /**
  18215. * Game Object type.
  18216. * @constant Phaser.CREATURE
  18217. * @type {integer}
  18218. */
  18219. CREATURE: 27,
  18220. /**
  18221. * Game Object type.
  18222. * @constant Phaser.VIDEO
  18223. * @type {integer}
  18224. */
  18225. VIDEO: 28,
  18226. /**
  18227. * Game Object type.
  18228. * @constant Phaser.PENDING_ATLAS
  18229. * @type {integer}
  18230. */
  18231. PENDING_ATLAS: -1,
  18232. /**
  18233. * A horizontal orientation
  18234. * @constant Phaser.HORIZONTAL
  18235. * @type {integer}
  18236. */
  18237. HORIZONTAL: 0,
  18238. /**
  18239. * A vertical orientation
  18240. * @constant Phaser.VERTICAL
  18241. * @type {integer}
  18242. */
  18243. VERTICAL: 1,
  18244. /**
  18245. * A landscape orientation
  18246. * @constant Phaser.LANDSCAPE
  18247. * @type {integer}
  18248. */
  18249. LANDSCAPE: 0,
  18250. /**
  18251. * A portrait orientation
  18252. * @constant Phaser.PORTRAIT
  18253. * @type {integer}
  18254. */
  18255. PORTRAIT: 1,
  18256. /**
  18257. * The Angle (in degrees) a Game Object needs to be set to in order to face up.
  18258. * @constant Phaser.ANGLE_UP
  18259. * @type {integer}
  18260. */
  18261. ANGLE_UP: 270,
  18262. /**
  18263. * The Angle (in degrees) a Game Object needs to be set to in order to face down.
  18264. * @constant Phaser.ANGLE_DOWN
  18265. * @type {integer}
  18266. */
  18267. ANGLE_DOWN: 90,
  18268. /**
  18269. * The Angle (in degrees) a Game Object needs to be set to in order to face left.
  18270. * @constant Phaser.ANGLE_LEFT
  18271. * @type {integer}
  18272. */
  18273. ANGLE_LEFT: 180,
  18274. /**
  18275. * The Angle (in degrees) a Game Object needs to be set to in order to face right.
  18276. * @constant Phaser.ANGLE_RIGHT
  18277. * @type {integer}
  18278. */
  18279. ANGLE_RIGHT: 0,
  18280. /**
  18281. * The Angle (in degrees) a Game Object needs to be set to in order to face north east.
  18282. * @constant Phaser.ANGLE_NORTH_EAST
  18283. * @type {integer}
  18284. */
  18285. ANGLE_NORTH_EAST: 315,
  18286. /**
  18287. * The Angle (in degrees) a Game Object needs to be set to in order to face north west.
  18288. * @constant Phaser.ANGLE_NORTH_WEST
  18289. * @type {integer}
  18290. */
  18291. ANGLE_NORTH_WEST: 225,
  18292. /**
  18293. * The Angle (in degrees) a Game Object needs to be set to in order to face south east.
  18294. * @constant Phaser.ANGLE_SOUTH_EAST
  18295. * @type {integer}
  18296. */
  18297. ANGLE_SOUTH_EAST: 45,
  18298. /**
  18299. * The Angle (in degrees) a Game Object needs to be set to in order to face south west.
  18300. * @constant Phaser.ANGLE_SOUTH_WEST
  18301. * @type {integer}
  18302. */
  18303. ANGLE_SOUTH_WEST: 135,
  18304. /**
  18305. * A constant representing a top-left alignment or position.
  18306. * @constant Phaser.TOP_LEFT
  18307. * @type {integer}
  18308. */
  18309. TOP_LEFT: 0,
  18310. /**
  18311. * A constant representing a top-center alignment or position.
  18312. * @constant Phaser.TOP_CENTER
  18313. * @type {integer}
  18314. */
  18315. TOP_CENTER: 1,
  18316. /**
  18317. * A constant representing a top-right alignment or position.
  18318. * @constant Phaser.TOP_RIGHT
  18319. * @type {integer}
  18320. */
  18321. TOP_RIGHT: 2,
  18322. /**
  18323. * A constant representing a left-top alignment or position.
  18324. * @constant Phaser.Phaser.LEFT_TOP
  18325. * @type {integer}
  18326. */
  18327. LEFT_TOP: 3,
  18328. /**
  18329. * A constant representing a left-center alignment or position.
  18330. * @constant Phaser.LEFT_TOP
  18331. * @type {integer}
  18332. */
  18333. LEFT_CENTER: 4,
  18334. /**
  18335. * A constant representing a left-bottom alignment or position.
  18336. * @constant Phaser.LEFT_BOTTOM
  18337. * @type {integer}
  18338. */
  18339. LEFT_BOTTOM: 5,
  18340. /**
  18341. * A constant representing a center alignment or position.
  18342. * @constant Phaser.CENTER
  18343. * @type {integer}
  18344. */
  18345. CENTER: 6,
  18346. /**
  18347. * A constant representing a right-top alignment or position.
  18348. * @constant Phaser.RIGHT_TOP
  18349. * @type {integer}
  18350. */
  18351. RIGHT_TOP: 7,
  18352. /**
  18353. * A constant representing a right-center alignment or position.
  18354. * @constant Phaser.RIGHT_CENTER
  18355. * @type {integer}
  18356. */
  18357. RIGHT_CENTER: 8,
  18358. /**
  18359. * A constant representing a right-bottom alignment or position.
  18360. * @constant Phaser.RIGHT_BOTTOM
  18361. * @type {integer}
  18362. */
  18363. RIGHT_BOTTOM: 9,
  18364. /**
  18365. * A constant representing a bottom-left alignment or position.
  18366. * @constant Phaser.BOTTOM_LEFT
  18367. * @type {integer}
  18368. */
  18369. BOTTOM_LEFT: 10,
  18370. /**
  18371. * A constant representing a bottom-center alignment or position.
  18372. * @constant Phaser.BOTTOM_CENTER
  18373. * @type {integer}
  18374. */
  18375. BOTTOM_CENTER: 11,
  18376. /**
  18377. * A constant representing a bottom-right alignment or position.
  18378. * @constant Phaser.BOTTOM_RIGHT
  18379. * @type {integer}
  18380. */
  18381. BOTTOM_RIGHT: 12,
  18382. /**
  18383. * Various blend modes supported by Pixi. See the samples in {@link https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing Canvas Tutorial: Compositing}.
  18384. *
  18385. * IMPORTANT: The WebGL renderer only supports the NORMAL, ADD, MULTIPLY and SCREEN blend modes.
  18386. *
  18387. * @constant {Object} Phaser.blendModes
  18388. * @property {Number} blendModes.NORMAL - Draws new shapes on top of the existing content. This is the default setting.
  18389. * @property {Number} blendModes.ADD - Where both shapes overlap the color is determined by adding color values.
  18390. * @property {Number} blendModes.MULTIPLY - The pixels of the top layer are multiplied with the corresponding pixel of the bottom layer, making a darker picture.
  18391. * @property {Number} blendModes.SCREEN - The pixels are inverted, multiplied, and inverted again, making a lighter picture.
  18392. * @property {Number} blendModes.OVERLAY
  18393. * @property {Number} blendModes.DARKEN
  18394. * @property {Number} blendModes.LIGHTEN
  18395. * @property {Number} blendModes.COLOR_DODGE
  18396. * @property {Number} blendModes.COLOR_BURN
  18397. * @property {Number} blendModes.HARD_LIGHT
  18398. * @property {Number} blendModes.SOFT_LIGHT
  18399. * @property {Number} blendModes.DIFFERENCE
  18400. * @property {Number} blendModes.EXCLUSION
  18401. * @property {Number} blendModes.HUE
  18402. * @property {Number} blendModes.SATURATION
  18403. * @property {Number} blendModes.COLOR
  18404. * @property {Number} blendModes.LUMINOSITY
  18405. * @static
  18406. */
  18407. blendModes: {
  18408. NORMAL: 0,
  18409. ADD: 1,
  18410. MULTIPLY: 2,
  18411. SCREEN: 3,
  18412. OVERLAY: 4,
  18413. DARKEN: 5,
  18414. LIGHTEN: 6,
  18415. COLOR_DODGE: 7,
  18416. COLOR_BURN: 8,
  18417. HARD_LIGHT: 9,
  18418. SOFT_LIGHT: 10,
  18419. DIFFERENCE: 11,
  18420. EXCLUSION: 12,
  18421. HUE: 13,
  18422. SATURATION: 14,
  18423. COLOR: 15,
  18424. LUMINOSITY: 16
  18425. },
  18426. /**
  18427. * The scale modes that are supported by Pixi.
  18428. *
  18429. * The DEFAULT scale mode affects the default scaling mode of future operations.
  18430. * It can be re-assigned to either LINEAR or NEAREST, depending upon suitability.
  18431. *
  18432. * @constant {Object} Phaser.scaleModes
  18433. * @property {Number} Phaser.scaleModes.DEFAULT=LINEAR
  18434. * @property {Number} Phaser.scaleModes.LINEAR Smooth scaling
  18435. * @property {Number} Phaser.scaleModes.NEAREST Pixelating scaling
  18436. * @static
  18437. */
  18438. scaleModes: {
  18439. DEFAULT: 0,
  18440. LINEAR: 0,
  18441. NEAREST: 1
  18442. },
  18443. PIXI: PIXI || {},
  18444. // Used to create IDs for various Pixi objects.
  18445. _UID: 0
  18446. };
  18447. /**
  18448. * @copyright 2016 Photon Storm Ltd.
  18449. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  18450. */
  18451. // ES6 Math.trunc - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
  18452. if (!Math.trunc) {
  18453. Math.trunc = function trunc(x) {
  18454. return x < 0 ? Math.ceil(x) : Math.floor(x);
  18455. };
  18456. }
  18457. /**
  18458. * A polyfill for Function.prototype.bind
  18459. */
  18460. if (!Function.prototype.bind) {
  18461. /* jshint freeze: false */
  18462. Function.prototype.bind = (function () {
  18463. var slice = Array.prototype.slice;
  18464. return function (thisArg) {
  18465. var target = this, boundArgs = slice.call(arguments, 1);
  18466. if (typeof target !== 'function')
  18467. {
  18468. throw new TypeError();
  18469. }
  18470. function bound() {
  18471. var args = boundArgs.concat(slice.call(arguments));
  18472. target.apply(this instanceof bound ? this : thisArg, args);
  18473. }
  18474. bound.prototype = (function F(proto) {
  18475. if (proto)
  18476. {
  18477. F.prototype = proto;
  18478. }
  18479. if (!(this instanceof F))
  18480. {
  18481. /* jshint supernew: true */
  18482. return new F;
  18483. }
  18484. })(target.prototype);
  18485. return bound;
  18486. };
  18487. })();
  18488. }
  18489. /**
  18490. * A polyfill for Array.isArray
  18491. */
  18492. if (!Array.isArray)
  18493. {
  18494. Array.isArray = function (arg)
  18495. {
  18496. return Object.prototype.toString.call(arg) === '[object Array]';
  18497. };
  18498. }
  18499. /**
  18500. * A polyfill for Array.forEach
  18501. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
  18502. */
  18503. if (!Array.prototype.forEach)
  18504. {
  18505. Array.prototype.forEach = function(fun /*, thisArg */)
  18506. {
  18507. "use strict";
  18508. if (this === void 0 || this === null)
  18509. {
  18510. throw new TypeError();
  18511. }
  18512. var t = Object(this);
  18513. var len = t.length >>> 0;
  18514. if (typeof fun !== "function")
  18515. {
  18516. throw new TypeError();
  18517. }
  18518. var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
  18519. for (var i = 0; i < len; i++)
  18520. {
  18521. if (i in t)
  18522. {
  18523. fun.call(thisArg, t[i], i, t);
  18524. }
  18525. }
  18526. };
  18527. }
  18528. /**
  18529. * Low-budget Float32Array knock-off, suitable for use with P2.js in IE9
  18530. * Source: http://www.html5gamedevs.com/topic/5988-phaser-12-ie9/
  18531. * Cameron Foale (http://www.kibibu.com)
  18532. */
  18533. if (typeof window.Uint32Array !== "function" && typeof window.Uint32Array !== "object")
  18534. {
  18535. var CheapArray = function(type)
  18536. {
  18537. var proto = new Array(); // jshint ignore:line
  18538. window[type] = function(arg) {
  18539. if (typeof(arg) === "number")
  18540. {
  18541. Array.call(this, arg);
  18542. this.length = arg;
  18543. for (var i = 0; i < this.length; i++)
  18544. {
  18545. this[i] = 0;
  18546. }
  18547. }
  18548. else
  18549. {
  18550. Array.call(this, arg.length);
  18551. this.length = arg.length;
  18552. for (var i = 0; i < this.length; i++)
  18553. {
  18554. this[i] = arg[i];
  18555. }
  18556. }
  18557. };
  18558. window[type].prototype = proto;
  18559. window[type].constructor = window[type];
  18560. };
  18561. CheapArray('Float32Array'); // jshint ignore:line
  18562. CheapArray('Uint32Array'); // jshint ignore:line
  18563. CheapArray('Uint16Array'); // jshint ignore:line
  18564. CheapArray('Int16Array'); // jshint ignore:line
  18565. CheapArray('ArrayBuffer'); // jshint ignore:line
  18566. }
  18567. /**
  18568. * Also fix for the absent console in IE9
  18569. */
  18570. if (!window.console)
  18571. {
  18572. window.console = {};
  18573. window.console.log = window.console.assert = function(){};
  18574. window.console.warn = window.console.assert = function(){};
  18575. }
  18576. /**
  18577. * Fix for Object.assign not existing on older devices
  18578. */
  18579. if (!Object.assign) {
  18580. /* jshint -W098 */
  18581. // We include `varArgs` (unused) to ensure Object.assign.length === 2
  18582. Object.assign = function(target, varArgs) {
  18583. /* jshint +W098 */
  18584. 'use strict';
  18585. if (target == null) { // TypeError if undefined or null
  18586. throw new TypeError('Cannot convert undefined or null to object');
  18587. }
  18588. var to = Object(target);
  18589. var hasOwn = Object.prototype.hasOwnProperty;
  18590. for (var index = 1; index < arguments.length; index++) {
  18591. var nextSource = arguments[index];
  18592. if (nextSource != null) { // Skip over if undefined or null
  18593. for (var nextKey in nextSource) {
  18594. // Avoid bugs when hasOwnProperty is shadowed
  18595. if (hasOwn.call(nextSource, nextKey)) {
  18596. to[nextKey] = nextSource[nextKey];
  18597. }
  18598. }
  18599. }
  18600. }
  18601. return to;
  18602. };
  18603. }
  18604. /**
  18605. * @author Richard Davey <rich@photonstorm.com>
  18606. * @copyright 2016 Photon Storm Ltd.
  18607. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  18608. */
  18609. /**
  18610. * @class Phaser.Utils
  18611. * @static
  18612. */
  18613. Phaser.Utils = {
  18614. /**
  18615. * Takes the given string and reverses it, returning the reversed string.
  18616. * For example if given the string `Atari 520ST` it would return `TS025 iratA`.
  18617. *
  18618. * @method Phaser.Utils.reverseString
  18619. * @param {string} string - The string to be reversed.
  18620. * @return {string} The reversed string.
  18621. */
  18622. reverseString: function (string) {
  18623. return string.split('').reverse().join('');
  18624. },
  18625. /**
  18626. * Gets an object's property by string.
  18627. *
  18628. * @method Phaser.Utils.getProperty
  18629. * @param {object} obj - The object to traverse.
  18630. * @param {string} prop - The property whose value will be returned.
  18631. * @return {any} - The value of the property or `undefined` if the property isn't found.
  18632. */
  18633. getProperty: function(obj, prop) {
  18634. var parts = prop.split('.'),
  18635. len = parts.length,
  18636. i = 0,
  18637. val = obj;
  18638. while (i < len)
  18639. {
  18640. var key = parts[i];
  18641. if (val != null)
  18642. {
  18643. val = val[key];
  18644. i++;
  18645. }
  18646. else
  18647. {
  18648. return undefined;
  18649. }
  18650. }
  18651. return val;
  18652. },
  18653. /**
  18654. * Sets an object's properties from a map of property names and values.
  18655. *
  18656. * ```javascript
  18657. * Phaser.Utils.setProperties(sprite, {
  18658. * 'animations.paused': true,
  18659. * 'body.enable': false,
  18660. * 'input.draggable': true,
  18661. * });
  18662. * ```
  18663. *
  18664. * @method Phaser.Utils.setProperties
  18665. * @param {object} obj - The object to modify.
  18666. * @param {object} props - The property names and values to set on the object (see {@link #setProperty}).
  18667. * @return {object} The modified object.
  18668. */
  18669. setProperties: function(obj, props) {
  18670. for (var name in props)
  18671. {
  18672. this.setProperty(obj, name, props[name]);
  18673. }
  18674. return obj;
  18675. },
  18676. /**
  18677. * Sets an object's property by name and value.
  18678. *
  18679. * ```javascript
  18680. * Phaser.Utils.setProperty(sprite, 'body.velocity.x', 60);
  18681. * ```
  18682. *
  18683. * @method Phaser.Utils.setProperty
  18684. * @param {object} obj - The object to modify.
  18685. * @param {string} name - The property name, or a series of names separated by `.` (for nested properties).
  18686. * @param {any} value - The value.
  18687. * @return {object} The modified object.
  18688. */
  18689. setProperty: function(obj, name, value) {
  18690. var parts = name.split('.');
  18691. switch (parts.length)
  18692. {
  18693. case 1:
  18694. obj[name] = value;
  18695. break;
  18696. case 2:
  18697. obj[parts[0]][parts[1]] = value;
  18698. break;
  18699. case 3:
  18700. obj[parts[0]][parts[1]][parts[2]] = value;
  18701. break;
  18702. case 4:
  18703. obj[parts[0]][parts[1]][parts[2]][parts[3]] = value;
  18704. break;
  18705. default:
  18706. this._setProperty(obj, name, value);
  18707. }
  18708. },
  18709. /**
  18710. * Sets an object's property by name and value.
  18711. *
  18712. * @private
  18713. * @method Phaser.Utils._setProperty
  18714. * @param {object} obj - The object to modify.
  18715. * @param {string} name - The property name, or a series of names separated by `.` (for nested properties).
  18716. * @param {any} value - The value.
  18717. * @return {object} The modified object.
  18718. */
  18719. _setProperty: function(obj, name, value) {
  18720. var parts = name.split('.'),
  18721. len = parts.length,
  18722. i = 0,
  18723. currentObj = obj,
  18724. key = parts[0];
  18725. if (len === 1)
  18726. {
  18727. obj[name] = value;
  18728. }
  18729. else
  18730. {
  18731. while (i < (len - 1))
  18732. {
  18733. currentObj = currentObj[key];
  18734. i++;
  18735. key = parts[i];
  18736. }
  18737. currentObj[key] = value;
  18738. }
  18739. return obj;
  18740. },
  18741. /**
  18742. * Generate a random bool result based on the chance value.
  18743. *
  18744. * Returns true or false based on the chance value (default 50%). For example if you wanted a player to have a 30% chance
  18745. * of getting a bonus, call chanceRoll(30) - true means the chance passed, false means it failed.
  18746. *
  18747. * @method Phaser.Utils#chanceRoll
  18748. * @param {number} chance - The chance of receiving the value. A number between 0 and 100 (effectively 0% to 100%).
  18749. * @return {boolean} True if the roll passed, or false otherwise.
  18750. */
  18751. chanceRoll: function (chance) {
  18752. if (chance === undefined) { chance = 50; }
  18753. return chance > 0 && (Math.random() * 100 <= chance);
  18754. },
  18755. /**
  18756. * Choose between one of two values randomly.
  18757. *
  18758. * @method Phaser.Utils#randomChoice
  18759. * @param {any} choice1
  18760. * @param {any} choice2
  18761. * @return {any} The randomly selected choice
  18762. */
  18763. randomChoice: function (choice1, choice2) {
  18764. return (Math.random() < 0.5) ? choice1 : choice2;
  18765. },
  18766. /**
  18767. * Get a unit dimension from a string.
  18768. *
  18769. * @method Phaser.Utils.parseDimension
  18770. * @param {string|number} size - The size to parse.
  18771. * @param {number} dimension - The window dimension to check.
  18772. * @return {number} The parsed dimension.
  18773. */
  18774. parseDimension: function (size, dimension) {
  18775. var f = 0;
  18776. var px = 0;
  18777. if (typeof size === 'string')
  18778. {
  18779. // %?
  18780. if (size.substr(-1) === '%')
  18781. {
  18782. f = parseInt(size, 10) / 100;
  18783. if (dimension === 0)
  18784. {
  18785. px = window.innerWidth * f;
  18786. }
  18787. else
  18788. {
  18789. px = window.innerHeight * f;
  18790. }
  18791. }
  18792. else
  18793. {
  18794. px = parseInt(size, 10);
  18795. }
  18796. }
  18797. else
  18798. {
  18799. px = size;
  18800. }
  18801. return px;
  18802. },
  18803. /**
  18804. * Takes the given string and pads it out, to the length required, using the character
  18805. * specified. For example if you need a string to be 6 characters long, you can call:
  18806. *
  18807. * `pad('bob', 6, '-', 2)`
  18808. *
  18809. * This would return: `bob---` as it has padded it out to 6 characters, using the `-` on the right.
  18810. *
  18811. * You can also use it to pad numbers (they are always returned as strings):
  18812. *
  18813. * `pad(512, 6, '0', 1)`
  18814. *
  18815. * Would return: `000512` with the string padded to the left.
  18816. *
  18817. * If you don't specify a direction it'll pad to both sides:
  18818. *
  18819. * `pad('c64', 7, '*')`
  18820. *
  18821. * Would return: `**c64**`
  18822. *
  18823. * @method Phaser.Utils.pad
  18824. * @param {string} str - The target string. `toString()` will be called on the string, which means you can also pass in common data types like numbers.
  18825. * @param {integer} [len=0] - The number of characters to be added.
  18826. * @param {string} [pad=" "] - The string to pad it out with (defaults to a space).
  18827. * @param {integer} [dir=3] - The direction dir = 1 (left), 2 (right), 3 (both).
  18828. * @return {string} The padded string.
  18829. */
  18830. pad: function (str, len, pad, dir) {
  18831. if (len === undefined) { var len = 0; }
  18832. if (pad === undefined) { var pad = ' '; }
  18833. if (dir === undefined) { var dir = 3; }
  18834. str = str.toString();
  18835. var padlen = 0;
  18836. if (len + 1 >= str.length)
  18837. {
  18838. switch (dir)
  18839. {
  18840. case 1:
  18841. str = new Array(len + 1 - str.length).join(pad) + str;
  18842. break;
  18843. case 3:
  18844. var right = Math.ceil((padlen = len - str.length) / 2);
  18845. var left = padlen - right;
  18846. str = new Array(left+1).join(pad) + str + new Array(right+1).join(pad);
  18847. break;
  18848. default:
  18849. str = str + new Array(len + 1 - str.length).join(pad);
  18850. break;
  18851. }
  18852. }
  18853. return str;
  18854. },
  18855. /**
  18856. * This is a slightly modified version of jQuery.isPlainObject.
  18857. * A plain object is an object whose internal class property is [object Object].
  18858. * @method Phaser.Utils.isPlainObject
  18859. * @param {object} obj - The object to inspect.
  18860. * @return {boolean} - true if the object is plain, otherwise false.
  18861. */
  18862. isPlainObject: function (obj) {
  18863. // Not plain objects:
  18864. // - Any object or value whose internal [[Class]] property is not "[object Object]"
  18865. // - DOM nodes
  18866. // - window
  18867. if (typeof(obj) !== "object" || obj.nodeType || obj === obj.window)
  18868. {
  18869. return false;
  18870. }
  18871. // Support: Firefox <20
  18872. // The try/catch suppresses exceptions thrown when attempting to access
  18873. // the "constructor" property of certain host objects, ie. |window.location|
  18874. // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
  18875. try {
  18876. if (obj.constructor && !({}).hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf"))
  18877. {
  18878. return false;
  18879. }
  18880. } catch (e) {
  18881. return false;
  18882. }
  18883. // If the function hasn't returned already, we're confident that
  18884. // |obj| is a plain object, created by {} or constructed with new Object
  18885. return true;
  18886. },
  18887. /**
  18888. * This is a slightly modified version of http://api.jquery.com/jQuery.extend/
  18889. *
  18890. * @method Phaser.Utils.extend
  18891. * @param {boolean} deep - Perform a deep copy?
  18892. * @param {object} target - The target object to copy to.
  18893. * @return {object} The extended object.
  18894. */
  18895. extend: function () {
  18896. var options, name, src, copy, copyIsArray, clone,
  18897. target = arguments[0] || {},
  18898. i = 1,
  18899. length = arguments.length,
  18900. deep = false;
  18901. // Handle a deep copy situation
  18902. if (typeof target === "boolean")
  18903. {
  18904. deep = target;
  18905. target = arguments[1] || {};
  18906. // skip the boolean and the target
  18907. i = 2;
  18908. }
  18909. // extend Phaser if only one argument is passed
  18910. if (length === i)
  18911. {
  18912. target = this;
  18913. --i;
  18914. }
  18915. for (; i < length; i++)
  18916. {
  18917. // Only deal with non-null/undefined values
  18918. if ((options = arguments[i]) != null)
  18919. {
  18920. // Extend the base object
  18921. for (name in options)
  18922. {
  18923. src = target[name];
  18924. copy = options[name];
  18925. // Prevent never-ending loop
  18926. if (target === copy)
  18927. {
  18928. continue;
  18929. }
  18930. // Recurse if we're merging plain objects or arrays
  18931. if (deep && copy && (Phaser.Utils.isPlainObject(copy) || (copyIsArray = Array.isArray(copy))))
  18932. {
  18933. if (copyIsArray)
  18934. {
  18935. copyIsArray = false;
  18936. clone = src && Array.isArray(src) ? src : [];
  18937. }
  18938. else
  18939. {
  18940. clone = src && Phaser.Utils.isPlainObject(src) ? src : {};
  18941. }
  18942. // Never move original objects, clone them
  18943. target[name] = Phaser.Utils.extend(deep, clone, copy);
  18944. // Don't bring in undefined values
  18945. }
  18946. else if (copy !== undefined)
  18947. {
  18948. target[name] = copy;
  18949. }
  18950. }
  18951. }
  18952. }
  18953. // Return the modified object
  18954. return target;
  18955. },
  18956. /**
  18957. * Mixes in an existing mixin object with the target.
  18958. *
  18959. * Values in the mixin that have either `get` or `set` functions are created as properties via `defineProperty`
  18960. * _except_ if they also define a `clone` method - if a clone method is defined that is called instead and
  18961. * the result is assigned directly.
  18962. *
  18963. * @method Phaser.Utils.mixinPrototype
  18964. * @param {object} target - The target object to receive the new functions.
  18965. * @param {object} mixin - The object to copy the functions from.
  18966. * @param {boolean} [replace=false] - If the target object already has a matching function should it be overwritten or not?
  18967. */
  18968. mixinPrototype: function (target, mixin, replace) {
  18969. if (replace === undefined) { replace = false; }
  18970. var mixinKeys = Object.keys(mixin);
  18971. for (var i = 0; i < mixinKeys.length; i++)
  18972. {
  18973. var key = mixinKeys[i];
  18974. var value = mixin[key];
  18975. if (!replace && (key in target))
  18976. {
  18977. // Not overwriting existing property
  18978. continue;
  18979. }
  18980. else
  18981. {
  18982. if (value &&
  18983. (typeof value.get === 'function' || typeof value.set === 'function'))
  18984. {
  18985. // Special case for classes like Phaser.Point which has a 'set' function!
  18986. if (typeof value.clone === 'function')
  18987. {
  18988. target[key] = value.clone();
  18989. }
  18990. else
  18991. {
  18992. Object.defineProperty(target, key, value);
  18993. }
  18994. }
  18995. else
  18996. {
  18997. target[key] = value;
  18998. }
  18999. }
  19000. }
  19001. },
  19002. /**
  19003. * Mixes the source object into the destination object, returning the newly modified destination object.
  19004. * Based on original code by @mudcube
  19005. *
  19006. * @method Phaser.Utils.mixin
  19007. * @param {object} from - The object to copy (the source object).
  19008. * @param {object} to - The object to copy to (the destination object).
  19009. * @return {object} The modified destination object.
  19010. */
  19011. mixin: function (from, to) {
  19012. if (!from || typeof (from) !== "object")
  19013. {
  19014. return to;
  19015. }
  19016. for (var key in from)
  19017. {
  19018. var o = from[key];
  19019. if (o.childNodes || o.cloneNode)
  19020. {
  19021. continue;
  19022. }
  19023. var type = typeof (from[key]);
  19024. if (!from[key] || type !== "object")
  19025. {
  19026. to[key] = from[key];
  19027. }
  19028. else
  19029. {
  19030. // Clone sub-object
  19031. if (typeof (to[key]) === type)
  19032. {
  19033. to[key] = Phaser.Utils.mixin(from[key], to[key]);
  19034. }
  19035. else
  19036. {
  19037. to[key] = Phaser.Utils.mixin(from[key], new o.constructor());
  19038. }
  19039. }
  19040. }
  19041. return to;
  19042. }
  19043. };
  19044. /**
  19045. * @author Richard Davey <rich@photonstorm.com>
  19046. * @copyright 2016 Photon Storm Ltd.
  19047. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  19048. */
  19049. /**
  19050. * Creates a new Circle object with the center coordinate specified by the x and y parameters and the diameter specified by the diameter parameter.
  19051. * If you call this function without parameters, a circle with x, y, diameter and radius properties set to 0 is created.
  19052. *
  19053. * @class Phaser.Circle
  19054. * @constructor
  19055. * @param {number} [x=0] - The x coordinate of the center of the circle.
  19056. * @param {number} [y=0] - The y coordinate of the center of the circle.
  19057. * @param {number} [diameter=0] - The diameter of the circle.
  19058. */
  19059. Phaser.Circle = function (x, y, diameter) {
  19060. x = x || 0;
  19061. y = y || 0;
  19062. diameter = diameter || 0;
  19063. /**
  19064. * @property {number} x - The x coordinate of the center of the circle.
  19065. */
  19066. this.x = x;
  19067. /**
  19068. * @property {number} y - The y coordinate of the center of the circle.
  19069. */
  19070. this.y = y;
  19071. /**
  19072. * @property {number} _diameter - The diameter of the circle.
  19073. * @private
  19074. */
  19075. this._diameter = diameter;
  19076. /**
  19077. * @property {number} _radius - The radius of the circle.
  19078. * @private
  19079. */
  19080. this._radius = 0;
  19081. if (diameter > 0)
  19082. {
  19083. this._radius = diameter * 0.5;
  19084. }
  19085. /**
  19086. * @property {number} type - The const type of this object.
  19087. * @readonly
  19088. */
  19089. this.type = Phaser.CIRCLE;
  19090. };
  19091. Phaser.Circle.prototype = {
  19092. /**
  19093. * The circumference of the circle.
  19094. *
  19095. * @method Phaser.Circle#circumference
  19096. * @return {number} The circumference of the circle.
  19097. */
  19098. circumference: function () {
  19099. return 2 * (Math.PI * this._radius);
  19100. },
  19101. /**
  19102. * Returns a uniformly distributed random point from anywhere within this Circle.
  19103. *
  19104. * @method Phaser.Circle#random
  19105. * @param {Phaser.Point|object} [out] - A Phaser.Point, or any object with public x/y properties, that the values will be set in.
  19106. * If no object is provided a new Phaser.Point object will be created. In high performance areas avoid this by re-using an existing object.
  19107. * @return {Phaser.Point} An object containing the random point in its `x` and `y` properties.
  19108. */
  19109. random: function (out) {
  19110. if (out === undefined) { out = new Phaser.Point(); }
  19111. var t = 2 * Math.PI * Math.random();
  19112. var u = Math.random() + Math.random();
  19113. var r = (u > 1) ? 2 - u : u;
  19114. var x = r * Math.cos(t);
  19115. var y = r * Math.sin(t);
  19116. out.x = this.x + (x * this.radius);
  19117. out.y = this.y + (y * this.radius);
  19118. return out;
  19119. },
  19120. /**
  19121. * Returns the framing rectangle of the circle as a Phaser.Rectangle object.
  19122. *
  19123. * @method Phaser.Circle#getBounds
  19124. * @return {Phaser.Rectangle} The bounds of the Circle.
  19125. */
  19126. getBounds: function () {
  19127. return new Phaser.Rectangle(this.x - this.radius, this.y - this.radius, this.diameter, this.diameter);
  19128. },
  19129. /**
  19130. * Sets the members of Circle to the specified values.
  19131. * @method Phaser.Circle#setTo
  19132. * @param {number} x - The x coordinate of the center of the circle.
  19133. * @param {number} y - The y coordinate of the center of the circle.
  19134. * @param {number} diameter - The diameter of the circle.
  19135. * @return {Circle} This circle object.
  19136. */
  19137. setTo: function (x, y, diameter) {
  19138. this.x = x;
  19139. this.y = y;
  19140. this._diameter = diameter;
  19141. this._radius = diameter * 0.5;
  19142. return this;
  19143. },
  19144. /**
  19145. * Copies the x, y and diameter properties from any given object to this Circle.
  19146. * @method Phaser.Circle#copyFrom
  19147. * @param {any} source - The object to copy from.
  19148. * @return {Circle} This Circle object.
  19149. */
  19150. copyFrom: function (source) {
  19151. return this.setTo(source.x, source.y, source.diameter);
  19152. },
  19153. /**
  19154. * Copies the x, y and diameter properties from this Circle to any given object.
  19155. * @method Phaser.Circle#copyTo
  19156. * @param {any} dest - The object to copy to.
  19157. * @return {object} This dest object.
  19158. */
  19159. copyTo: function (dest) {
  19160. dest.x = this.x;
  19161. dest.y = this.y;
  19162. dest.diameter = this._diameter;
  19163. return dest;
  19164. },
  19165. /**
  19166. * Returns the distance from the center of the Circle object to the given object
  19167. * (can be Circle, Point or anything with x/y properties)
  19168. * @method Phaser.Circle#distance
  19169. * @param {object} dest - The target object. Must have visible x and y properties that represent the center of the object.
  19170. * @param {boolean} [round=false] - Round the distance to the nearest integer.
  19171. * @return {number} The distance between this Point object and the destination Point object.
  19172. */
  19173. distance: function (dest, round) {
  19174. var distance = Phaser.Math.distance(this.x, this.y, dest.x, dest.y);
  19175. return round ? Math.round(distance) : distance;
  19176. },
  19177. /**
  19178. * Returns a new Circle object with the same values for the x, y, width, and height properties as this Circle object.
  19179. * @method Phaser.Circle#clone
  19180. * @param {Phaser.Circle} output - Optional Circle object. If given the values will be set into the object, otherwise a brand new Circle object will be created and returned.
  19181. * @return {Phaser.Circle} The cloned Circle object.
  19182. */
  19183. clone: function (output) {
  19184. if (output === undefined || output === null)
  19185. {
  19186. output = new Phaser.Circle(this.x, this.y, this.diameter);
  19187. }
  19188. else
  19189. {
  19190. output.setTo(this.x, this.y, this.diameter);
  19191. }
  19192. return output;
  19193. },
  19194. /**
  19195. * Return true if the given x/y coordinates are within this Circle object.
  19196. * @method Phaser.Circle#contains
  19197. * @param {number} x - The X value of the coordinate to test.
  19198. * @param {number} y - The Y value of the coordinate to test.
  19199. * @return {boolean} True if the coordinates are within this circle, otherwise false.
  19200. */
  19201. contains: function (x, y) {
  19202. return Phaser.Circle.contains(this, x, y);
  19203. },
  19204. /**
  19205. * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle.
  19206. * @method Phaser.Circle#circumferencePoint
  19207. * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from.
  19208. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)?
  19209. * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specified a new Point object will be created.
  19210. * @return {Phaser.Point} The Point object holding the result.
  19211. */
  19212. circumferencePoint: function (angle, asDegrees, out) {
  19213. return Phaser.Circle.circumferencePoint(this, angle, asDegrees, out);
  19214. },
  19215. /**
  19216. * Creates or positions points on the circle.
  19217. *
  19218. * The points are equally distributed in the half-closed interval [startAngle, endAngle). The default arc is the entire circle.
  19219. *
  19220. * If the `out` argument is omitted, this method creates and returns an array of {@link Phaser.Point points}. If an array is passed as `out`, its items are treated as points and placed in the same way.
  19221. *
  19222. * @param {type} [steps=60] - The number of points to place.
  19223. * @param {type} [startAngle=0] - The starting angle in radians (unless asDegrees is true).
  19224. * @param {type} [endAngle=Phaser.Math.PI2] - The end angle in radians (unless asDegrees is true).
  19225. * @param {type} [asDegrees=false] - Are the given angles in radians (false) or degrees (true)?
  19226. * @param {any[]} [out] - An array of points or point-like objects (e.g., sprites). It should start at index 0 and its length should be equal to or greater than `steps`.
  19227. * @return {any[]} - The modified `out` argument or a new array of points.
  19228. */
  19229. sample: function (steps, startAngle, endAngle, asDegrees, out) {
  19230. if (!steps) { steps = 60; }
  19231. if (startAngle == null) { startAngle = 0; }
  19232. if (endAngle == null) { endAngle = Phaser.Math.PI2; }
  19233. if (!out) { out = []; }
  19234. var i = 0;
  19235. while (i < steps)
  19236. {
  19237. this.circumferencePoint(
  19238. Phaser.Math.linear(startAngle, endAngle, i / steps),
  19239. asDegrees,
  19240. out[i] || (out[i] = new Phaser.Point())
  19241. );
  19242. i += 1;
  19243. }
  19244. return out;
  19245. },
  19246. /**
  19247. * Adjusts the location of the Circle object, as determined by its center coordinate, by the specified amounts.
  19248. * @method Phaser.Circle#offset
  19249. * @param {number} dx - Moves the x value of the Circle object by this amount.
  19250. * @param {number} dy - Moves the y value of the Circle object by this amount.
  19251. * @return {Circle} This Circle object.
  19252. */
  19253. offset: function (dx, dy) {
  19254. this.x += dx;
  19255. this.y += dy;
  19256. return this;
  19257. },
  19258. /**
  19259. * Adjusts the location of the Circle object using a Point object as a parameter. This method is similar to the Circle.offset() method, except that it takes a Point object as a parameter.
  19260. * @method Phaser.Circle#offsetPoint
  19261. * @param {Point} point A Point object to use to offset this Circle object (or any valid object with exposed x and y properties).
  19262. * @return {Circle} This Circle object.
  19263. */
  19264. offsetPoint: function (point) {
  19265. return this.offset(point.x, point.y);
  19266. },
  19267. /**
  19268. * Returns a string representation of this object.
  19269. * @method Phaser.Circle#toString
  19270. * @return {string} a string representation of the instance.
  19271. */
  19272. toString: function () {
  19273. return "[{Phaser.Circle (x=" + this.x + " y=" + this.y + " diameter=" + this.diameter + " radius=" + this.radius + ")}]";
  19274. }
  19275. };
  19276. Phaser.Circle.prototype.constructor = Phaser.Circle;
  19277. /**
  19278. * The largest distance between any two points on the circle. The same as the radius * 2.
  19279. *
  19280. * @name Phaser.Circle#diameter
  19281. * @property {number} diameter - Gets or sets the diameter of the circle.
  19282. */
  19283. Object.defineProperty(Phaser.Circle.prototype, "diameter", {
  19284. get: function () {
  19285. return this._diameter;
  19286. },
  19287. set: function (value) {
  19288. if (value > 0)
  19289. {
  19290. this._diameter = value;
  19291. this._radius = value * 0.5;
  19292. }
  19293. }
  19294. });
  19295. /**
  19296. * The length of a line extending from the center of the circle to any point on the circle itself. The same as half the diameter.
  19297. * @name Phaser.Circle#radius
  19298. * @property {number} radius - Gets or sets the radius of the circle.
  19299. */
  19300. Object.defineProperty(Phaser.Circle.prototype, "radius", {
  19301. get: function () {
  19302. return this._radius;
  19303. },
  19304. set: function (value) {
  19305. if (value > 0)
  19306. {
  19307. this._radius = value;
  19308. this._diameter = value * 2;
  19309. }
  19310. }
  19311. });
  19312. /**
  19313. * The x coordinate of the leftmost point of the circle. Changing the left property of a Circle object has no effect on the x and y properties. However it does affect the diameter, whereas changing the x value does not affect the diameter property.
  19314. * @name Phaser.Circle#left
  19315. * @propety {number} left - Gets or sets the value of the leftmost point of the circle.
  19316. */
  19317. Object.defineProperty(Phaser.Circle.prototype, "left", {
  19318. get: function () {
  19319. return this.x - this._radius;
  19320. },
  19321. set: function (value) {
  19322. if (value > this.x)
  19323. {
  19324. this._radius = 0;
  19325. this._diameter = 0;
  19326. }
  19327. else
  19328. {
  19329. this.radius = this.x - value;
  19330. }
  19331. }
  19332. });
  19333. /**
  19334. * The x coordinate of the rightmost point of the circle. Changing the right property of a Circle object has no effect on the x and y properties. However it does affect the diameter, whereas changing the x value does not affect the diameter property.
  19335. * @name Phaser.Circle#right
  19336. * @property {number} right - Gets or sets the value of the rightmost point of the circle.
  19337. */
  19338. Object.defineProperty(Phaser.Circle.prototype, "right", {
  19339. get: function () {
  19340. return this.x + this._radius;
  19341. },
  19342. set: function (value) {
  19343. if (value < this.x)
  19344. {
  19345. this._radius = 0;
  19346. this._diameter = 0;
  19347. }
  19348. else
  19349. {
  19350. this.radius = value - this.x;
  19351. }
  19352. }
  19353. });
  19354. /**
  19355. * The sum of the y minus the radius property. Changing the top property of a Circle object has no effect on the x and y properties, but does change the diameter.
  19356. * @name Phaser.Circle#top
  19357. * @property {number} top - Gets or sets the top of the circle.
  19358. */
  19359. Object.defineProperty(Phaser.Circle.prototype, "top", {
  19360. get: function () {
  19361. return this.y - this._radius;
  19362. },
  19363. set: function (value) {
  19364. if (value > this.y)
  19365. {
  19366. this._radius = 0;
  19367. this._diameter = 0;
  19368. }
  19369. else
  19370. {
  19371. this.radius = this.y - value;
  19372. }
  19373. }
  19374. });
  19375. /**
  19376. * The sum of the y and radius properties. Changing the bottom property of a Circle object has no effect on the x and y properties, but does change the diameter.
  19377. * @name Phaser.Circle#bottom
  19378. * @property {number} bottom - Gets or sets the bottom of the circle.
  19379. */
  19380. Object.defineProperty(Phaser.Circle.prototype, "bottom", {
  19381. get: function () {
  19382. return this.y + this._radius;
  19383. },
  19384. set: function (value) {
  19385. if (value < this.y)
  19386. {
  19387. this._radius = 0;
  19388. this._diameter = 0;
  19389. }
  19390. else
  19391. {
  19392. this.radius = value - this.y;
  19393. }
  19394. }
  19395. });
  19396. /**
  19397. * The area of this Circle.
  19398. * @name Phaser.Circle#area
  19399. * @property {number} area - The area of this circle.
  19400. * @readonly
  19401. */
  19402. Object.defineProperty(Phaser.Circle.prototype, "area", {
  19403. get: function () {
  19404. if (this._radius > 0)
  19405. {
  19406. return Math.PI * this._radius * this._radius;
  19407. }
  19408. else
  19409. {
  19410. return 0;
  19411. }
  19412. }
  19413. });
  19414. /**
  19415. * Determines whether or not this Circle object is empty. Will return a value of true if the Circle objects diameter is less than or equal to 0; otherwise false.
  19416. * If set to true it will reset all of the Circle objects properties to 0. A Circle object is empty if its diameter is less than or equal to 0.
  19417. * @name Phaser.Circle#empty
  19418. * @property {boolean} empty - Gets or sets the empty state of the circle.
  19419. */
  19420. Object.defineProperty(Phaser.Circle.prototype, "empty", {
  19421. get: function () {
  19422. return (this._diameter === 0);
  19423. },
  19424. set: function (value) {
  19425. if (value === true)
  19426. {
  19427. this.setTo(0, 0, 0);
  19428. }
  19429. }
  19430. });
  19431. /**
  19432. * Return true if the given x/y coordinates are within the Circle object.
  19433. * @method Phaser.Circle.contains
  19434. * @param {Phaser.Circle} a - The Circle to be checked.
  19435. * @param {number} x - The X value of the coordinate to test.
  19436. * @param {number} y - The Y value of the coordinate to test.
  19437. * @return {boolean} True if the coordinates are within this circle, otherwise false.
  19438. */
  19439. Phaser.Circle.contains = function (a, x, y) {
  19440. // Check if x/y are within the bounds first
  19441. if (a.radius > 0 && x >= a.left && x <= a.right && y >= a.top && y <= a.bottom)
  19442. {
  19443. var dx = (a.x - x) * (a.x - x);
  19444. var dy = (a.y - y) * (a.y - y);
  19445. return (dx + dy) <= (a.radius * a.radius);
  19446. }
  19447. else
  19448. {
  19449. return false;
  19450. }
  19451. };
  19452. /**
  19453. * Determines whether the two Circle objects match. This method compares the x, y and diameter properties.
  19454. * @method Phaser.Circle.equals
  19455. * @param {Phaser.Circle} a - The first Circle object.
  19456. * @param {Phaser.Circle} b - The second Circle object.
  19457. * @return {boolean} A value of true if the object has exactly the same values for the x, y and diameter properties as this Circle object; otherwise false.
  19458. */
  19459. Phaser.Circle.equals = function (a, b) {
  19460. return (a.x === b.x && a.y === b.y && a.diameter === b.diameter);
  19461. };
  19462. /**
  19463. * Determines whether the two Circle objects intersect.
  19464. * This method checks the radius distances between the two Circle objects to see if they intersect.
  19465. * @method Phaser.Circle.intersects
  19466. * @param {Phaser.Circle} a - The first Circle object.
  19467. * @param {Phaser.Circle} b - The second Circle object.
  19468. * @return {boolean} A value of true if the specified object intersects with this Circle object; otherwise false.
  19469. */
  19470. Phaser.Circle.intersects = function (a, b) {
  19471. return (Phaser.Math.distance(a.x, a.y, b.x, b.y) <= (a.radius + b.radius));
  19472. };
  19473. /**
  19474. * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle.
  19475. * @method Phaser.Circle.circumferencePoint
  19476. * @param {Phaser.Circle} a - The first Circle object.
  19477. * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from.
  19478. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)?
  19479. * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specified a new Point object will be created.
  19480. * @return {Phaser.Point} The Point object holding the result.
  19481. */
  19482. Phaser.Circle.circumferencePoint = function (a, angle, asDegrees, out) {
  19483. if (asDegrees === undefined) { asDegrees = false; }
  19484. if (out === undefined) { out = new Phaser.Point(); }
  19485. if (asDegrees === true)
  19486. {
  19487. angle = Phaser.Math.degToRad(angle);
  19488. }
  19489. out.x = a.x + a.radius * Math.cos(angle);
  19490. out.y = a.y + a.radius * Math.sin(angle);
  19491. return out;
  19492. };
  19493. /**
  19494. * Checks if the given Circle and Rectangle objects intersect.
  19495. * @method Phaser.Circle.intersectsRectangle
  19496. * @param {Phaser.Circle} c - The Circle object to test.
  19497. * @param {Phaser.Rectangle} r - The Rectangle object to test.
  19498. * @return {boolean} True if the two objects intersect, otherwise false.
  19499. */
  19500. Phaser.Circle.intersectsRectangle = function (c, r) {
  19501. var cx = Math.abs(c.x - r.x - r.halfWidth);
  19502. var xDist = r.halfWidth + c.radius;
  19503. if (cx > xDist)
  19504. {
  19505. return false;
  19506. }
  19507. var cy = Math.abs(c.y - r.y - r.halfHeight);
  19508. var yDist = r.halfHeight + c.radius;
  19509. if (cy > yDist)
  19510. {
  19511. return false;
  19512. }
  19513. if (cx <= r.halfWidth || cy <= r.halfHeight)
  19514. {
  19515. return true;
  19516. }
  19517. var xCornerDist = cx - r.halfWidth;
  19518. var yCornerDist = cy - r.halfHeight;
  19519. var xCornerDistSq = xCornerDist * xCornerDist;
  19520. var yCornerDistSq = yCornerDist * yCornerDist;
  19521. var maxCornerDistSq = c.radius * c.radius;
  19522. return xCornerDistSq + yCornerDistSq <= maxCornerDistSq;
  19523. };
  19524. /**
  19525. * Checks if the given Circle and Line objects intersect.
  19526. * @method Phaser.Circle.intersectsLine
  19527. * @param {Phaser.Circle} c - The Circle object to test.
  19528. * @param {Phaser.Line} l - The Line object to test.
  19529. * @param {boolean} [returnpoints] - optional Array Object, Return an array of intersection points if true, otherwise return boolean.
  19530. * @return {boolean} True if the two objects intersect, otherwise false.
  19531. */
  19532. Phaser.Circle.intersectsLine = function (c, l, returnPoints) {
  19533. var h = c.x;
  19534. var k = c.y;
  19535. var m = ((l.end.y - l.start.y) / (l.end.x - l.start.x));
  19536. var n = l.end.y - (m * l.end.x);
  19537. var a = c.radius;
  19538. var b = c.radius;
  19539. var del = n + m * h;
  19540. var x0 = (h * (b * b) - m * (a * a) * (n - k) + a * b * (Math.sqrt((a * a) * (m * m) + (b * b) - (del * del) - (k * k) + (2 * del * k)))) / ((a * a) * (m * m) + (b * b));
  19541. var x1 = (h * (b * b) - m * (a * a) * (n - k) - a * b * (Math.sqrt((a * a) * (m * m) + (b * b) - (del * del) - (k * k) + (2 * del * k)))) / ((a * a) * (m * m) + (b * b));
  19542. var y0 = m * x0 + n;
  19543. var y1 = m * x1 + n;
  19544. var p0 = new Phaser.Point(x0, y0);
  19545. var p1 = new Phaser.Point(x1, y1);
  19546. var p0Exists = l.pointOnSegment(p0.x, p0.y, 0.01);
  19547. var p1Exists = l.pointOnSegment(p1.x, p1.y, 0.01);
  19548. if (p0Exists && p1Exists)
  19549. {
  19550. return returnPoints ? [p0, p1] : true;
  19551. }
  19552. else if (p0Exists)
  19553. {
  19554. return returnPoints ? [p0] : true;
  19555. }
  19556. else if (p1Exists)
  19557. {
  19558. return returnPoints ? [p1] : true;
  19559. }
  19560. else
  19561. {
  19562. return returnPoints ? [] : false;
  19563. }
  19564. };
  19565. // Because PIXI uses its own Circle, we'll replace it with ours to avoid duplicating code or confusion.
  19566. PIXI.Circle = Phaser.Circle;
  19567. /**
  19568. * @author Richard Davey <rich@photonstorm.com>
  19569. * @author Chad Engler <chad@pantherdev.com>
  19570. * @copyright 2016 Photon Storm Ltd.
  19571. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  19572. */
  19573. /**
  19574. * Creates a Ellipse object. A curve on a plane surrounding two focal points.
  19575. *
  19576. * @class Phaser.Ellipse
  19577. * @constructor
  19578. * @param {number} [x=0] - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
  19579. * @param {number} [y=0] - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
  19580. * @param {number} [width=0] - The overall width of this ellipse.
  19581. * @param {number} [height=0] - The overall height of this ellipse.
  19582. */
  19583. Phaser.Ellipse = function (x, y, width, height) {
  19584. x = x || 0;
  19585. y = y || 0;
  19586. width = width || 0;
  19587. height = height || 0;
  19588. /**
  19589. * @property {number} x - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
  19590. */
  19591. this.x = x;
  19592. /**
  19593. * @property {number} y - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
  19594. */
  19595. this.y = y;
  19596. /**
  19597. * @property {number} width - The overall width of this ellipse.
  19598. */
  19599. this.width = width;
  19600. /**
  19601. * @property {number} height - The overall height of this ellipse.
  19602. */
  19603. this.height = height;
  19604. /**
  19605. * @property {number} type - The const type of this object.
  19606. * @readonly
  19607. */
  19608. this.type = Phaser.ELLIPSE;
  19609. };
  19610. Phaser.Ellipse.prototype = {
  19611. /**
  19612. * Sets the members of the Ellipse to the specified values.
  19613. * @method Phaser.Ellipse#setTo
  19614. * @param {number} x - The X coordinate of the upper-left corner of the framing rectangle of this ellipse.
  19615. * @param {number} y - The Y coordinate of the upper-left corner of the framing rectangle of this ellipse.
  19616. * @param {number} width - The overall width of this ellipse.
  19617. * @param {number} height - The overall height of this ellipse.
  19618. * @return {Phaser.Ellipse} This Ellipse object.
  19619. */
  19620. setTo: function (x, y, width, height) {
  19621. this.x = x;
  19622. this.y = y;
  19623. this.width = width;
  19624. this.height = height;
  19625. return this;
  19626. },
  19627. /**
  19628. * Returns the framing rectangle of the ellipse as a Phaser.Rectangle object.
  19629. *
  19630. * @method Phaser.Ellipse#getBounds
  19631. * @return {Phaser.Rectangle} The bounds of the Ellipse.
  19632. */
  19633. getBounds: function () {
  19634. return new Phaser.Rectangle(this.x - this.width, this.y - this.height, this.width, this.height);
  19635. },
  19636. /**
  19637. * Copies the x, y, width and height properties from any given object to this Ellipse.
  19638. *
  19639. * @method Phaser.Ellipse#copyFrom
  19640. * @param {any} source - The object to copy from.
  19641. * @return {Phaser.Ellipse} This Ellipse object.
  19642. */
  19643. copyFrom: function (source) {
  19644. return this.setTo(source.x, source.y, source.width, source.height);
  19645. },
  19646. /**
  19647. * Copies the x, y, width and height properties from this Ellipse to any given object.
  19648. * @method Phaser.Ellipse#copyTo
  19649. * @param {any} dest - The object to copy to.
  19650. * @return {object} This dest object.
  19651. */
  19652. copyTo: function(dest) {
  19653. dest.x = this.x;
  19654. dest.y = this.y;
  19655. dest.width = this.width;
  19656. dest.height = this.height;
  19657. return dest;
  19658. },
  19659. /**
  19660. * Returns a new Ellipse object with the same values for the x, y, width, and height properties as this Ellipse object.
  19661. * @method Phaser.Ellipse#clone
  19662. * @param {Phaser.Ellipse} output - Optional Ellipse object. If given the values will be set into the object, otherwise a brand new Ellipse object will be created and returned.
  19663. * @return {Phaser.Ellipse} The cloned Ellipse object.
  19664. */
  19665. clone: function(output) {
  19666. if (output === undefined || output === null)
  19667. {
  19668. output = new Phaser.Ellipse(this.x, this.y, this.width, this.height);
  19669. }
  19670. else
  19671. {
  19672. output.setTo(this.x, this.y, this.width, this.height);
  19673. }
  19674. return output;
  19675. },
  19676. /**
  19677. * Return true if the given x/y coordinates are within this Ellipse object.
  19678. *
  19679. * @method Phaser.Ellipse#contains
  19680. * @param {number} x - The X value of the coordinate to test.
  19681. * @param {number} y - The Y value of the coordinate to test.
  19682. * @return {boolean} True if the coordinates are within this ellipse, otherwise false.
  19683. */
  19684. contains: function (x, y) {
  19685. return Phaser.Ellipse.contains(this, x, y);
  19686. },
  19687. /**
  19688. * Returns a uniformly distributed random point from anywhere within this Ellipse.
  19689. *
  19690. * @method Phaser.Ellipse#random
  19691. * @param {Phaser.Point|object} [out] - A Phaser.Point, or any object with public x/y properties, that the values will be set in.
  19692. * If no object is provided a new Phaser.Point object will be created. In high performance areas avoid this by re-using an existing object.
  19693. * @return {Phaser.Point} An object containing the random point in its `x` and `y` properties.
  19694. */
  19695. random: function (out) {
  19696. if (out === undefined) { out = new Phaser.Point(); }
  19697. var p = Math.random() * Math.PI * 2;
  19698. var r = Math.random();
  19699. out.x = Math.sqrt(r) * Math.cos(p);
  19700. out.y = Math.sqrt(r) * Math.sin(p);
  19701. out.x = this.x + (out.x * this.width / 2.0);
  19702. out.y = this.y + (out.y * this.height / 2.0);
  19703. return out;
  19704. },
  19705. /**
  19706. * Returns a string representation of this object.
  19707. * @method Phaser.Ellipse#toString
  19708. * @return {string} A string representation of the instance.
  19709. */
  19710. toString: function () {
  19711. return "[{Phaser.Ellipse (x=" + this.x + " y=" + this.y + " width=" + this.width + " height=" + this.height + ")}]";
  19712. }
  19713. };
  19714. Phaser.Ellipse.prototype.constructor = Phaser.Ellipse;
  19715. /**
  19716. * The left coordinate of the Ellipse. The same as the X coordinate.
  19717. * @name Phaser.Ellipse#left
  19718. * @propety {number} left - Gets or sets the value of the leftmost point of the ellipse.
  19719. */
  19720. Object.defineProperty(Phaser.Ellipse.prototype, "left", {
  19721. get: function () {
  19722. return this.x;
  19723. },
  19724. set: function (value) {
  19725. this.x = value;
  19726. }
  19727. });
  19728. /**
  19729. * The x coordinate of the rightmost point of the Ellipse. Changing the right property of an Ellipse object has no effect on the x property, but does adjust the width.
  19730. * @name Phaser.Ellipse#right
  19731. * @property {number} right - Gets or sets the value of the rightmost point of the ellipse.
  19732. */
  19733. Object.defineProperty(Phaser.Ellipse.prototype, "right", {
  19734. get: function () {
  19735. return this.x + this.width;
  19736. },
  19737. set: function (value) {
  19738. if (value < this.x)
  19739. {
  19740. this.width = 0;
  19741. }
  19742. else
  19743. {
  19744. this.width = value - this.x;
  19745. }
  19746. }
  19747. });
  19748. /**
  19749. * The top of the Ellipse. The same as its y property.
  19750. * @name Phaser.Ellipse#top
  19751. * @property {number} top - Gets or sets the top of the ellipse.
  19752. */
  19753. Object.defineProperty(Phaser.Ellipse.prototype, "top", {
  19754. get: function () {
  19755. return this.y;
  19756. },
  19757. set: function (value) {
  19758. this.y = value;
  19759. }
  19760. });
  19761. /**
  19762. * The sum of the y and height properties. Changing the bottom property of an Ellipse doesn't adjust the y property, but does change the height.
  19763. * @name Phaser.Ellipse#bottom
  19764. * @property {number} bottom - Gets or sets the bottom of the ellipse.
  19765. */
  19766. Object.defineProperty(Phaser.Ellipse.prototype, "bottom", {
  19767. get: function () {
  19768. return this.y + this.height;
  19769. },
  19770. set: function (value) {
  19771. if (value < this.y)
  19772. {
  19773. this.height = 0;
  19774. }
  19775. else
  19776. {
  19777. this.height = value - this.y;
  19778. }
  19779. }
  19780. });
  19781. /**
  19782. * Determines whether or not this Ellipse object is empty. Will return a value of true if the Ellipse objects dimensions are less than or equal to 0; otherwise false.
  19783. * If set to true it will reset all of the Ellipse objects properties to 0. An Ellipse object is empty if its width or height is less than or equal to 0.
  19784. * @name Phaser.Ellipse#empty
  19785. * @property {boolean} empty - Gets or sets the empty state of the ellipse.
  19786. */
  19787. Object.defineProperty(Phaser.Ellipse.prototype, "empty", {
  19788. get: function () {
  19789. return (this.width === 0 || this.height === 0);
  19790. },
  19791. set: function (value) {
  19792. if (value === true)
  19793. {
  19794. this.setTo(0, 0, 0, 0);
  19795. }
  19796. }
  19797. });
  19798. /**
  19799. * Return true if the given x/y coordinates are within the Ellipse object.
  19800. *
  19801. * @method Phaser.Ellipse.contains
  19802. * @param {Phaser.Ellipse} a - The Ellipse to be checked.
  19803. * @param {number} x - The X value of the coordinate to test.
  19804. * @param {number} y - The Y value of the coordinate to test.
  19805. * @return {boolean} True if the coordinates are within this ellipse, otherwise false.
  19806. */
  19807. Phaser.Ellipse.contains = function (a, x, y) {
  19808. if (a.width <= 0 || a.height <= 0) {
  19809. return false;
  19810. }
  19811. // Normalize the coords to an ellipse with center 0,0 and a radius of 0.5
  19812. var normx = ((x - a.x) / a.width) - 0.5;
  19813. var normy = ((y - a.y) / a.height) - 0.5;
  19814. normx *= normx;
  19815. normy *= normy;
  19816. return (normx + normy < 0.25);
  19817. };
  19818. /**
  19819. * Checks if the given Ellipse and Line objects intersect.
  19820. * @method Phaser.Ellipse.intersectsLine
  19821. * @param {Phaser.Ellipse} e - The Ellipse object to test.
  19822. * @param {Phaser.Line} l - The Line object to test.
  19823. * @param {boolean} [returnPoints] - optional Array Object, Return an array of intersection points if true, otherwise return boolean.
  19824. * @return {boolean} True if the two objects intersect, otherwise false.
  19825. */
  19826. Phaser.Ellipse.intersectsLine = function (e, l, returnPoints) {
  19827. var h = e.x;
  19828. var k = e.y;
  19829. var m = ((l.end.y - l.start.y) / (l.end.x - l.start.x));
  19830. var n = l.end.y - (m * l.end.x);
  19831. var a = e.width / 2;
  19832. var b = e.height / 2;
  19833. var del = n + m * h;
  19834. var x0 = (h * (b * b) - m * (a * a) * (n - k) + a * b * (Math.sqrt((a * a) * (m * m) + (b * b) - (del * del) - (k * k) + (2 * del * k)))) / ((a * a) * (m * m) + (b * b));
  19835. var x1 = (h * (b * b) - m * (a * a) * (n - k) - a * b * (Math.sqrt((a * a) * (m * m) + (b * b) - (del * del) - (k * k) + (2 * del * k)))) / ((a * a) * (m * m) + (b * b));
  19836. var y0 = m * x0 + n;
  19837. var y1 = m * x1 + n;
  19838. var p0 = new Phaser.Point(x0, y0);
  19839. var p1 = new Phaser.Point(x1, y1);
  19840. var p0Exists = l.pointOnSegment(p0.x, p0.y, 0.01);
  19841. var p1Exists = l.pointOnSegment(p1.x, p1.y, 0.01);
  19842. if (p0Exists && p1Exists)
  19843. {
  19844. return returnPoints ? [p0, p1] : true;
  19845. }
  19846. else if (p0Exists)
  19847. {
  19848. return returnPoints ? [p0] : true;
  19849. }
  19850. else if (p1Exists)
  19851. {
  19852. return returnPoints ? [p1] : true;
  19853. }
  19854. else
  19855. {
  19856. return returnPoints ? [] : false;
  19857. }
  19858. };
  19859. // Because PIXI uses its own Ellipse, we'll replace it with ours to avoid duplicating code or confusion.
  19860. PIXI.Ellipse = Phaser.Ellipse;
  19861. /**
  19862. * @author Richard Davey <rich@photonstorm.com>
  19863. * @copyright 2016 Photon Storm Ltd.
  19864. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  19865. */
  19866. /**
  19867. * Creates a new Line object with a start and an end point.
  19868. *
  19869. * @class Phaser.Line
  19870. * @constructor
  19871. * @param {number} [x1=0] - The x coordinate of the start of the line.
  19872. * @param {number} [y1=0] - The y coordinate of the start of the line.
  19873. * @param {number} [x2=0] - The x coordinate of the end of the line.
  19874. * @param {number} [y2=0] - The y coordinate of the end of the line.
  19875. */
  19876. Phaser.Line = function (x1, y1, x2, y2) {
  19877. x1 = x1 || 0;
  19878. y1 = y1 || 0;
  19879. x2 = x2 || 0;
  19880. y2 = y2 || 0;
  19881. /**
  19882. * @property {Phaser.Point} start - The start point of the line.
  19883. */
  19884. this.start = new Phaser.Point(x1, y1);
  19885. /**
  19886. * @property {Phaser.Point} end - The end point of the line.
  19887. */
  19888. this.end = new Phaser.Point(x2, y2);
  19889. /**
  19890. * @property {number} type - The const type of this object.
  19891. * @readonly
  19892. */
  19893. this.type = Phaser.LINE;
  19894. };
  19895. Phaser.Line.prototype = {
  19896. /**
  19897. * Sets the components of the Line to the specified values.
  19898. *
  19899. * @method Phaser.Line#setTo
  19900. * @param {number} [x1=0] - The x coordinate of the start of the line.
  19901. * @param {number} [y1=0] - The y coordinate of the start of the line.
  19902. * @param {number} [x2=0] - The x coordinate of the end of the line.
  19903. * @param {number} [y2=0] - The y coordinate of the end of the line.
  19904. * @return {Phaser.Line} This line object
  19905. */
  19906. setTo: function (x1, y1, x2, y2) {
  19907. this.start.setTo(x1, y1);
  19908. this.end.setTo(x2, y2);
  19909. return this;
  19910. },
  19911. /**
  19912. * Sets the line to match the x/y coordinates of the two given sprites.
  19913. * Can optionally be calculated from their center coordinates.
  19914. *
  19915. * @method Phaser.Line#fromSprite
  19916. * @param {Phaser.Sprite} startSprite - The coordinates of this Sprite will be set to the Line.start point.
  19917. * @param {Phaser.Sprite} endSprite - The coordinates of this Sprite will be set to the Line.start point.
  19918. * @param {boolean} [useCenter=false] - If true it will use startSprite.centerX, if false startSprite.x.
  19919. * @return {Phaser.Line} This line object
  19920. */
  19921. fromSprite: function (startSprite, endSprite, useCenter) {
  19922. if (useCenter === undefined) { useCenter = false; }
  19923. if (useCenter)
  19924. {
  19925. return this.setTo(startSprite.centerX, startSprite.centerY, endSprite.centerX, endSprite.centerY);
  19926. }
  19927. return this.setTo(startSprite.x, startSprite.y, endSprite.x, endSprite.y);
  19928. },
  19929. /**
  19930. * Sets this line to start at the given `x` and `y` coordinates and for the segment to extend at `angle` for the given `length`.
  19931. *
  19932. * @method Phaser.Line#fromAngle
  19933. * @param {number} x - The x coordinate of the start of the line.
  19934. * @param {number} y - The y coordinate of the start of the line.
  19935. * @param {number} angle - The angle of the line in radians.
  19936. * @param {number} length - The length of the line in pixels.
  19937. * @return {Phaser.Line} This line object
  19938. */
  19939. fromAngle: function (x, y, angle, length) {
  19940. this.start.setTo(x, y);
  19941. this.end.setTo(x + (Math.cos(angle) * length), y + (Math.sin(angle) * length));
  19942. return this;
  19943. },
  19944. /**
  19945. * Rotates the line by the amount specified in `angle`.
  19946. *
  19947. * Rotation takes place from the center of the line.
  19948. * If you wish to rotate around a different point see Line.rotateAround.
  19949. *
  19950. * If you wish to rotate the ends of the Line then see Line.start.rotate or Line.end.rotate.
  19951. *
  19952. * @method Phaser.Line#rotate
  19953. * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the line by.
  19954. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)?
  19955. * @return {Phaser.Line} This line object
  19956. */
  19957. rotate: function (angle, asDegrees) {
  19958. var cx = (this.start.x + this.end.x) / 2;
  19959. var cy = (this.start.y + this.end.y) / 2;
  19960. this.start.rotate(cx, cy, angle, asDegrees);
  19961. this.end.rotate(cx, cy, angle, asDegrees);
  19962. return this;
  19963. },
  19964. /**
  19965. * Rotates the line by the amount specified in `angle`.
  19966. *
  19967. * Rotation takes place around the coordinates given.
  19968. *
  19969. * @method Phaser.Line#rotateAround
  19970. * @param {number} x - The x coordinate to offset the rotation from.
  19971. * @param {number} y - The y coordinate to offset the rotation from.
  19972. * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the line by.
  19973. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)?
  19974. * @return {Phaser.Line} This line object
  19975. */
  19976. rotateAround: function (x, y, angle, asDegrees) {
  19977. this.start.rotate(x, y, angle, asDegrees);
  19978. this.end.rotate(x, y, angle, asDegrees);
  19979. return this;
  19980. },
  19981. /**
  19982. * Checks for intersection between this line and another Line.
  19983. * If asSegment is true it will check for segment intersection. If asSegment is false it will check for line intersection.
  19984. * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
  19985. *
  19986. * @method Phaser.Line#intersects
  19987. * @param {Phaser.Line} line - The line to check against this one.
  19988. * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
  19989. * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
  19990. * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
  19991. */
  19992. intersects: function (line, asSegment, result) {
  19993. return Phaser.Line.intersectsPoints(this.start, this.end, line.start, line.end, asSegment, result);
  19994. },
  19995. /**
  19996. * Returns the reflected angle between two lines.
  19997. * This is the outgoing angle based on the angle of this line and the normalAngle of the given line.
  19998. *
  19999. * @method Phaser.Line#reflect
  20000. * @param {Phaser.Line} line - The line to reflect off this line.
  20001. * @return {number} The reflected angle in radians.
  20002. */
  20003. reflect: function (line) {
  20004. return Phaser.Line.reflect(this, line);
  20005. },
  20006. /**
  20007. * Returns a Point object where the x and y values correspond to the center (or midpoint) of the Line segment.
  20008. *
  20009. * @method Phaser.Line#midPoint
  20010. * @param {Phaser.Point} [out] - A Phaser.Point object into which the result will be populated. If not given a new Point object is created.
  20011. * @return {Phaser.Point} A Phaser.Point object with the x and y values set to the center of the line segment.
  20012. */
  20013. midPoint: function (out) {
  20014. if (out === undefined) { out = new Phaser.Point(); }
  20015. out.x = (this.start.x + this.end.x) / 2;
  20016. out.y = (this.start.y + this.end.y) / 2;
  20017. return out;
  20018. },
  20019. /**
  20020. * Centers this Line on the given coordinates.
  20021. *
  20022. * The line is centered by positioning the start and end points so that the lines midpoint matches
  20023. * the coordinates given.
  20024. *
  20025. * @method Phaser.Line#centerOn
  20026. * @param {number} x - The x position to center the line on.
  20027. * @param {number} y - The y position to center the line on.
  20028. * @return {Phaser.Line} This line object
  20029. */
  20030. centerOn: function (x, y) {
  20031. var cx = (this.start.x + this.end.x) / 2;
  20032. var cy = (this.start.y + this.end.y) / 2;
  20033. var tx = x - cx;
  20034. var ty = y - cy;
  20035. this.start.add(tx, ty);
  20036. this.end.add(tx, ty);
  20037. },
  20038. /**
  20039. * Tests if the given coordinates fall on this line. See {@link #pointOnSegment} to test against just the line segment.
  20040. *
  20041. * @method Phaser.Line#pointOnLine
  20042. * @param {number} x - The line to check against this one.
  20043. * @param {number} y - The line to check against this one.
  20044. * @param {number} [epsilon=0] - Range for a fuzzy comparison, e.g., 0.0001.
  20045. * @return {boolean} True if the point is on the line, false if not.
  20046. */
  20047. pointOnLine: function (x, y, epsilon) {
  20048. return Phaser.Math.fuzzyEqual((x - this.start.x) * (this.end.y - this.start.y), (this.end.x - this.start.x) * (y - this.start.y), epsilon || 0);
  20049. },
  20050. /**
  20051. * Tests if the given coordinates fall on this line and within the segment. See {@link #pointOnLine} to test against just the line.
  20052. *
  20053. * @method Phaser.Line#pointOnSegment
  20054. * @param {number} x - The line to check against this one.
  20055. * @param {number} y - The line to check against this one.
  20056. * @param {number} [epsilon=0] - Range for a fuzzy comparison, e.g., 0.0001.
  20057. * @return {boolean} True if the point is on the line and segment, false if not.
  20058. */
  20059. pointOnSegment: function (x, y, epsilon) {
  20060. var xMin = Math.min(this.start.x, this.end.x);
  20061. var xMax = Math.max(this.start.x, this.end.x);
  20062. var yMin = Math.min(this.start.y, this.end.y);
  20063. var yMax = Math.max(this.start.y, this.end.y);
  20064. return (this.pointOnLine(x, y, epsilon) && (x >= xMin && x <= xMax) && (y >= yMin && y <= yMax));
  20065. },
  20066. /**
  20067. * Picks a random point from anywhere on the Line segment and returns it.
  20068. *
  20069. * @method Phaser.Line#random
  20070. * @param {Phaser.Point|object} [out] - A Phaser.Point, or any object with public x/y properties, that the values will be set in.
  20071. * If no object is provided a new Phaser.Point object will be created. In high performance areas avoid this by re-using an object.
  20072. * @return {Phaser.Point} An object containing the random point in its `x` and `y` properties.
  20073. */
  20074. random: function (out) {
  20075. if (out === undefined) { out = new Phaser.Point(); }
  20076. var t = Math.random();
  20077. out.x = this.start.x + t * (this.end.x - this.start.x);
  20078. out.y = this.start.y + t * (this.end.y - this.start.y);
  20079. return out;
  20080. },
  20081. /**
  20082. * Using Bresenham's line algorithm this will return an array of all coordinates on this line.
  20083. * The start and end points are rounded before this runs as the algorithm works on integers.
  20084. *
  20085. * @method Phaser.Line#coordinatesOnLine
  20086. * @param {number} [stepRate=1] - How many steps will we return? 1 = every coordinate on the line, 2 = every other coordinate, etc.
  20087. * @param {array} [results] - The array to store the results in. If not provided a new one will be generated.
  20088. * @return {array} An array of coordinates.
  20089. */
  20090. coordinatesOnLine: function (stepRate, results) {
  20091. if (stepRate === undefined) { stepRate = 1; }
  20092. if (results === undefined) { results = []; }
  20093. var x1 = Math.round(this.start.x);
  20094. var y1 = Math.round(this.start.y);
  20095. var x2 = Math.round(this.end.x);
  20096. var y2 = Math.round(this.end.y);
  20097. var dx = Math.abs(x2 - x1);
  20098. var dy = Math.abs(y2 - y1);
  20099. var sx = (x1 < x2) ? 1 : -1;
  20100. var sy = (y1 < y2) ? 1 : -1;
  20101. var err = dx - dy;
  20102. results.push([x1, y1]);
  20103. var i = 1;
  20104. while (!((x1 === x2) && (y1 === y2)))
  20105. {
  20106. var e2 = err << 1;
  20107. if (e2 > -dy)
  20108. {
  20109. err -= dy;
  20110. x1 += sx;
  20111. }
  20112. if (e2 < dx)
  20113. {
  20114. err += dx;
  20115. y1 += sy;
  20116. }
  20117. if (i % stepRate === 0)
  20118. {
  20119. results.push([x1, y1]);
  20120. }
  20121. i++;
  20122. }
  20123. return results;
  20124. },
  20125. /**
  20126. * Returns a new Line object with the same values for the start and end properties as this Line object.
  20127. * @method Phaser.Line#clone
  20128. * @param {Phaser.Line} output - Optional Line object. If given the values will be set into the object, otherwise a brand new Line object will be created and returned.
  20129. * @return {Phaser.Line} The cloned Line object.
  20130. */
  20131. clone: function (output) {
  20132. if (output === undefined || output === null)
  20133. {
  20134. output = new Phaser.Line(this.start.x, this.start.y, this.end.x, this.end.y);
  20135. }
  20136. else
  20137. {
  20138. output.setTo(this.start.x, this.start.y, this.end.x, this.end.y);
  20139. }
  20140. return output;
  20141. }
  20142. };
  20143. /**
  20144. * @name Phaser.Line#length
  20145. * @property {number} length - Gets the length of the line segment.
  20146. * @readonly
  20147. */
  20148. Object.defineProperty(Phaser.Line.prototype, "length", {
  20149. get: function () {
  20150. return Math.sqrt((this.end.x - this.start.x) * (this.end.x - this.start.x) + (this.end.y - this.start.y) * (this.end.y - this.start.y));
  20151. }
  20152. });
  20153. /**
  20154. * @name Phaser.Line#angle
  20155. * @property {number} angle - Gets the angle of the line in radians.
  20156. * @readonly
  20157. */
  20158. Object.defineProperty(Phaser.Line.prototype, "angle", {
  20159. get: function () {
  20160. return Math.atan2(this.end.y - this.start.y, this.end.x - this.start.x);
  20161. }
  20162. });
  20163. /**
  20164. * @name Phaser.Line#slope
  20165. * @property {number} slope - Gets the slope of the line (y/x).
  20166. * @readonly
  20167. */
  20168. Object.defineProperty(Phaser.Line.prototype, "slope", {
  20169. get: function () {
  20170. return (this.end.y - this.start.y) / (this.end.x - this.start.x);
  20171. }
  20172. });
  20173. /**
  20174. * @name Phaser.Line#perpSlope
  20175. * @property {number} perpSlope - Gets the perpendicular slope of the line (x/y).
  20176. * @readonly
  20177. */
  20178. Object.defineProperty(Phaser.Line.prototype, "perpSlope", {
  20179. get: function () {
  20180. return -((this.end.x - this.start.x) / (this.end.y - this.start.y));
  20181. }
  20182. });
  20183. /**
  20184. * @name Phaser.Line#x
  20185. * @property {number} x - Gets the x coordinate of the top left of the bounds around this line.
  20186. * @readonly
  20187. */
  20188. Object.defineProperty(Phaser.Line.prototype, "x", {
  20189. get: function () {
  20190. return Math.min(this.start.x, this.end.x);
  20191. }
  20192. });
  20193. /**
  20194. * @name Phaser.Line#y
  20195. * @property {number} y - Gets the y coordinate of the top left of the bounds around this line.
  20196. * @readonly
  20197. */
  20198. Object.defineProperty(Phaser.Line.prototype, "y", {
  20199. get: function () {
  20200. return Math.min(this.start.y, this.end.y);
  20201. }
  20202. });
  20203. /**
  20204. * @name Phaser.Line#left
  20205. * @property {number} left - Gets the left-most point of this line.
  20206. * @readonly
  20207. */
  20208. Object.defineProperty(Phaser.Line.prototype, "left", {
  20209. get: function () {
  20210. return Math.min(this.start.x, this.end.x);
  20211. }
  20212. });
  20213. /**
  20214. * @name Phaser.Line#right
  20215. * @property {number} right - Gets the right-most point of this line.
  20216. * @readonly
  20217. */
  20218. Object.defineProperty(Phaser.Line.prototype, "right", {
  20219. get: function () {
  20220. return Math.max(this.start.x, this.end.x);
  20221. }
  20222. });
  20223. /**
  20224. * @name Phaser.Line#top
  20225. * @property {number} top - Gets the top-most point of this line.
  20226. * @readonly
  20227. */
  20228. Object.defineProperty(Phaser.Line.prototype, "top", {
  20229. get: function () {
  20230. return Math.min(this.start.y, this.end.y);
  20231. }
  20232. });
  20233. /**
  20234. * @name Phaser.Line#bottom
  20235. * @property {number} bottom - Gets the bottom-most point of this line.
  20236. * @readonly
  20237. */
  20238. Object.defineProperty(Phaser.Line.prototype, "bottom", {
  20239. get: function () {
  20240. return Math.max(this.start.y, this.end.y);
  20241. }
  20242. });
  20243. /**
  20244. * @name Phaser.Line#width
  20245. * @property {number} width - Gets the width of this bounds of this line.
  20246. * @readonly
  20247. */
  20248. Object.defineProperty(Phaser.Line.prototype, "width", {
  20249. get: function () {
  20250. return Math.abs(this.start.x - this.end.x);
  20251. }
  20252. });
  20253. /**
  20254. * @name Phaser.Line#height
  20255. * @property {number} height - Gets the height of this bounds of this line.
  20256. * @readonly
  20257. */
  20258. Object.defineProperty(Phaser.Line.prototype, "height", {
  20259. get: function () {
  20260. return Math.abs(this.start.y - this.end.y);
  20261. }
  20262. });
  20263. /**
  20264. * @name Phaser.Line#normalX
  20265. * @property {number} normalX - Gets the x component of the left-hand normal of this line.
  20266. * @readonly
  20267. */
  20268. Object.defineProperty(Phaser.Line.prototype, "normalX", {
  20269. get: function () {
  20270. return Math.cos(this.angle - 1.5707963267948966);
  20271. }
  20272. });
  20273. /**
  20274. * @name Phaser.Line#normalY
  20275. * @property {number} normalY - Gets the y component of the left-hand normal of this line.
  20276. * @readonly
  20277. */
  20278. Object.defineProperty(Phaser.Line.prototype, "normalY", {
  20279. get: function () {
  20280. return Math.sin(this.angle - 1.5707963267948966);
  20281. }
  20282. });
  20283. /**
  20284. * @name Phaser.Line#normalAngle
  20285. * @property {number} normalAngle - Gets the angle in radians of the normal of this line (line.angle - 90 degrees.)
  20286. * @readonly
  20287. */
  20288. Object.defineProperty(Phaser.Line.prototype, "normalAngle", {
  20289. get: function () {
  20290. return Phaser.Math.wrap(this.angle - 1.5707963267948966, -Math.PI, Math.PI);
  20291. }
  20292. });
  20293. /**
  20294. * Checks for intersection between two lines as defined by the given start and end points.
  20295. * If asSegment is true it will check for line segment intersection. If asSegment is false it will check for line intersection.
  20296. * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
  20297. * Adapted from code by Keith Hair
  20298. *
  20299. * @method Phaser.Line.intersectsPoints
  20300. * @param {Phaser.Point} a - The start of the first Line to be checked.
  20301. * @param {Phaser.Point} b - The end of the first line to be checked.
  20302. * @param {Phaser.Point} e - The start of the second Line to be checked.
  20303. * @param {Phaser.Point} f - The end of the second line to be checked.
  20304. * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
  20305. * @param {Phaser.Point|object} [result] - A Point object to store the result in, if not given a new one will be created.
  20306. * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
  20307. */
  20308. Phaser.Line.intersectsPoints = function (a, b, e, f, asSegment, result) {
  20309. if (asSegment === undefined) { asSegment = true; }
  20310. if (result === undefined) { result = new Phaser.Point(); }
  20311. var a1 = b.y - a.y;
  20312. var a2 = f.y - e.y;
  20313. var b1 = a.x - b.x;
  20314. var b2 = e.x - f.x;
  20315. var c1 = (b.x * a.y) - (a.x * b.y);
  20316. var c2 = (f.x * e.y) - (e.x * f.y);
  20317. var denom = (a1 * b2) - (a2 * b1);
  20318. if (denom === 0)
  20319. {
  20320. return null;
  20321. }
  20322. result.x = ((b1 * c2) - (b2 * c1)) / denom;
  20323. result.y = ((a2 * c1) - (a1 * c2)) / denom;
  20324. if (asSegment)
  20325. {
  20326. var uc = ((f.y - e.y) * (b.x - a.x) - (f.x - e.x) * (b.y - a.y));
  20327. var ua = (((f.x - e.x) * (a.y - e.y)) - (f.y - e.y) * (a.x - e.x)) / uc;
  20328. var ub = (((b.x - a.x) * (a.y - e.y)) - ((b.y - a.y) * (a.x - e.x))) / uc;
  20329. if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
  20330. {
  20331. return result;
  20332. }
  20333. else
  20334. {
  20335. return null;
  20336. }
  20337. }
  20338. return result;
  20339. };
  20340. /**
  20341. * Checks for intersection between two lines.
  20342. * If asSegment is true it will check for segment intersection.
  20343. * If asSegment is false it will check for line intersection.
  20344. * Returns the intersection segment of AB and EF as a Point, or null if there is no intersection.
  20345. * Adapted from code by Keith Hair
  20346. *
  20347. * @method Phaser.Line.intersects
  20348. * @param {Phaser.Line} a - The first Line to be checked.
  20349. * @param {Phaser.Line} b - The second Line to be checked.
  20350. * @param {boolean} [asSegment=true] - If true it will check for segment intersection, otherwise full line intersection.
  20351. * @param {Phaser.Point} [result] - A Point object to store the result in, if not given a new one will be created.
  20352. * @return {Phaser.Point} The intersection segment of the two lines as a Point, or null if there is no intersection.
  20353. */
  20354. Phaser.Line.intersects = function (a, b, asSegment, result) {
  20355. return Phaser.Line.intersectsPoints(a.start, a.end, b.start, b.end, asSegment, result);
  20356. };
  20357. /**
  20358. * Checks for intersection between the Line and a Rectangle shape, or a rectangle-like
  20359. * object, with public `x`, `y`, `right` and `bottom` properties, such as a Sprite or Body.
  20360. *
  20361. * An intersection is considered valid if:
  20362. *
  20363. * The line starts within or ends within the rectangle; or
  20364. * The line segment intersects one of the 4 rectangle edges; and
  20365. * The line has a non-zero length; and
  20366. * The rectangle is not empty.
  20367. *
  20368. * For the purposes of this function rectangles are considered 'solid'.
  20369. *
  20370. * @method Phaser.Line.intersectsRectangle
  20371. * @param {Phaser.Line} line - The line to check for intersection with.
  20372. * @param {Phaser.Rectangle|object} rect - The rectangle, or rectangle-like object, to check for intersection with.
  20373. * @return {boolean} True if the line intersects with the rectangle edges, or starts or ends within the rectangle.
  20374. */
  20375. Phaser.Line.intersectsRectangle = function (line, rect) {
  20376. // Quick bail out
  20377. if (line.length === 0 || rect.empty)
  20378. {
  20379. return false;
  20380. }
  20381. var x1 = line.start.x;
  20382. var y1 = line.start.y;
  20383. var x2 = line.end.x;
  20384. var y2 = line.end.y;
  20385. var bx1 = rect.x;
  20386. var by1 = rect.y;
  20387. var bx2 = rect.right;
  20388. var by2 = rect.bottom;
  20389. var t = 0;
  20390. // If the start or end of the line is inside the rect then we assume
  20391. // collision, as rects are solid for our use-case.
  20392. if ((x1 >= bx1 && x1 <= bx2 && y1 >= by1 && y1 <= by2) ||
  20393. (x2 >= bx1 && x2 <= bx2 && y2 >= by1 && y2 <= by2))
  20394. {
  20395. return true;
  20396. }
  20397. if (x1 < bx1 && x2 >= bx1)
  20398. {
  20399. // Left edge
  20400. t = y1 + (y2 - y1) * (bx1 - x1) / (x2 - x1);
  20401. if (t > by1 && t <= by2)
  20402. {
  20403. return true;
  20404. }
  20405. }
  20406. else if (x1 > bx2 && x2 <= bx2)
  20407. {
  20408. // Right edge
  20409. t = y1 + (y2 - y1) * (bx2 - x1) / (x2 - x1);
  20410. if (t >= by1 && t <= by2)
  20411. {
  20412. return true;
  20413. }
  20414. }
  20415. if (y1 < by1 && y2 >= by1)
  20416. {
  20417. // Top edge
  20418. t = x1 + (x2 - x1) * (by1 - y1) / (y2 - y1);
  20419. if (t >= bx1 && t <= bx2)
  20420. {
  20421. return true;
  20422. }
  20423. }
  20424. else if (y1 > by2 && y2 <= by2)
  20425. {
  20426. // Bottom edge
  20427. t = x1 + (x2 - x1) * (by2 - y1) / (y2 - y1);
  20428. if (t >= bx1 && t <= bx2)
  20429. {
  20430. return true;
  20431. }
  20432. }
  20433. return false;
  20434. };
  20435. /**
  20436. * Finds the closest intersection between the Line and a Rectangle shape, or a rectangle-like
  20437. * object, such as a Sprite or Body.
  20438. *
  20439. * @method Phaser.Line.intersectionWithRectangle
  20440. * @param {Phaser.Line} line - The line to check for intersection with.
  20441. * @param {Phaser.Rectangle} rect - The rectangle, or rectangle-like object, to check for intersection with.
  20442. * @param {Phaser.Point} [result] - A Point object to store the result in.
  20443. * @return {?Phaser.Point} - The intersection closest to the Line's start, or null if there is no intersection.
  20444. */
  20445. Phaser.Line.intersectionWithRectangle = function (line, rect, result) {
  20446. var self = Phaser.Line.intersectionWithRectangle;
  20447. if (!result)
  20448. {
  20449. result = new Phaser.Point();
  20450. }
  20451. if (!self.edges)
  20452. {
  20453. self.edges = [new Phaser.Line(), new Phaser.Line(), new Phaser.Line(), new Phaser.Line()];
  20454. }
  20455. if (!self.edgeIntersection)
  20456. {
  20457. self.edgeIntersection = new Phaser.Point();
  20458. }
  20459. var edges = self.edges;
  20460. var edgeIntersection = self.edgeIntersection.set(0);
  20461. var bx1 = rect.x;
  20462. var by1 = rect.y;
  20463. var bx2 = rect.right;
  20464. var by2 = rect.bottom;
  20465. var closestDistance = Infinity;
  20466. edges[0].setTo(bx1, by1, bx2, by1);
  20467. edges[1].setTo(bx1, by2, bx2, by2);
  20468. edges[2].setTo(bx1, by1, bx1, by2);
  20469. edges[3].setTo(bx2, by1, bx2, by2);
  20470. for (var edge, i = 0; (edge = edges[i]); i++)
  20471. {
  20472. if (line.intersects(edge, true, edgeIntersection))
  20473. {
  20474. var distance = line.start.distance(edgeIntersection);
  20475. if (distance < closestDistance)
  20476. {
  20477. closestDistance = distance;
  20478. result.copyFrom(edgeIntersection);
  20479. }
  20480. }
  20481. }
  20482. if (distance != null)
  20483. {
  20484. return result;
  20485. }
  20486. return null;
  20487. };
  20488. /**
  20489. * Returns the reflected angle between two lines.
  20490. * This is the outgoing angle based on the angle of Line 1 and the normalAngle of Line 2.
  20491. *
  20492. * @method Phaser.Line.reflect
  20493. * @param {Phaser.Line} a - The base line.
  20494. * @param {Phaser.Line} b - The line to be reflected from the base line.
  20495. * @return {number} The reflected angle in radians.
  20496. */
  20497. Phaser.Line.reflect = function (a, b) {
  20498. return 2 * b.normalAngle - 3.141592653589793 - a.angle;
  20499. };
  20500. /**
  20501. * @author Mat Groves http://matgroves.com/ @Doormat23
  20502. * @author Richard Davey <rich@photonstorm.com>
  20503. * @copyright 2016 Photon Storm Ltd.
  20504. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  20505. */
  20506. /**
  20507. * The Matrix is a 3x3 matrix mostly used for display transforms within the renderer.
  20508. *
  20509. * It is represented like so:
  20510. *
  20511. * | a | b | tx |
  20512. * | c | d | ty |
  20513. * | 0 | 0 | 1 |
  20514. *
  20515. * @class Phaser.Matrix
  20516. * @constructor
  20517. * @param {number} [a=1] - Horizontal scaling
  20518. * @param {number} [b=0] - Horizontal skewing
  20519. * @param {number} [c=0] - Vertical skewing
  20520. * @param {number} [d=1] - Vertical scaling
  20521. * @param {number} [tx=0] - Horizontal translation
  20522. * @param {number} [ty=0] - Vertical translation
  20523. */
  20524. Phaser.Matrix = function (a, b, c, d, tx, ty) {
  20525. if (a === undefined || a === null) { a = 1; }
  20526. if (b === undefined || b === null) { b = 0; }
  20527. if (c === undefined || c === null) { c = 0; }
  20528. if (d === undefined || d === null) { d = 1; }
  20529. if (tx === undefined || tx === null) { tx = 0; }
  20530. if (ty === undefined || ty === null) { ty = 0; }
  20531. /**
  20532. * @property {number} a
  20533. * @default 1
  20534. */
  20535. this.a = a;
  20536. /**
  20537. * @property {number} b
  20538. * @default 0
  20539. */
  20540. this.b = b;
  20541. /**
  20542. * @property {number} c
  20543. * @default 0
  20544. */
  20545. this.c = c;
  20546. /**
  20547. * @property {number} d
  20548. * @default 1
  20549. */
  20550. this.d = d;
  20551. /**
  20552. * @property {number} tx
  20553. * @default 0
  20554. */
  20555. this.tx = tx;
  20556. /**
  20557. * @property {number} ty
  20558. * @default 0
  20559. */
  20560. this.ty = ty;
  20561. /**
  20562. * @property {number} type - The const type of this object.
  20563. * @readonly
  20564. */
  20565. this.type = Phaser.MATRIX;
  20566. };
  20567. Phaser.Matrix.prototype = {
  20568. /**
  20569. * Sets the values of this Matrix to the values in the given array.
  20570. *
  20571. * The Array elements should be set as follows:
  20572. *
  20573. * a = array[0]
  20574. * b = array[1]
  20575. * c = array[3]
  20576. * d = array[4]
  20577. * tx = array[2]
  20578. * ty = array[5]
  20579. *
  20580. * @method Phaser.Matrix#fromArray
  20581. * @param {Array} array - The array to copy from.
  20582. * @return {Phaser.Matrix} This Matrix object.
  20583. */
  20584. fromArray: function (array) {
  20585. return this.setTo(array[0], array[1], array[3], array[4], array[2], array[5]);
  20586. },
  20587. /**
  20588. * Sets the values of this Matrix to the given values.
  20589. *
  20590. * @method Phaser.Matrix#setTo
  20591. * @param {number} a - Horizontal scaling
  20592. * @param {number} b - Horizontal skewing
  20593. * @param {number} c - Vertical skewing
  20594. * @param {number} d - Vertical scaling
  20595. * @param {number} tx - Horizontal translation
  20596. * @param {number} ty - Vertical translation
  20597. * @return {Phaser.Matrix} This Matrix object.
  20598. */
  20599. setTo: function (a, b, c, d, tx, ty) {
  20600. this.a = a;
  20601. this.b = b;
  20602. this.c = c;
  20603. this.d = d;
  20604. this.tx = tx;
  20605. this.ty = ty;
  20606. return this;
  20607. },
  20608. /**
  20609. * Creates a new Matrix object based on the values of this Matrix.
  20610. * If you provide the output parameter the values of this Matrix will be copied over to it.
  20611. * If the output parameter is blank a new Matrix object will be created.
  20612. *
  20613. * @method Phaser.Matrix#clone
  20614. * @param {Phaser.Matrix} [output] - If provided the values of this Matrix will be copied to it, otherwise a new Matrix object is created.
  20615. * @return {Phaser.Matrix} A clone of this Matrix.
  20616. */
  20617. clone: function (output) {
  20618. if (output === undefined || output === null)
  20619. {
  20620. output = new Phaser.Matrix(this.a, this.b, this.c, this.d, this.tx, this.ty);
  20621. }
  20622. else
  20623. {
  20624. output.a = this.a;
  20625. output.b = this.b;
  20626. output.c = this.c;
  20627. output.d = this.d;
  20628. output.tx = this.tx;
  20629. output.ty = this.ty;
  20630. }
  20631. return output;
  20632. },
  20633. /**
  20634. * Copies the properties from this Matrix to the given Matrix.
  20635. *
  20636. * @method Phaser.Matrix#copyTo
  20637. * @param {Phaser.Matrix} matrix - The Matrix to copy from.
  20638. * @return {Phaser.Matrix} The destination Matrix object.
  20639. */
  20640. copyTo: function (matrix) {
  20641. matrix.copyFrom(this);
  20642. return matrix;
  20643. },
  20644. /**
  20645. * Copies the properties from the given Matrix into this Matrix.
  20646. *
  20647. * @method Phaser.Matrix#copyFrom
  20648. * @param {Phaser.Matrix} matrix - The Matrix to copy from.
  20649. * @return {Phaser.Matrix} This Matrix object.
  20650. */
  20651. copyFrom: function (matrix) {
  20652. this.a = matrix.a;
  20653. this.b = matrix.b;
  20654. this.c = matrix.c;
  20655. this.d = matrix.d;
  20656. this.tx = matrix.tx;
  20657. this.ty = matrix.ty;
  20658. return this;
  20659. },
  20660. /**
  20661. * Creates a Float32 Array with values populated from this Matrix object.
  20662. *
  20663. * @method Phaser.Matrix#toArray
  20664. * @param {boolean} [transpose=false] - Whether the values in the array are transposed or not.
  20665. * @param {Float32Array} [array] - If provided the values will be set into this array, otherwise a new Float32Array is created.
  20666. * @return {Float32Array} The newly created array which contains the matrix.
  20667. */
  20668. toArray: function (transpose, array) {
  20669. if (array === undefined) { array = new Float32Array(9); }
  20670. if (transpose)
  20671. {
  20672. array[0] = this.a;
  20673. array[1] = this.b;
  20674. array[2] = 0;
  20675. array[3] = this.c;
  20676. array[4] = this.d;
  20677. array[5] = 0;
  20678. array[6] = this.tx;
  20679. array[7] = this.ty;
  20680. array[8] = 1;
  20681. }
  20682. else
  20683. {
  20684. array[0] = this.a;
  20685. array[1] = this.c;
  20686. array[2] = this.tx;
  20687. array[3] = this.b;
  20688. array[4] = this.d;
  20689. array[5] = this.ty;
  20690. array[6] = 0;
  20691. array[7] = 0;
  20692. array[8] = 1;
  20693. }
  20694. return array;
  20695. },
  20696. /**
  20697. * Get a new position with the current transformation applied.
  20698. *
  20699. * Can be used to go from a childs coordinate space to the world coordinate space (e.g. rendering)
  20700. *
  20701. * @method Phaser.Matrix#apply
  20702. * @param {Phaser.Point} pos - The origin Point.
  20703. * @param {Phaser.Point} [newPos] - The point that the new position is assigned to. This can be same as input point.
  20704. * @return {Phaser.Point} The new point, transformed through this matrix.
  20705. */
  20706. apply: function (pos, newPos) {
  20707. if (newPos === undefined) { newPos = new Phaser.Point(); }
  20708. newPos.x = this.a * pos.x + this.c * pos.y + this.tx;
  20709. newPos.y = this.b * pos.x + this.d * pos.y + this.ty;
  20710. return newPos;
  20711. },
  20712. /**
  20713. * Get a new position with the inverse of the current transformation applied.
  20714. *
  20715. * Can be used to go from the world coordinate space to a childs coordinate space. (e.g. input)
  20716. *
  20717. * @method Phaser.Matrix#applyInverse
  20718. * @param {Phaser.Point} pos - The origin Point.
  20719. * @param {Phaser.Point} [newPos] - The point that the new position is assigned to. This can be same as input point.
  20720. * @return {Phaser.Point} The new point, inverse transformed through this matrix.
  20721. */
  20722. applyInverse: function (pos, newPos) {
  20723. if (newPos === undefined) { newPos = new Phaser.Point(); }
  20724. var id = 1 / (this.a * this.d + this.c * -this.b);
  20725. var x = pos.x;
  20726. var y = pos.y;
  20727. newPos.x = this.d * id * x + -this.c * id * y + (this.ty * this.c - this.tx * this.d) * id;
  20728. newPos.y = this.a * id * y + -this.b * id * x + (-this.ty * this.a + this.tx * this.b) * id;
  20729. return newPos;
  20730. },
  20731. /**
  20732. * Translates the matrix on the x and y.
  20733. * This is the same as Matrix.tx += x.
  20734. *
  20735. * @method Phaser.Matrix#translate
  20736. * @param {number} x - The x value to translate on.
  20737. * @param {number} y - The y value to translate on.
  20738. * @return {Phaser.Matrix} This Matrix object.
  20739. */
  20740. translate: function (x, y) {
  20741. this.tx += x;
  20742. this.ty += y;
  20743. return this;
  20744. },
  20745. /**
  20746. * Applies a scale transformation to this matrix.
  20747. *
  20748. * @method Phaser.Matrix#scale
  20749. * @param {number} x - The amount to scale horizontally.
  20750. * @param {number} y - The amount to scale vertically.
  20751. * @return {Phaser.Matrix} This Matrix object.
  20752. */
  20753. scale: function (x, y) {
  20754. this.a *= x;
  20755. this.d *= y;
  20756. this.c *= x;
  20757. this.b *= y;
  20758. this.tx *= x;
  20759. this.ty *= y;
  20760. return this;
  20761. },
  20762. /**
  20763. * Applies a rotation transformation to this matrix.
  20764. *
  20765. * @method Phaser.Matrix#rotate
  20766. * @param {number} angle - The angle to rotate by, given in radians.
  20767. * @return {Phaser.Matrix} This Matrix object.
  20768. */
  20769. rotate: function (angle) {
  20770. var cos = Math.cos(angle);
  20771. var sin = Math.sin(angle);
  20772. var a1 = this.a;
  20773. var c1 = this.c;
  20774. var tx1 = this.tx;
  20775. this.a = a1 * cos-this.b * sin;
  20776. this.b = a1 * sin+this.b * cos;
  20777. this.c = c1 * cos-this.d * sin;
  20778. this.d = c1 * sin+this.d * cos;
  20779. this.tx = tx1 * cos - this.ty * sin;
  20780. this.ty = tx1 * sin + this.ty * cos;
  20781. return this;
  20782. },
  20783. /**
  20784. * Appends the given Matrix to this Matrix.
  20785. *
  20786. * @method Phaser.Matrix#append
  20787. * @param {Phaser.Matrix} matrix - The matrix to append to this one.
  20788. * @return {Phaser.Matrix} This Matrix object.
  20789. */
  20790. append: function (matrix) {
  20791. var a1 = this.a;
  20792. var b1 = this.b;
  20793. var c1 = this.c;
  20794. var d1 = this.d;
  20795. this.a = matrix.a * a1 + matrix.b * c1;
  20796. this.b = matrix.a * b1 + matrix.b * d1;
  20797. this.c = matrix.c * a1 + matrix.d * c1;
  20798. this.d = matrix.c * b1 + matrix.d * d1;
  20799. this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx;
  20800. this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty;
  20801. return this;
  20802. },
  20803. /**
  20804. * Resets this Matrix to an identity (default) matrix.
  20805. *
  20806. * @method Phaser.Matrix#identity
  20807. * @return {Phaser.Matrix} This Matrix object.
  20808. */
  20809. identity: function () {
  20810. return this.setTo(1, 0, 0, 1, 0, 0);
  20811. }
  20812. };
  20813. Phaser.identityMatrix = new Phaser.Matrix();
  20814. /**
  20815. * @author Richard Davey <rich@photonstorm.com>
  20816. * @copyright 2016 Photon Storm Ltd.
  20817. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  20818. */
  20819. /**
  20820. * A Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis.
  20821. * The following code creates a point at (0,0):
  20822. * `var myPoint = new Phaser.Point();`
  20823. * You can also use them as 2D Vectors and you'll find different vector related methods in this class.
  20824. *
  20825. * @class Phaser.Point
  20826. * @constructor
  20827. * @param {number} [x=0] - The horizontal position of this Point.
  20828. * @param {number} [y=0] - The vertical position of this Point.
  20829. */
  20830. Phaser.Point = function (x, y) {
  20831. x = x || 0;
  20832. y = y || 0;
  20833. /**
  20834. * @property {number} x - The x value of the point.
  20835. */
  20836. this.x = x;
  20837. /**
  20838. * @property {number} y - The y value of the point.
  20839. */
  20840. this.y = y;
  20841. /**
  20842. * @property {number} type - The const type of this object.
  20843. * @readonly
  20844. */
  20845. this.type = Phaser.POINT;
  20846. };
  20847. Phaser.Point.prototype = {
  20848. /**
  20849. * Copies the x and y properties from any given object to this Point.
  20850. *
  20851. * @method Phaser.Point#copyFrom
  20852. * @param {any} source - The object to copy from.
  20853. * @return {Phaser.Point} This Point object.
  20854. */
  20855. copyFrom: function (source) {
  20856. return this.setTo(source.x, source.y);
  20857. },
  20858. /**
  20859. * Inverts the x and y values of this Point
  20860. *
  20861. * @method Phaser.Point#invert
  20862. * @return {Phaser.Point} This Point object.
  20863. */
  20864. invert: function () {
  20865. return this.setTo(this.y, this.x);
  20866. },
  20867. /**
  20868. * Sets the `x` and `y` values of this Point object to the given values.
  20869. * If you omit the `y` value then the `x` value will be applied to both, for example:
  20870. * `Point.setTo(2)` is the same as `Point.setTo(2, 2)`
  20871. *
  20872. * Identical to {@link #set}.
  20873. *
  20874. * @method Phaser.Point#setTo
  20875. * @param {number} x - The horizontal value of this point.
  20876. * @param {number} [y] - The vertical value of this point. If not given the x value will be used in its place.
  20877. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  20878. */
  20879. setTo: function (x, y) {
  20880. return Phaser.Point.set(this, x, y);
  20881. },
  20882. /**
  20883. * Sets the `x` and `y` values of this Point object to the given values.
  20884. * If you omit the `y` value then the `x` value will be applied to both, for example:
  20885. * `Point.set(2)` is the same as `Point.set(2, 2)`
  20886. *
  20887. * Identical to {@link #setTo}.
  20888. *
  20889. * @method Phaser.Point#set
  20890. * @param {number} x - The horizontal value of this point.
  20891. * @param {number} [y] - The vertical value of this point. If not given the x value will be used in its place.
  20892. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  20893. */
  20894. set: function (x, y) {
  20895. return Phaser.Point.set(this, x, y);
  20896. },
  20897. /**
  20898. * Sets the `x` and `y` values of this Point object from a given polar coordinate.
  20899. *
  20900. * @method Phaser.Point#setToPolar
  20901. * @param {number} azimuth - The angular coordinate, in radians (unless `asDegrees`).
  20902. * @param {number} [radius=1] - The radial coordinate (length).
  20903. * @param {boolean} [asDegrees=false] - True if `azimuth` is in degrees.
  20904. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  20905. */
  20906. setToPolar: function(azimuth, radius, asDegrees) {
  20907. if (radius == null) { radius = 1; }
  20908. if (asDegrees) { azimuth = Phaser.Math.degToRad(azimuth); }
  20909. return this.setTo(Math.cos(azimuth) * radius, Math.sin(azimuth) * radius);
  20910. },
  20911. /**
  20912. * Adds the given x and y values to this Point.
  20913. *
  20914. * @method Phaser.Point#add
  20915. * @param {number} x - The value to add to Point.x.
  20916. * @param {number} y - The value to add to Point.y.
  20917. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  20918. */
  20919. add: function (x, y) {
  20920. this.x += x;
  20921. this.y += y;
  20922. return this;
  20923. },
  20924. /**
  20925. * Subtracts the given x and y values from this Point.
  20926. *
  20927. * @method Phaser.Point#subtract
  20928. * @param {number} x - The value to subtract from Point.x.
  20929. * @param {number} y - The value to subtract from Point.y.
  20930. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  20931. */
  20932. subtract: function (x, y) {
  20933. this.x -= x;
  20934. this.y -= y;
  20935. return this;
  20936. },
  20937. /**
  20938. * Multiplies Point.x and Point.y by the given x and y values. Sometimes known as `Scale`.
  20939. *
  20940. * @method Phaser.Point#multiply
  20941. * @param {number} x - The value to multiply Point.x by.
  20942. * @param {number} y - The value to multiply Point.x by.
  20943. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  20944. */
  20945. multiply: function (x, y) {
  20946. this.x *= x;
  20947. this.y *= y;
  20948. return this;
  20949. },
  20950. /**
  20951. * Divides Point.x and Point.y by the given x and y values.
  20952. *
  20953. * @method Phaser.Point#divide
  20954. * @param {number} x - The value to divide Point.x by.
  20955. * @param {number} y - The value to divide Point.x by.
  20956. * @return {Phaser.Point} This Point object. Useful for chaining method calls.
  20957. */
  20958. divide: function (x, y) {
  20959. this.x /= x;
  20960. this.y /= y;
  20961. return this;
  20962. },
  20963. /**
  20964. * Clamps the x value of this Point to be between the given min and max.
  20965. *
  20966. * @method Phaser.Point#clampX
  20967. * @param {number} min - The minimum value to clamp this Point to.
  20968. * @param {number} max - The maximum value to clamp this Point to.
  20969. * @return {Phaser.Point} This Point object.
  20970. */
  20971. clampX: function (min, max) {
  20972. this.x = Phaser.Math.clamp(this.x, min, max);
  20973. return this;
  20974. },
  20975. /**
  20976. * Clamps the y value of this Point to be between the given min and max
  20977. *
  20978. * @method Phaser.Point#clampY
  20979. * @param {number} min - The minimum value to clamp this Point to.
  20980. * @param {number} max - The maximum value to clamp this Point to.
  20981. * @return {Phaser.Point} This Point object.
  20982. */
  20983. clampY: function (min, max) {
  20984. this.y = Phaser.Math.clamp(this.y, min, max);
  20985. return this;
  20986. },
  20987. /**
  20988. * Clamps this Point object values to be between the given min and max.
  20989. *
  20990. * @method Phaser.Point#clamp
  20991. * @param {number} min - The minimum value to clamp this Point to.
  20992. * @param {number} max - The maximum value to clamp this Point to.
  20993. * @return {Phaser.Point} This Point object.
  20994. */
  20995. clamp: function (min, max) {
  20996. this.x = Phaser.Math.clamp(this.x, min, max);
  20997. this.y = Phaser.Math.clamp(this.y, min, max);
  20998. return this;
  20999. },
  21000. /**
  21001. * If this Point is not within the given object, moves it inside (at the nearest edge).
  21002. *
  21003. * @method Phaser.Point#clip
  21004. * @param {any} rect - A {@link Phaser.Rectangle} or any object with left, top, right, and bottom properties.
  21005. * @return {Phaser.Point} This Point object.
  21006. */
  21007. clip: function (rect) {
  21008. var left = rect.left, top = rect.top, right = rect.right, bottom = rect.bottom;
  21009. if (this.x < left ) { this.x = left; }
  21010. else if (this.x > right) { this.x = right; }
  21011. if (this.y < top) { this.y = top; }
  21012. else if (this.y > bottom) { this.y = bottom; }
  21013. return this;
  21014. },
  21015. /**
  21016. * Creates a copy of the given Point.
  21017. *
  21018. * @method Phaser.Point#clone
  21019. * @param {Phaser.Point} [output] Optional Point object. If given the values will be set into this object, otherwise a brand new Point object will be created and returned.
  21020. * @return {Phaser.Point} The new Point object.
  21021. */
  21022. clone: function (output) {
  21023. if (output === undefined || output === null)
  21024. {
  21025. output = new Phaser.Point(this.x, this.y);
  21026. }
  21027. else
  21028. {
  21029. output.setTo(this.x, this.y);
  21030. }
  21031. return output;
  21032. },
  21033. /**
  21034. * Copies the x and y properties from this Point to any given object.
  21035. *
  21036. * @method Phaser.Point#copyTo
  21037. * @param {any} dest - The object to copy to.
  21038. * @return {object} The dest object.
  21039. */
  21040. copyTo: function (dest) {
  21041. dest.x = this.x;
  21042. dest.y = this.y;
  21043. return dest;
  21044. },
  21045. /**
  21046. * Returns the distance of this Point object to the given object (can be a Circle, Point or anything with x/y properties)
  21047. *
  21048. * @method Phaser.Point#distance
  21049. * @param {object} dest - The target object. Must have visible x and y properties that represent the center of the object.
  21050. * @param {boolean} [round] - Round the distance to the nearest integer (default false).
  21051. * @return {number} The distance between this Point object and the destination Point object.
  21052. */
  21053. distance: function (dest, round) {
  21054. return Phaser.Point.distance(this, dest, round);
  21055. },
  21056. /**
  21057. * Determines whether the given objects x/y values are equal to this Point object.
  21058. *
  21059. * @method Phaser.Point#equals
  21060. * @param {Phaser.Point|any} a - The object to compare with this Point.
  21061. * @return {boolean} A value of true if the x and y points are equal, otherwise false.
  21062. */
  21063. equals: function (a) {
  21064. return a.x === this.x && a.y === this.y;
  21065. },
  21066. /**
  21067. * Determines whether a set of x-y coordinates are equal to this Point's.
  21068. *
  21069. * @method Phaser.Point#equalsXY
  21070. * @param {number} x - The x-coordinate to compare with this Point.
  21071. * @param {number} y - The y-coordinate to compare with this Point.
  21072. * @return {boolean} A value of true if the Point's coordinates are identical to the arguments, otherwise false.
  21073. */
  21074. equalsXY: function (x, y) {
  21075. return this.x === x && this.y === y;
  21076. },
  21077. fuzzyEquals: function (a, epsilon) {
  21078. return Phaser.Point.fuzzyEquals(this, a, epsilon);
  21079. },
  21080. fuzzyEqualsXY: function (x, y, epsilon) {
  21081. return Phaser.Point.fuzzyEqualsXY(this, x, y, epsilon);
  21082. },
  21083. /**
  21084. * Returns the angle between this Point object and another object with public x and y properties.
  21085. *
  21086. * @method Phaser.Point#angle
  21087. * @param {Phaser.Point|any} a - The object to get the angle from this Point to.
  21088. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)?
  21089. * @return {number} The angle between the two objects.
  21090. */
  21091. angle: function (a, asDegrees) {
  21092. if (asDegrees === undefined) { asDegrees = false; }
  21093. if (asDegrees)
  21094. {
  21095. return Phaser.Math.radToDeg(Math.atan2(a.y - this.y, a.x - this.x));
  21096. }
  21097. else
  21098. {
  21099. return Math.atan2(a.y - this.y, a.x - this.x);
  21100. }
  21101. },
  21102. /**
  21103. * Rotates this Point around the x/y coordinates given to the desired angle.
  21104. *
  21105. * @method Phaser.Point#rotate
  21106. * @param {number} x - The x coordinate of the anchor point.
  21107. * @param {number} y - The y coordinate of the anchor point.
  21108. * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the Point to.
  21109. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)?
  21110. * @param {number} [distance] - An optional distance constraint between the Point and the anchor.
  21111. * @return {Phaser.Point} The modified point object.
  21112. */
  21113. rotate: function (x, y, angle, asDegrees, distance) {
  21114. return Phaser.Point.rotate(this, x, y, angle, asDegrees, distance);
  21115. },
  21116. /**
  21117. * Calculates the length of the Point object.
  21118. *
  21119. * @method Phaser.Point#getMagnitude
  21120. * @return {number} The length of the Point.
  21121. */
  21122. getMagnitude: function () {
  21123. return Math.sqrt((this.x * this.x) + (this.y * this.y));
  21124. },
  21125. /**
  21126. * Calculates the length squared of the Point object.
  21127. *
  21128. * @method Phaser.Point#getMagnitudeSq
  21129. * @return {number} The length ^ 2 of the Point.
  21130. */
  21131. getMagnitudeSq: function () {
  21132. return (this.x * this.x) + (this.y * this.y);
  21133. },
  21134. /**
  21135. * Alters the length of the Point without changing the direction.
  21136. *
  21137. * @method Phaser.Point#setMagnitude
  21138. * @param {number} magnitude - The desired magnitude of the resulting Point.
  21139. * @return {Phaser.Point} This Point object.
  21140. */
  21141. setMagnitude: function (magnitude) {
  21142. return this.normalize().multiply(magnitude, magnitude);
  21143. },
  21144. /**
  21145. * Alters the Point object so that its length is 1, but it retains the same direction.
  21146. *
  21147. * @method Phaser.Point#normalize
  21148. * @return {Phaser.Point} This Point object.
  21149. */
  21150. normalize: function () {
  21151. if (!this.isZero())
  21152. {
  21153. var m = this.getMagnitude();
  21154. this.x /= m;
  21155. this.y /= m;
  21156. }
  21157. return this;
  21158. },
  21159. /**
  21160. * Alters the Point object so it's magnitude is at most the max value.
  21161. *
  21162. * @method Phaser.Point#limit
  21163. * @param {number} max - The maximum magnitude for the Point.
  21164. * @return {Phaser.Point} This Point object.
  21165. */
  21166. limit: function (max) {
  21167. if (this.getMagnitudeSq() > max * max)
  21168. {
  21169. this.setMagnitude(max);
  21170. }
  21171. return this;
  21172. },
  21173. /**
  21174. * Determine if this point is at 0,0.
  21175. *
  21176. * @method Phaser.Point#isZero
  21177. * @return {boolean} True if this Point is 0,0, otherwise false.
  21178. */
  21179. isZero: function () {
  21180. return (this.x === 0 && this.y === 0);
  21181. },
  21182. /**
  21183. * The dot product of this and another Point object.
  21184. *
  21185. * @method Phaser.Point#dot
  21186. * @param {Phaser.Point} a - The Point object to get the dot product combined with this Point.
  21187. * @return {number} The result.
  21188. */
  21189. dot: function (a) {
  21190. return ((this.x * a.x) + (this.y * a.y));
  21191. },
  21192. /**
  21193. * The cross product of this and another Point object.
  21194. *
  21195. * @method Phaser.Point#cross
  21196. * @param {Phaser.Point} a - The Point object to get the cross product combined with this Point.
  21197. * @return {number} The result.
  21198. */
  21199. cross: function (a) {
  21200. return ((this.x * a.y) - (this.y * a.x));
  21201. },
  21202. /**
  21203. * Make this Point perpendicular (90 degrees rotation)
  21204. *
  21205. * @method Phaser.Point#perp
  21206. * @return {Phaser.Point} This Point object.
  21207. */
  21208. perp: function () {
  21209. return this.setTo(-this.y, this.x);
  21210. },
  21211. /**
  21212. * Make this Point perpendicular (-90 degrees rotation)
  21213. *
  21214. * @method Phaser.Point#rperp
  21215. * @return {Phaser.Point} This Point object.
  21216. */
  21217. rperp: function () {
  21218. return this.setTo(this.y, -this.x);
  21219. },
  21220. /**
  21221. * Right-hand normalize (make unit length) this Point.
  21222. *
  21223. * @method Phaser.Point#normalRightHand
  21224. * @return {Phaser.Point} This Point object.
  21225. */
  21226. normalRightHand: function () {
  21227. return this.setTo(this.y * -1, this.x);
  21228. },
  21229. /**
  21230. * Math.floor() both the x and y properties of this Point.
  21231. *
  21232. * @method Phaser.Point#floor
  21233. * @return {Phaser.Point} This Point object.
  21234. */
  21235. floor: function () {
  21236. return this.setTo(Math.floor(this.x), Math.floor(this.y));
  21237. },
  21238. /**
  21239. * Math.ceil() both the x and y properties of this Point.
  21240. *
  21241. * @method Phaser.Point#ceil
  21242. * @return {Phaser.Point} This Point object.
  21243. */
  21244. ceil: function () {
  21245. return this.setTo(Math.ceil(this.x), Math.ceil(this.y));
  21246. },
  21247. /**
  21248. * Returns a string representation of this object.
  21249. *
  21250. * @method Phaser.Point#toString
  21251. * @return {string} A string representation of the instance.
  21252. */
  21253. toString: function () {
  21254. return '[{Point (x=' + this.x + ' y=' + this.y + ')}]';
  21255. }
  21256. };
  21257. Phaser.Point.prototype.constructor = Phaser.Point;
  21258. /**
  21259. * Adds the coordinates of two points together to create a new point.
  21260. *
  21261. * @method Phaser.Point.add
  21262. * @param {Phaser.Point} a - The first Point object.
  21263. * @param {Phaser.Point} b - The second Point object.
  21264. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21265. * @return {Phaser.Point} The new Point object.
  21266. */
  21267. Phaser.Point.add = function (a, b, out) {
  21268. if (out === undefined) { out = new Phaser.Point(); }
  21269. out.x = a.x + b.x;
  21270. out.y = a.y + b.y;
  21271. return out;
  21272. };
  21273. /**
  21274. * Subtracts the coordinates of two points to create a new point.
  21275. *
  21276. * @method Phaser.Point.subtract
  21277. * @param {Phaser.Point} a - The first Point object.
  21278. * @param {Phaser.Point} b - The second Point object.
  21279. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21280. * @return {Phaser.Point} The new Point object.
  21281. */
  21282. Phaser.Point.subtract = function (a, b, out) {
  21283. if (out === undefined) { out = new Phaser.Point(); }
  21284. out.x = a.x - b.x;
  21285. out.y = a.y - b.y;
  21286. return out;
  21287. };
  21288. /**
  21289. * Multiplies the coordinates of two points to create a new point.
  21290. *
  21291. * @method Phaser.Point.multiply
  21292. * @param {Phaser.Point} a - The first Point object.
  21293. * @param {Phaser.Point} b - The second Point object.
  21294. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21295. * @return {Phaser.Point} The new Point object.
  21296. */
  21297. Phaser.Point.multiply = function (a, b, out) {
  21298. if (out === undefined) { out = new Phaser.Point(); }
  21299. out.x = a.x * b.x;
  21300. out.y = a.y * b.y;
  21301. return out;
  21302. };
  21303. /**
  21304. * Divides the coordinates of two points to create a new point.
  21305. *
  21306. * @method Phaser.Point.divide
  21307. * @param {Phaser.Point} a - The first Point object.
  21308. * @param {Phaser.Point} b - The second Point object.
  21309. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21310. * @return {Phaser.Point} The new Point object.
  21311. */
  21312. Phaser.Point.divide = function (a, b, out) {
  21313. if (out === undefined) { out = new Phaser.Point(); }
  21314. out.x = a.x / b.x;
  21315. out.y = a.y / b.y;
  21316. return out;
  21317. };
  21318. /**
  21319. * Determines whether the two given Point objects are equal. They are considered equal if they have the same x and y values.
  21320. *
  21321. * @method Phaser.Point.equals
  21322. * @param {Phaser.Point} a - The first Point object.
  21323. * @param {Phaser.Point} b - The second Point object.
  21324. * @return {boolean} A value of true if the Points are equal, otherwise false.
  21325. */
  21326. Phaser.Point.equals = function (a, b) {
  21327. return a.x === b.x && a.y === b.y;
  21328. };
  21329. Phaser.Point.equalsXY = function (a, x, y) {
  21330. return a.x === x && a.y === y;
  21331. };
  21332. Phaser.Point.fuzzyEquals = function (a, b, epsilon) {
  21333. return Phaser.Math.fuzzyEquals(a.x, b.x, epsilon) &&
  21334. Phaser.Math.fuzzyEquals(a.y, b.y, epsilon);
  21335. };
  21336. Phaser.Point.fuzzyEqualsXY = function (a, x, y, epsilon) {
  21337. return Phaser.Math.fuzzyEquals(a.x, x, epsilon) &&
  21338. Phaser.Math.fuzzyEquals(a.y, y, epsilon);
  21339. };
  21340. /**
  21341. * Returns the angle between two Point objects.
  21342. *
  21343. * @method Phaser.Point.angle
  21344. * @param {Phaser.Point} a - The first Point object.
  21345. * @param {Phaser.Point} b - The second Point object.
  21346. * @return {number} The angle between the two Points.
  21347. */
  21348. Phaser.Point.angle = function (a, b) {
  21349. // return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);
  21350. return Math.atan2(a.y - b.y, a.x - b.x);
  21351. };
  21352. /**
  21353. * Creates a negative Point.
  21354. *
  21355. * @method Phaser.Point.negative
  21356. * @param {Phaser.Point} a - The first Point object.
  21357. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21358. * @return {Phaser.Point} The new Point object.
  21359. */
  21360. Phaser.Point.negative = function (a, out) {
  21361. if (out === undefined) { out = new Phaser.Point(); }
  21362. return out.setTo(-a.x, -a.y);
  21363. };
  21364. /**
  21365. * Adds two 2D Points together and multiplies the result by the given scalar.
  21366. *
  21367. * @method Phaser.Point.multiplyAdd
  21368. * @param {Phaser.Point} a - The first Point object.
  21369. * @param {Phaser.Point} b - The second Point object.
  21370. * @param {number} s - The scaling value.
  21371. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21372. * @return {Phaser.Point} The new Point object.
  21373. */
  21374. Phaser.Point.multiplyAdd = function (a, b, s, out) {
  21375. if (out === undefined) { out = new Phaser.Point(); }
  21376. return out.setTo(a.x + b.x * s, a.y + b.y * s);
  21377. };
  21378. /**
  21379. * Interpolates the two given Points, based on the `f` value (between 0 and 1) and returns a new Point.
  21380. *
  21381. * @method Phaser.Point.interpolate
  21382. * @param {Phaser.Point} a - The first Point object.
  21383. * @param {Phaser.Point} b - The second Point object.
  21384. * @param {number} f - The level of interpolation between the two points. Indicates where the new point will be, along the line between pt1 and pt2. If f=1, pt1 is returned; if f=0, pt2 is returned.
  21385. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21386. * @return {Phaser.Point} The new Point object.
  21387. */
  21388. Phaser.Point.interpolate = function (a, b, f, out) {
  21389. if (out === undefined) { out = new Phaser.Point(); }
  21390. return out.setTo(a.x + (b.x - a.x) * f, a.y + (b.y - a.y) * f);
  21391. };
  21392. /**
  21393. * Return a perpendicular vector (90 degrees rotation)
  21394. *
  21395. * @method Phaser.Point.perp
  21396. * @param {Phaser.Point} a - The Point object.
  21397. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21398. * @return {Phaser.Point} The new Point object.
  21399. */
  21400. Phaser.Point.perp = function (a, out) {
  21401. if (out === undefined) { out = new Phaser.Point(); }
  21402. return out.setTo(-a.y, a.x);
  21403. };
  21404. /**
  21405. * Return a perpendicular vector (-90 degrees rotation)
  21406. *
  21407. * @method Phaser.Point.rperp
  21408. * @param {Phaser.Point} a - The Point object.
  21409. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21410. * @return {Phaser.Point} The new Point object.
  21411. */
  21412. Phaser.Point.rperp = function (a, out) {
  21413. if (out === undefined) { out = new Phaser.Point(); }
  21414. return out.setTo(a.y, -a.x);
  21415. };
  21416. /**
  21417. * Returns the euclidian distance of this Point object to the given object (can be a Circle, Point or anything with x/y properties).
  21418. *
  21419. * @method Phaser.Point.distance
  21420. * @param {object} a - The target object. Must have visible x and y properties that represent the center of the object.
  21421. * @param {object} b - The target object. Must have visible x and y properties that represent the center of the object.
  21422. * @param {boolean} [round=false] - Round the distance to the nearest integer.
  21423. * @return {number} The distance between this Point object and the destination Point object.
  21424. */
  21425. Phaser.Point.distance = function (a, b, round) {
  21426. var distance = Phaser.Math.distance(a.x, a.y, b.x, b.y);
  21427. return round ? Math.round(distance) : distance;
  21428. };
  21429. /**
  21430. * Project two Points onto another Point.
  21431. *
  21432. * @method Phaser.Point.project
  21433. * @param {Phaser.Point} a - The first Point object.
  21434. * @param {Phaser.Point} b - The second Point object.
  21435. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21436. * @return {Phaser.Point} The new Point object.
  21437. */
  21438. Phaser.Point.project = function (a, b, out) {
  21439. if (out === undefined) { out = new Phaser.Point(); }
  21440. var amt = a.dot(b) / b.getMagnitudeSq();
  21441. if (amt !== 0)
  21442. {
  21443. out.setTo(amt * b.x, amt * b.y);
  21444. }
  21445. return out;
  21446. };
  21447. /**
  21448. * Project two Points onto a Point of unit length.
  21449. *
  21450. * @method Phaser.Point.projectUnit
  21451. * @param {Phaser.Point} a - The first Point object.
  21452. * @param {Phaser.Point} b - The second Point object.
  21453. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21454. * @return {Phaser.Point} The new Point object.
  21455. */
  21456. Phaser.Point.projectUnit = function (a, b, out) {
  21457. if (out === undefined) { out = new Phaser.Point(); }
  21458. var amt = a.dot(b);
  21459. if (amt !== 0)
  21460. {
  21461. out.setTo(amt * b.x, amt * b.y);
  21462. }
  21463. return out;
  21464. };
  21465. /**
  21466. * Right-hand normalize (make unit length) a Point.
  21467. *
  21468. * @method Phaser.Point.normalRightHand
  21469. * @param {Phaser.Point} a - The Point object.
  21470. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21471. * @return {Phaser.Point} The new Point object.
  21472. */
  21473. Phaser.Point.normalRightHand = function (a, out) {
  21474. if (out === undefined) { out = new Phaser.Point(); }
  21475. return out.setTo(a.y * -1, a.x);
  21476. };
  21477. /**
  21478. * Normalize (make unit length) a Point.
  21479. *
  21480. * @method Phaser.Point.normalize
  21481. * @param {Phaser.Point} a - The Point object.
  21482. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21483. * @return {Phaser.Point} The new Point object.
  21484. */
  21485. Phaser.Point.normalize = function (a, out) {
  21486. if (out === undefined) { out = new Phaser.Point(); }
  21487. var m = a.getMagnitude();
  21488. if (m !== 0)
  21489. {
  21490. out.setTo(a.x / m, a.y / m);
  21491. }
  21492. return out;
  21493. };
  21494. /**
  21495. * Rotates a Point object, or any object with exposed x/y properties, around the given coordinates by
  21496. * the angle specified. If the angle between the point and coordinates was 45 deg and the angle argument
  21497. * is 45 deg then the resulting angle will be 90 deg, as the angle argument is added to the current angle.
  21498. *
  21499. * The distance allows you to specify a distance constraint for the rotation between the point and the
  21500. * coordinates. If none is given the distance between the two is calculated and used.
  21501. *
  21502. * @method Phaser.Point.rotate
  21503. * @param {Phaser.Point} a - The Point object to rotate.
  21504. * @param {number} x - The x coordinate of the anchor point
  21505. * @param {number} y - The y coordinate of the anchor point
  21506. * @param {number} angle - The angle in radians (unless asDegrees is true) to rotate the Point by.
  21507. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)?
  21508. * @param {number} [distance] - An optional distance constraint between the Point and the anchor.
  21509. * @return {Phaser.Point} The modified point object.
  21510. */
  21511. Phaser.Point.rotate = function (a, x, y, angle, asDegrees, distance) {
  21512. if (asDegrees) { angle = Phaser.Math.degToRad(angle); }
  21513. if (distance === undefined)
  21514. {
  21515. a.subtract(x, y);
  21516. var s = Math.sin(angle);
  21517. var c = Math.cos(angle);
  21518. var tx = c * a.x - s * a.y;
  21519. var ty = s * a.x + c * a.y;
  21520. a.x = tx + x;
  21521. a.y = ty + y;
  21522. }
  21523. else
  21524. {
  21525. var t = angle + Math.atan2(a.y - y, a.x - x);
  21526. a.x = x + distance * Math.cos(t);
  21527. a.y = y + distance * Math.sin(t);
  21528. }
  21529. return a;
  21530. };
  21531. /**
  21532. * Calculates centroid (or midpoint) from an array of points. If only one point is provided, that point is returned.
  21533. *
  21534. * @method Phaser.Point.centroid
  21535. * @param {Phaser.Point[]} points - The array of one or more points.
  21536. * @param {Phaser.Point} [out] - Optional Point to store the value in, if not supplied a new Point object will be created.
  21537. * @return {Phaser.Point} The new Point object.
  21538. */
  21539. Phaser.Point.centroid = function (points, out) {
  21540. if (out === undefined) { out = new Phaser.Point(); }
  21541. if (Object.prototype.toString.call(points) !== '[object Array]')
  21542. {
  21543. throw new Error("Phaser.Point. Parameter 'points' must be an array");
  21544. }
  21545. var pointslength = points.length;
  21546. if (pointslength < 1)
  21547. {
  21548. throw new Error("Phaser.Point. Parameter 'points' array must not be empty");
  21549. }
  21550. if (pointslength === 1)
  21551. {
  21552. out.copyFrom(points[0]);
  21553. return out;
  21554. }
  21555. for (var i = 0; i < pointslength; i++)
  21556. {
  21557. Phaser.Point.add(out, points[i], out);
  21558. }
  21559. out.divide(pointslength, pointslength);
  21560. return out;
  21561. };
  21562. /**
  21563. * Parses an object for x and/or y properties and returns a new Phaser.Point with matching values.
  21564. * If the object doesn't contain those properties a Point with x/y of zero will be returned.
  21565. *
  21566. * @method Phaser.Point.parse
  21567. * @static
  21568. * @param {object} obj - The object to parse.
  21569. * @param {string} [xProp='x'] - The property used to set the Point.x value.
  21570. * @param {string} [yProp='y'] - The property used to set the Point.y value.
  21571. * @return {Phaser.Point} The new Point object.
  21572. */
  21573. Phaser.Point.parse = function(obj, xProp, yProp) {
  21574. xProp = xProp || 'x';
  21575. yProp = yProp || 'y';
  21576. var point = new Phaser.Point();
  21577. if (obj[xProp])
  21578. {
  21579. point.x = parseInt(obj[xProp], 10);
  21580. }
  21581. if (obj[yProp])
  21582. {
  21583. point.y = parseInt(obj[yProp], 10);
  21584. }
  21585. return point;
  21586. };
  21587. /**
  21588. * Tests a Point or Point-like object.
  21589. *
  21590. * @method Phaser.Point.isPoint
  21591. * @static
  21592. * @return {boolean} - True if the object has numeric x and y properties.
  21593. */
  21594. Phaser.Point.isPoint = function(obj) {
  21595. return (obj != null) && (typeof obj.x === 'number') && (typeof obj.y === 'number');
  21596. };
  21597. /**
  21598. * Sets the `x` and `y` values of an object and returns the object.
  21599. *
  21600. * @method Phaser.Point#set
  21601. * @static
  21602. * @param {object} obj - An object with numeric x and y properties.
  21603. * @param {number} x - The x value.
  21604. * @param {number} [y] - The y value. If not given the x value will be used in its place.
  21605. * @return {object} The object. Useful for chaining method calls.
  21606. */
  21607. Phaser.Point.set = function(obj, x, y) {
  21608. obj.x = x || 0;
  21609. obj.y = y || ( (y !== 0) ? obj.x : 0 );
  21610. return obj;
  21611. };
  21612. // Because PIXI uses its own Point, we'll replace it with ours to avoid duplicating code or confusion.
  21613. PIXI.Point = Phaser.Point;
  21614. /**
  21615. * @author Richard Davey <rich@photonstorm.com>
  21616. * @author Adrien Brault <adrien.brault@gmail.com>
  21617. * @copyright 2016 Photon Storm Ltd.
  21618. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  21619. */
  21620. /**
  21621. * Creates a new Polygon.
  21622. *
  21623. * The points can be set from a variety of formats:
  21624. *
  21625. * - An array of Point objects: `[new Phaser.Point(x1, y1), ...]`
  21626. * - An array of objects with public x/y properties: `[obj1, obj2, ...]`
  21627. * - An array of paired numbers that represent point coordinates: `[x1,y1, x2,y2, ...]`
  21628. * - As separate Point arguments: `setTo(new Phaser.Point(x1, y1), ...)`
  21629. * - As separate objects with public x/y properties arguments: `setTo(obj1, obj2, ...)`
  21630. * - As separate arguments representing point coordinates: `setTo(x1,y1, x2,y2, ...)`
  21631. *
  21632. * @class Phaser.Polygon
  21633. * @constructor
  21634. * @param {Phaser.Point[]|number[]|...Phaser.Point|...number} points - The points to set.
  21635. */
  21636. Phaser.Polygon = function () {
  21637. /**
  21638. * @property {number} area - The area of this Polygon.
  21639. */
  21640. this.area = 0;
  21641. /**
  21642. * @property {array} _points - An array of Points that make up this Polygon.
  21643. * @private
  21644. */
  21645. this._points = [];
  21646. if (arguments.length > 0)
  21647. {
  21648. this.setTo.apply(this, arguments);
  21649. }
  21650. /**
  21651. * @property {boolean} closed - Is the Polygon closed or not?
  21652. */
  21653. this.closed = true;
  21654. /**
  21655. * @property {boolean} flattened - Has this Polygon been flattened by a call to `Polygon.flatten` ?
  21656. */
  21657. this.flattened = false;
  21658. /**
  21659. * @property {number} type - The base object type.
  21660. */
  21661. this.type = Phaser.POLYGON;
  21662. };
  21663. Phaser.Polygon.prototype = {
  21664. /**
  21665. * Export the points as an array of flat numbers, following the sequence [ x,y, x,y, x,y ]
  21666. *
  21667. * @method Phaser.Polygon#toNumberArray
  21668. * @param {array} [output] - The array to append the points to. If not specified a new array will be created.
  21669. * @return {array} The flattened array.
  21670. */
  21671. toNumberArray: function (output) {
  21672. if (output === undefined) { output = []; }
  21673. for (var i = 0; i < this._points.length; i++)
  21674. {
  21675. if (typeof this._points[i] === 'number')
  21676. {
  21677. output.push(this._points[i]);
  21678. output.push(this._points[i + 1]);
  21679. i++;
  21680. }
  21681. else
  21682. {
  21683. output.push(this._points[i].x);
  21684. output.push(this._points[i].y);
  21685. }
  21686. }
  21687. return output;
  21688. },
  21689. /**
  21690. * Flattens this Polygon so the points are a sequence of numbers.
  21691. * Any Point objects found are removed and replaced with two numbers.
  21692. * Also sets the Polygon.flattened property to `true`.
  21693. *
  21694. * @method Phaser.Polygon#flatten
  21695. * @return {Phaser.Polygon} This Polygon object
  21696. */
  21697. flatten: function () {
  21698. this._points = this.toNumberArray();
  21699. this.flattened = true;
  21700. return this;
  21701. },
  21702. /**
  21703. * Creates a copy of the given Polygon.
  21704. * This is a deep clone, the resulting copy contains new Phaser.Point objects
  21705. *
  21706. * @method Phaser.Polygon#clone
  21707. * @param {Phaser.Polygon} [output=(new Polygon)] - The polygon to update. If not specified a new polygon will be created.
  21708. * @return {Phaser.Polygon} The cloned (`output`) polygon object.
  21709. */
  21710. clone: function (output) {
  21711. var points = this._points.slice();
  21712. if (output === undefined || output === null)
  21713. {
  21714. output = new Phaser.Polygon(points);
  21715. }
  21716. else
  21717. {
  21718. output.setTo(points);
  21719. }
  21720. return output;
  21721. },
  21722. /**
  21723. * Checks whether the x and y coordinates are contained within this polygon.
  21724. *
  21725. * @method Phaser.Polygon#contains
  21726. * @param {number} x - The X value of the coordinate to test.
  21727. * @param {number} y - The Y value of the coordinate to test.
  21728. * @return {boolean} True if the coordinates are within this polygon, otherwise false.
  21729. */
  21730. contains: function (x, y) {
  21731. // Adapted from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html by Jonas Raoni Soares Silva
  21732. var inside = false;
  21733. if (this.flattened)
  21734. {
  21735. for (var i = -2, j = this._points.length - 2; (i += 2) < this._points.length; j = i)
  21736. {
  21737. var ix = this._points[i];
  21738. var iy = this._points[i + 1];
  21739. var jx = this._points[j];
  21740. var jy = this._points[j + 1];
  21741. if (((iy <= y && y < jy) || (jy <= y && y < iy)) && (x < (jx - ix) * (y - iy) / (jy - iy) + ix))
  21742. {
  21743. inside = !inside;
  21744. }
  21745. }
  21746. }
  21747. else
  21748. {
  21749. for (var i = -1, j = this._points.length - 1; ++i < this._points.length; j = i)
  21750. {
  21751. var ix = this._points[i].x;
  21752. var iy = this._points[i].y;
  21753. var jx = this._points[j].x;
  21754. var jy = this._points[j].y;
  21755. if (((iy <= y && y < jy) || (jy <= y && y < iy)) && (x < (jx - ix) * (y - iy) / (jy - iy) + ix))
  21756. {
  21757. inside = !inside;
  21758. }
  21759. }
  21760. }
  21761. return inside;
  21762. },
  21763. /**
  21764. * Sets this Polygon to the given points.
  21765. *
  21766. * The points can be set from a variety of formats:
  21767. *
  21768. * - An array of Point objects: `[new Phaser.Point(x1, y1), ...]`
  21769. * - An array of objects with public x/y properties: `[obj1, obj2, ...]`
  21770. * - An array of paired numbers that represent point coordinates: `[x1,y1, x2,y2, ...]`
  21771. * - An array of arrays with two elements representing x/y coordinates: `[[x1, y1], [x2, y2], ...]`
  21772. * - As separate Point arguments: `setTo(new Phaser.Point(x1, y1), ...)`
  21773. * - As separate objects with public x/y properties arguments: `setTo(obj1, obj2, ...)`
  21774. * - As separate arguments representing point coordinates: `setTo(x1,y1, x2,y2, ...)`
  21775. *
  21776. * `setTo` may also be called without any arguments to remove all points.
  21777. *
  21778. * @method Phaser.Polygon#setTo
  21779. * @param {Phaser.Point[]|number[]|...Phaser.Point|...number} points - The points to set.
  21780. * @return {Phaser.Polygon} This Polygon object
  21781. */
  21782. setTo: function (points) {
  21783. this.area = 0;
  21784. this._points = [];
  21785. if (arguments.length > 0)
  21786. {
  21787. // If points isn't an array, use arguments as the array
  21788. if (!Array.isArray(points))
  21789. {
  21790. points = Array.prototype.slice.call(arguments);
  21791. }
  21792. var y0 = Number.MAX_VALUE;
  21793. // Allows for mixed-type arguments
  21794. for (var i = 0, len = points.length; i < len; i++)
  21795. {
  21796. if (typeof points[i] === 'number')
  21797. {
  21798. var p = new PIXI.Point(points[i], points[i + 1]);
  21799. i++;
  21800. }
  21801. else if (Array.isArray(points[i]))
  21802. {
  21803. var p = new PIXI.Point(points[i][0], points[i][1]);
  21804. }
  21805. else
  21806. {
  21807. var p = new PIXI.Point(points[i].x, points[i].y);
  21808. }
  21809. this._points.push(p);
  21810. // Lowest boundary
  21811. if (p.y < y0)
  21812. {
  21813. y0 = p.y;
  21814. }
  21815. }
  21816. this.calculateArea(y0);
  21817. }
  21818. return this;
  21819. },
  21820. /**
  21821. * Calcuates the area of the Polygon. This is available in the property Polygon.area
  21822. *
  21823. * @method Phaser.Polygon#calculateArea
  21824. * @private
  21825. * @param {number} y0 - The lowest boundary
  21826. * @return {number} The area of the Polygon.
  21827. */
  21828. calculateArea: function (y0) {
  21829. var p1;
  21830. var p2;
  21831. var avgHeight;
  21832. var width;
  21833. for (var i = 0, len = this._points.length; i < len; i++)
  21834. {
  21835. p1 = this._points[i];
  21836. if (i === len - 1)
  21837. {
  21838. p2 = this._points[0];
  21839. }
  21840. else
  21841. {
  21842. p2 = this._points[i + 1];
  21843. }
  21844. avgHeight = ((p1.y - y0) + (p2.y - y0)) / 2;
  21845. width = p1.x - p2.x;
  21846. this.area += avgHeight * width;
  21847. }
  21848. return this.area;
  21849. }
  21850. };
  21851. Phaser.Polygon.prototype.constructor = Phaser.Polygon;
  21852. /**
  21853. * Sets and modifies the points of this polygon.
  21854. *
  21855. * See {@link Phaser.Polygon#setTo setTo} for the different kinds of arrays formats that can be assigned.
  21856. *
  21857. * @name Phaser.Polygon#points
  21858. * @property {Phaser.Point[]} points - The array of vertex points.
  21859. * @deprecated Use `setTo`.
  21860. */
  21861. Object.defineProperty(Phaser.Polygon.prototype, 'points', {
  21862. get: function() {
  21863. return this._points;
  21864. },
  21865. set: function(points) {
  21866. if (points != null)
  21867. {
  21868. this.setTo(points);
  21869. }
  21870. else
  21871. {
  21872. // Clear the points
  21873. this.setTo();
  21874. }
  21875. }
  21876. });
  21877. // Because PIXI uses its own type, we'll replace it with ours to avoid duplicating code or confusion.
  21878. PIXI.Polygon = Phaser.Polygon;
  21879. /**
  21880. * @author Richard Davey <rich@photonstorm.com>
  21881. * @copyright 2016 Photon Storm Ltd.
  21882. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  21883. */
  21884. /**
  21885. * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters.
  21886. * If you call this function without parameters, a Rectangle with x, y, width, and height properties set to 0 is created.
  21887. *
  21888. * @class Phaser.Rectangle
  21889. * @constructor
  21890. * @param {number} x - The x coordinate of the top-left corner of the Rectangle.
  21891. * @param {number} y - The y coordinate of the top-left corner of the Rectangle.
  21892. * @param {number} width - The width of the Rectangle. Should always be either zero or a positive value.
  21893. * @param {number} height - The height of the Rectangle. Should always be either zero or a positive value.
  21894. */
  21895. Phaser.Rectangle = function (x, y, width, height) {
  21896. x = x || 0;
  21897. y = y || 0;
  21898. width = width || 0;
  21899. height = height || 0;
  21900. /**
  21901. * @property {number} x - The x coordinate of the top-left corner of the Rectangle.
  21902. */
  21903. this.x = x;
  21904. /**
  21905. * @property {number} y - The y coordinate of the top-left corner of the Rectangle.
  21906. */
  21907. this.y = y;
  21908. /**
  21909. * @property {number} width - The width of the Rectangle. This value should never be set to a negative.
  21910. */
  21911. this.width = width;
  21912. /**
  21913. * @property {number} height - The height of the Rectangle. This value should never be set to a negative.
  21914. */
  21915. this.height = height;
  21916. /**
  21917. * @property {number} type - The const type of this object.
  21918. * @readonly
  21919. */
  21920. this.type = Phaser.RECTANGLE;
  21921. };
  21922. Phaser.Rectangle.prototype = {
  21923. /**
  21924. * Adjusts the location of the Rectangle object, as determined by its top-left corner, by the specified amounts.
  21925. * @method Phaser.Rectangle#offset
  21926. * @param {number} dx - Moves the x value of the Rectangle object by this amount.
  21927. * @param {number} dy - Moves the y value of the Rectangle object by this amount.
  21928. * @return {Phaser.Rectangle} This Rectangle object.
  21929. */
  21930. offset: function (dx, dy) {
  21931. this.x += dx;
  21932. this.y += dy;
  21933. return this;
  21934. },
  21935. /**
  21936. * Adjusts the location of the Rectangle object using a Point object as a parameter. This method is similar to the Rectangle.offset() method, except that it takes a Point object as a parameter.
  21937. * @method Phaser.Rectangle#offsetPoint
  21938. * @param {Phaser.Point} point - A Point object to use to offset this Rectangle object.
  21939. * @return {Phaser.Rectangle} This Rectangle object.
  21940. */
  21941. offsetPoint: function (point) {
  21942. return this.offset(point.x, point.y);
  21943. },
  21944. /**
  21945. * Sets the members of Rectangle to the specified values.
  21946. * @method Phaser.Rectangle#setTo
  21947. * @param {number} x - The x coordinate of the top-left corner of the Rectangle.
  21948. * @param {number} y - The y coordinate of the top-left corner of the Rectangle.
  21949. * @param {number} width - The width of the Rectangle. Should always be either zero or a positive value.
  21950. * @param {number} height - The height of the Rectangle. Should always be either zero or a positive value.
  21951. * @return {Phaser.Rectangle} This Rectangle object
  21952. */
  21953. setTo: function (x, y, width, height) {
  21954. this.x = x;
  21955. this.y = y;
  21956. this.width = width;
  21957. this.height = height;
  21958. return this;
  21959. },
  21960. /**
  21961. * Scales the width and height of this Rectangle by the given amounts.
  21962. *
  21963. * @method Phaser.Rectangle#scale
  21964. * @param {number} x - The amount to scale the width of the Rectangle by. A value of 0.5 would reduce by half, a value of 2 would double the width, etc.
  21965. * @param {number} [y] - The amount to scale the height of the Rectangle by. A value of 0.5 would reduce by half, a value of 2 would double the height, etc.
  21966. * @return {Phaser.Rectangle} This Rectangle object
  21967. */
  21968. scale: function (x, y) {
  21969. if (y === undefined) { y = x; }
  21970. this.width *= x;
  21971. this.height *= y;
  21972. return this;
  21973. },
  21974. /**
  21975. * Centers this Rectangle so that the center coordinates match the given x and y values.
  21976. *
  21977. * @method Phaser.Rectangle#centerOn
  21978. * @param {number} x - The x coordinate to place the center of the Rectangle at.
  21979. * @param {number} y - The y coordinate to place the center of the Rectangle at.
  21980. * @return {Phaser.Rectangle} This Rectangle object
  21981. */
  21982. centerOn: function (x, y) {
  21983. this.centerX = x;
  21984. this.centerY = y;
  21985. return this;
  21986. },
  21987. /**
  21988. * Runs Math.floor() on both the x and y values of this Rectangle.
  21989. * @method Phaser.Rectangle#floor
  21990. */
  21991. floor: function () {
  21992. this.x = Math.floor(this.x);
  21993. this.y = Math.floor(this.y);
  21994. },
  21995. /**
  21996. * Runs Math.floor() on the x, y, width and height values of this Rectangle.
  21997. * @method Phaser.Rectangle#floorAll
  21998. */
  21999. floorAll: function () {
  22000. this.x = Math.floor(this.x);
  22001. this.y = Math.floor(this.y);
  22002. this.width = Math.floor(this.width);
  22003. this.height = Math.floor(this.height);
  22004. },
  22005. /**
  22006. * Runs Math.ceil() on both the x and y values of this Rectangle.
  22007. * @method Phaser.Rectangle#ceil
  22008. */
  22009. ceil: function () {
  22010. this.x = Math.ceil(this.x);
  22011. this.y = Math.ceil(this.y);
  22012. },
  22013. /**
  22014. * Runs Math.ceil() on the x, y, width and height values of this Rectangle.
  22015. * @method Phaser.Rectangle#ceilAll
  22016. */
  22017. ceilAll: function () {
  22018. this.x = Math.ceil(this.x);
  22019. this.y = Math.ceil(this.y);
  22020. this.width = Math.ceil(this.width);
  22021. this.height = Math.ceil(this.height);
  22022. },
  22023. /**
  22024. * Copies the x, y, width and height properties from any given object to this Rectangle.
  22025. * @method Phaser.Rectangle#copyFrom
  22026. * @param {any} source - The object to copy from.
  22027. * @return {Phaser.Rectangle} This Rectangle object.
  22028. */
  22029. copyFrom: function (source) {
  22030. return this.setTo(source.x, source.y, source.width, source.height);
  22031. },
  22032. /**
  22033. * Copies the left, top, width and height properties from any given object to this Rectangle.
  22034. * @method Phaser.Rectangle#copyFromBounds
  22035. * @param {any} source - The object to copy from.
  22036. * @return {Phaser.Rectangle} This Rectangle object.
  22037. */
  22038. copyFromBounds: function(source) {
  22039. return this.setTo(source.left, source.top, source.width, source.height);
  22040. },
  22041. /**
  22042. * Copies the x, y, width and height properties from this Rectangle to any given object.
  22043. * @method Phaser.Rectangle#copyTo
  22044. * @param {any} source - The object to copy to.
  22045. * @return {object} This object.
  22046. */
  22047. copyTo: function (dest) {
  22048. dest.x = this.x;
  22049. dest.y = this.y;
  22050. dest.width = this.width;
  22051. dest.height = this.height;
  22052. return dest;
  22053. },
  22054. /**
  22055. * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value.
  22056. * @method Phaser.Rectangle#inflate
  22057. * @param {number} dx - The amount to be added to the left side of the Rectangle.
  22058. * @param {number} dy - The amount to be added to the bottom side of the Rectangle.
  22059. * @return {Phaser.Rectangle} This Rectangle object.
  22060. */
  22061. inflate: function (dx, dy) {
  22062. return Phaser.Rectangle.inflate(this, dx, dy);
  22063. },
  22064. /**
  22065. * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties.
  22066. * @method Phaser.Rectangle#size
  22067. * @param {Phaser.Point} [output] - Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned.
  22068. * @return {Phaser.Point} The size of the Rectangle object.
  22069. */
  22070. size: function (output) {
  22071. return Phaser.Rectangle.size(this, output);
  22072. },
  22073. /**
  22074. * Resize the Rectangle by providing a new width and height.
  22075. * The x and y positions remain unchanged.
  22076. *
  22077. * @method Phaser.Rectangle#resize
  22078. * @param {number} width - The width of the Rectangle. Should always be either zero or a positive value.
  22079. * @param {number} height - The height of the Rectangle. Should always be either zero or a positive value.
  22080. * @return {Phaser.Rectangle} This Rectangle object
  22081. */
  22082. resize: function (width, height) {
  22083. this.width = width;
  22084. this.height = height;
  22085. return this;
  22086. },
  22087. /**
  22088. * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object.
  22089. * @method Phaser.Rectangle#clone
  22090. * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned.
  22091. * @return {Phaser.Rectangle}
  22092. */
  22093. clone: function (output) {
  22094. return Phaser.Rectangle.clone(this, output);
  22095. },
  22096. /**
  22097. * Determines whether the specified coordinates are contained within the region defined by this Rectangle object.
  22098. * @method Phaser.Rectangle#contains
  22099. * @param {number} x - The x coordinate of the point to test.
  22100. * @param {number} y - The y coordinate of the point to test.
  22101. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  22102. */
  22103. contains: function (x, y) {
  22104. return Phaser.Rectangle.contains(this, x, y);
  22105. },
  22106. /**
  22107. * Determines whether the first Rectangle object is fully contained within the second Rectangle object.
  22108. * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first.
  22109. * @method Phaser.Rectangle#containsRect
  22110. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22111. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  22112. */
  22113. containsRect: function (b) {
  22114. return Phaser.Rectangle.containsRect(b, this);
  22115. },
  22116. /**
  22117. * Determines whether the two Rectangles are equal.
  22118. * This method compares the x, y, width and height properties of each Rectangle.
  22119. * @method Phaser.Rectangle#equals
  22120. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22121. * @return {boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false.
  22122. */
  22123. equals: function (b) {
  22124. return Phaser.Rectangle.equals(this, b);
  22125. },
  22126. /**
  22127. * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0.
  22128. * @method Phaser.Rectangle#intersection
  22129. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22130. * @param {Phaser.Rectangle} out - Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
  22131. * @return {Phaser.Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0.
  22132. */
  22133. intersection: function (b, out) {
  22134. return Phaser.Rectangle.intersection(this, b, out);
  22135. },
  22136. /**
  22137. * Determines whether this Rectangle and another given Rectangle intersect with each other.
  22138. * This method checks the x, y, width, and height properties of the two Rectangles.
  22139. *
  22140. * @method Phaser.Rectangle#intersects
  22141. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22142. * @return {boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false.
  22143. */
  22144. intersects: function (b) {
  22145. return Phaser.Rectangle.intersects(this, b);
  22146. },
  22147. /**
  22148. * Determines whether the coordinates given intersects (overlaps) with this Rectangle.
  22149. *
  22150. * @method Phaser.Rectangle#intersectsRaw
  22151. * @param {number} left - The x coordinate of the left of the area.
  22152. * @param {number} right - The right coordinate of the area.
  22153. * @param {number} top - The y coordinate of the area.
  22154. * @param {number} bottom - The bottom coordinate of the area.
  22155. * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0
  22156. * @return {boolean} A value of true if the specified object intersects with the Rectangle; otherwise false.
  22157. */
  22158. intersectsRaw: function (left, right, top, bottom, tolerance) {
  22159. return Phaser.Rectangle.intersectsRaw(this, left, right, top, bottom, tolerance);
  22160. },
  22161. /**
  22162. * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles.
  22163. * @method Phaser.Rectangle#union
  22164. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22165. * @param {Phaser.Rectangle} [out] - Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
  22166. * @return {Phaser.Rectangle} A Rectangle object that is the union of the two Rectangles.
  22167. */
  22168. union: function (b, out) {
  22169. return Phaser.Rectangle.union(this, b, out);
  22170. },
  22171. /**
  22172. * Returns a uniformly distributed random point from anywhere within this Rectangle.
  22173. *
  22174. * @method Phaser.Rectangle#random
  22175. * @param {Phaser.Point|object} [out] - A Phaser.Point, or any object with public x/y properties, that the values will be set in.
  22176. * If no object is provided a new Phaser.Point object will be created. In high performance areas avoid this by re-using an existing object.
  22177. * @return {Phaser.Point} An object containing the random point in its `x` and `y` properties.
  22178. */
  22179. random: function (out) {
  22180. if (out === undefined) { out = new Phaser.Point(); }
  22181. out.x = this.randomX;
  22182. out.y = this.randomY;
  22183. return out;
  22184. },
  22185. /**
  22186. * Returns a point based on the given position constant, which can be one of:
  22187. *
  22188. * `Phaser.TOP_LEFT`, `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`,
  22189. * `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER`
  22190. * and `Phaser.BOTTOM_RIGHT`.
  22191. *
  22192. * This method returns the same values as calling Rectangle.bottomLeft, etc, but those
  22193. * calls always create a new Point object, where-as this one allows you to use your own.
  22194. *
  22195. * @method Phaser.Rectangle#getPoint
  22196. * @param {integer} [position] - One of the Phaser position constants, such as `Phaser.TOP_RIGHT`.
  22197. * @param {Phaser.Point} [out] - A Phaser.Point that the values will be set in.
  22198. * If no object is provided a new Phaser.Point object will be created. In high performance areas avoid this by re-using an existing object.
  22199. * @return {Phaser.Point} An object containing the point in its `x` and `y` properties.
  22200. */
  22201. getPoint: function (position, out) {
  22202. if (out === undefined) { out = new Phaser.Point(); }
  22203. switch (position)
  22204. {
  22205. default:
  22206. case Phaser.TOP_LEFT:
  22207. return out.set(this.x, this.y);
  22208. case Phaser.TOP_CENTER:
  22209. return out.set(this.centerX, this.y);
  22210. case Phaser.TOP_RIGHT:
  22211. return out.set(this.right, this.y);
  22212. case Phaser.LEFT_CENTER:
  22213. return out.set(this.x, this.centerY);
  22214. case Phaser.CENTER:
  22215. return out.set(this.centerX, this.centerY);
  22216. case Phaser.RIGHT_CENTER:
  22217. return out.set(this.right, this.centerY);
  22218. case Phaser.BOTTOM_LEFT:
  22219. return out.set(this.x, this.bottom);
  22220. case Phaser.BOTTOM_CENTER:
  22221. return out.set(this.centerX, this.bottom);
  22222. case Phaser.BOTTOM_RIGHT:
  22223. return out.set(this.right, this.bottom);
  22224. }
  22225. },
  22226. /**
  22227. * Creates or positions four {@link Phaser.Line} lines representing the Rectangle's sides.
  22228. *
  22229. * @method Phaser.Rectangle#sides
  22230. * @param {Phaser.Line} [top]
  22231. * @param {Phaser.Line} [right]
  22232. * @param {Phaser.Line} [bottom]
  22233. * @param {Phaser.Line} [left]
  22234. * @return {?Phaser.Line[]} - An array containing four lines (if no arguments were given), or null.
  22235. */
  22236. sides: function (top, right, bottom, left) {
  22237. if (!arguments.length) {
  22238. top = new Phaser.Line();
  22239. right = new Phaser.Line();
  22240. bottom = new Phaser.Line();
  22241. left = new Phaser.Line();
  22242. }
  22243. var x1 = this.x;
  22244. var y1 = this.y;
  22245. var x2 = this.right;
  22246. var y2 = this.bottom;
  22247. top.setTo(x1, y1, x2, y1);
  22248. right.setTo(x2, y1, x2, y2);
  22249. bottom.setTo(x1, y2, x2, y2);
  22250. left.setTo(x1, y1, x1, y2);
  22251. if (!arguments.length) {
  22252. return [top, right, bottom, left];
  22253. }
  22254. return null;
  22255. },
  22256. /**
  22257. * Returns a string representation of this object.
  22258. * @method Phaser.Rectangle#toString
  22259. * @return {string} A string representation of the instance.
  22260. */
  22261. toString: function () {
  22262. return "[{Rectangle (x=" + this.x + " y=" + this.y + " width=" + this.width + " height=" + this.height + " empty=" + this.empty + ")}]";
  22263. }
  22264. };
  22265. /**
  22266. * @name Phaser.Rectangle#halfWidth
  22267. * @property {number} halfWidth - Half of the width of the Rectangle.
  22268. * @readonly
  22269. */
  22270. Object.defineProperty(Phaser.Rectangle.prototype, "halfWidth", {
  22271. get: function () {
  22272. return Math.round(this.width / 2);
  22273. }
  22274. });
  22275. /**
  22276. * @name Phaser.Rectangle#halfHeight
  22277. * @property {number} halfHeight - Half of the height of the Rectangle.
  22278. * @readonly
  22279. */
  22280. Object.defineProperty(Phaser.Rectangle.prototype, "halfHeight", {
  22281. get: function () {
  22282. return Math.round(this.height / 2);
  22283. }
  22284. });
  22285. /**
  22286. * The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property.
  22287. * @name Phaser.Rectangle#bottom
  22288. * @property {number} bottom - The sum of the y and height properties.
  22289. */
  22290. Object.defineProperty(Phaser.Rectangle.prototype, "bottom", {
  22291. get: function () {
  22292. return this.y + this.height;
  22293. },
  22294. set: function (value) {
  22295. if (value <= this.y)
  22296. {
  22297. this.height = 0;
  22298. }
  22299. else
  22300. {
  22301. this.height = value - this.y;
  22302. }
  22303. }
  22304. });
  22305. /**
  22306. * The location of the Rectangles bottom left corner as a Point object.
  22307. * @name Phaser.Rectangle#bottomLeft
  22308. * @property {Phaser.Point} bottomLeft - Gets or sets the location of the Rectangles bottom left corner as a Point object.
  22309. */
  22310. Object.defineProperty(Phaser.Rectangle.prototype, "bottomLeft", {
  22311. get: function () {
  22312. return new Phaser.Point(this.x, this.bottom);
  22313. },
  22314. set: function (value) {
  22315. this.x = value.x;
  22316. this.bottom = value.y;
  22317. }
  22318. });
  22319. /**
  22320. * The location of the Rectangles bottom right corner as a Point object.
  22321. * @name Phaser.Rectangle#bottomRight
  22322. * @property {Phaser.Point} bottomRight - Gets or sets the location of the Rectangles bottom right corner as a Point object.
  22323. */
  22324. Object.defineProperty(Phaser.Rectangle.prototype, "bottomRight", {
  22325. get: function () {
  22326. return new Phaser.Point(this.right, this.bottom);
  22327. },
  22328. set: function (value) {
  22329. this.right = value.x;
  22330. this.bottom = value.y;
  22331. }
  22332. });
  22333. /**
  22334. * The x coordinate of the left of the Rectangle. Changing the left property of a Rectangle object has no effect on the y and height properties. However it does affect the width property, whereas changing the x value does not affect the width property.
  22335. * @name Phaser.Rectangle#left
  22336. * @property {number} left - The x coordinate of the left of the Rectangle.
  22337. */
  22338. Object.defineProperty(Phaser.Rectangle.prototype, "left", {
  22339. get: function () {
  22340. return this.x;
  22341. },
  22342. set: function (value) {
  22343. if (value >= this.right) {
  22344. this.width = 0;
  22345. } else {
  22346. this.width = this.right - value;
  22347. }
  22348. this.x = value;
  22349. }
  22350. });
  22351. /**
  22352. * The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties, however it does affect the width property.
  22353. * @name Phaser.Rectangle#right
  22354. * @property {number} right - The sum of the x and width properties.
  22355. */
  22356. Object.defineProperty(Phaser.Rectangle.prototype, "right", {
  22357. get: function () {
  22358. return this.x + this.width;
  22359. },
  22360. set: function (value) {
  22361. if (value <= this.x) {
  22362. this.width = 0;
  22363. } else {
  22364. this.width = value - this.x;
  22365. }
  22366. }
  22367. });
  22368. /**
  22369. * The volume of the Rectangle derived from width * height.
  22370. * @name Phaser.Rectangle#volume
  22371. * @property {number} volume - The volume of the Rectangle derived from width * height.
  22372. * @readonly
  22373. */
  22374. Object.defineProperty(Phaser.Rectangle.prototype, "volume", {
  22375. get: function () {
  22376. return this.width * this.height;
  22377. }
  22378. });
  22379. /**
  22380. * The perimeter size of the Rectangle. This is the sum of all 4 sides.
  22381. * @name Phaser.Rectangle#perimeter
  22382. * @property {number} perimeter - The perimeter size of the Rectangle. This is the sum of all 4 sides.
  22383. * @readonly
  22384. */
  22385. Object.defineProperty(Phaser.Rectangle.prototype, "perimeter", {
  22386. get: function () {
  22387. return (this.width * 2) + (this.height * 2);
  22388. }
  22389. });
  22390. /**
  22391. * The x coordinate of the center of the Rectangle.
  22392. * @name Phaser.Rectangle#centerX
  22393. * @property {number} centerX - The x coordinate of the center of the Rectangle.
  22394. */
  22395. Object.defineProperty(Phaser.Rectangle.prototype, "centerX", {
  22396. get: function () {
  22397. return this.x + this.halfWidth;
  22398. },
  22399. set: function (value) {
  22400. this.x = value - this.halfWidth;
  22401. }
  22402. });
  22403. /**
  22404. * The y coordinate of the center of the Rectangle.
  22405. * @name Phaser.Rectangle#centerY
  22406. * @property {number} centerY - The y coordinate of the center of the Rectangle.
  22407. */
  22408. Object.defineProperty(Phaser.Rectangle.prototype, "centerY", {
  22409. get: function () {
  22410. return this.y + this.halfHeight;
  22411. },
  22412. set: function (value) {
  22413. this.y = value - this.halfHeight;
  22414. }
  22415. });
  22416. /**
  22417. * A random value between the left and right values (inclusive) of the Rectangle.
  22418. *
  22419. * @name Phaser.Rectangle#randomX
  22420. * @property {number} randomX - A random value between the left and right values (inclusive) of the Rectangle.
  22421. */
  22422. Object.defineProperty(Phaser.Rectangle.prototype, "randomX", {
  22423. get: function () {
  22424. return this.x + (Math.random() * this.width);
  22425. }
  22426. });
  22427. /**
  22428. * A random value between the top and bottom values (inclusive) of the Rectangle.
  22429. *
  22430. * @name Phaser.Rectangle#randomY
  22431. * @property {number} randomY - A random value between the top and bottom values (inclusive) of the Rectangle.
  22432. */
  22433. Object.defineProperty(Phaser.Rectangle.prototype, "randomY", {
  22434. get: function () {
  22435. return this.y + (Math.random() * this.height);
  22436. }
  22437. });
  22438. /**
  22439. * The y coordinate of the top of the Rectangle. Changing the top property of a Rectangle object has no effect on the x and width properties.
  22440. * However it does affect the height property, whereas changing the y value does not affect the height property.
  22441. * @name Phaser.Rectangle#top
  22442. * @property {number} top - The y coordinate of the top of the Rectangle.
  22443. */
  22444. Object.defineProperty(Phaser.Rectangle.prototype, "top", {
  22445. get: function () {
  22446. return this.y;
  22447. },
  22448. set: function (value) {
  22449. if (value >= this.bottom) {
  22450. this.height = 0;
  22451. this.y = value;
  22452. } else {
  22453. this.height = (this.bottom - value);
  22454. }
  22455. }
  22456. });
  22457. /**
  22458. * The location of the Rectangles top left corner as a Point object.
  22459. * @name Phaser.Rectangle#topLeft
  22460. * @property {Phaser.Point} topLeft - The location of the Rectangles top left corner as a Point object.
  22461. */
  22462. Object.defineProperty(Phaser.Rectangle.prototype, "topLeft", {
  22463. get: function () {
  22464. return new Phaser.Point(this.x, this.y);
  22465. },
  22466. set: function (value) {
  22467. this.x = value.x;
  22468. this.y = value.y;
  22469. }
  22470. });
  22471. /**
  22472. * The location of the Rectangles top right corner as a Point object.
  22473. * @name Phaser.Rectangle#topRight
  22474. * @property {Phaser.Point} topRight - The location of the Rectangles top left corner as a Point object.
  22475. */
  22476. Object.defineProperty(Phaser.Rectangle.prototype, "topRight", {
  22477. get: function () {
  22478. return new Phaser.Point(this.x + this.width, this.y);
  22479. },
  22480. set: function (value) {
  22481. this.right = value.x;
  22482. this.y = value.y;
  22483. }
  22484. });
  22485. /**
  22486. * Determines whether or not this Rectangle object is empty. A Rectangle object is empty if its width or height is less than or equal to 0.
  22487. * If set to true then all of the Rectangle properties are set to 0.
  22488. * @name Phaser.Rectangle#empty
  22489. * @property {boolean} empty - Gets or sets the Rectangles empty state.
  22490. */
  22491. Object.defineProperty(Phaser.Rectangle.prototype, "empty", {
  22492. get: function () {
  22493. return (!this.width || !this.height);
  22494. },
  22495. set: function (value) {
  22496. if (value === true)
  22497. {
  22498. this.setTo(0, 0, 0, 0);
  22499. }
  22500. }
  22501. });
  22502. Phaser.Rectangle.prototype.constructor = Phaser.Rectangle;
  22503. /**
  22504. * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value.
  22505. * @method Phaser.Rectangle.inflate
  22506. * @param {Phaser.Rectangle} a - The Rectangle object.
  22507. * @param {number} dx - The amount to be added to the left side of the Rectangle.
  22508. * @param {number} dy - The amount to be added to the bottom side of the Rectangle.
  22509. * @return {Phaser.Rectangle} This Rectangle object.
  22510. */
  22511. Phaser.Rectangle.inflate = function (a, dx, dy) {
  22512. a.x -= dx;
  22513. a.width += 2 * dx;
  22514. a.y -= dy;
  22515. a.height += 2 * dy;
  22516. return a;
  22517. };
  22518. /**
  22519. * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter.
  22520. * @method Phaser.Rectangle.inflatePoint
  22521. * @param {Phaser.Rectangle} a - The Rectangle object.
  22522. * @param {Phaser.Point} point - The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object.
  22523. * @return {Phaser.Rectangle} The Rectangle object.
  22524. */
  22525. Phaser.Rectangle.inflatePoint = function (a, point) {
  22526. return Phaser.Rectangle.inflate(a, point.x, point.y);
  22527. };
  22528. /**
  22529. * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties.
  22530. * @method Phaser.Rectangle.size
  22531. * @param {Phaser.Rectangle} a - The Rectangle object.
  22532. * @param {Phaser.Point} [output] - Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned.
  22533. * @return {Phaser.Point} The size of the Rectangle object
  22534. */
  22535. Phaser.Rectangle.size = function (a, output) {
  22536. if (output === undefined || output === null)
  22537. {
  22538. output = new Phaser.Point(a.width, a.height);
  22539. }
  22540. else
  22541. {
  22542. output.setTo(a.width, a.height);
  22543. }
  22544. return output;
  22545. };
  22546. /**
  22547. * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object.
  22548. * @method Phaser.Rectangle.clone
  22549. * @param {Phaser.Rectangle} a - The Rectangle object.
  22550. * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned.
  22551. * @return {Phaser.Rectangle}
  22552. */
  22553. Phaser.Rectangle.clone = function (a, output) {
  22554. if (output === undefined || output === null)
  22555. {
  22556. output = new Phaser.Rectangle(a.x, a.y, a.width, a.height);
  22557. }
  22558. else
  22559. {
  22560. output.setTo(a.x, a.y, a.width, a.height);
  22561. }
  22562. return output;
  22563. };
  22564. /**
  22565. * Returns a new Rectangle object with the same values for the left, top, width, and height properties as the original object.
  22566. * @method Phaser.Rectangle.createFromBounds
  22567. * @param {any} a - An object with `left`, `top`, `width`, and `height` properties.
  22568. * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned.
  22569. * @return {Phaser.Rectangle}
  22570. */
  22571. Phaser.Rectangle.createFromBounds = function (a, output) {
  22572. if (output === undefined || output === null)
  22573. {
  22574. output = new Phaser.Rectangle(a.x, a.y, a.width, a.height);
  22575. }
  22576. return output.copyFromBounds(a);
  22577. };
  22578. /**
  22579. * Determines whether the specified coordinates are contained within the region defined by this Rectangle object.
  22580. * @method Phaser.Rectangle.contains
  22581. * @param {Phaser.Rectangle} a - The Rectangle object.
  22582. * @param {number} x - The x coordinate of the point to test.
  22583. * @param {number} y - The y coordinate of the point to test.
  22584. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  22585. */
  22586. Phaser.Rectangle.contains = function (a, x, y) {
  22587. if (a.width <= 0 || a.height <= 0)
  22588. {
  22589. return false;
  22590. }
  22591. return (x >= a.x && x < a.right && y >= a.y && y < a.bottom);
  22592. };
  22593. /**
  22594. * Determines whether the specified coordinates are contained within the region defined by the given raw values.
  22595. * @method Phaser.Rectangle.containsRaw
  22596. * @param {number} rx - The x coordinate of the top left of the area.
  22597. * @param {number} ry - The y coordinate of the top left of the area.
  22598. * @param {number} rw - The width of the area.
  22599. * @param {number} rh - The height of the area.
  22600. * @param {number} x - The x coordinate of the point to test.
  22601. * @param {number} y - The y coordinate of the point to test.
  22602. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  22603. */
  22604. Phaser.Rectangle.containsRaw = function (rx, ry, rw, rh, x, y) {
  22605. return (x >= rx && x < (rx + rw) && y >= ry && y < (ry + rh));
  22606. };
  22607. /**
  22608. * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter.
  22609. * @method Phaser.Rectangle.containsPoint
  22610. * @param {Phaser.Rectangle} a - The Rectangle object.
  22611. * @param {Phaser.Point} point - The point object being checked. Can be Point or any object with .x and .y values.
  22612. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  22613. */
  22614. Phaser.Rectangle.containsPoint = function (a, point) {
  22615. return Phaser.Rectangle.contains(a, point.x, point.y);
  22616. };
  22617. /**
  22618. * Determines whether the first Rectangle object is fully contained within the second Rectangle object.
  22619. * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first.
  22620. * @method Phaser.Rectangle.containsRect
  22621. * @param {Phaser.Rectangle} a - The first Rectangle object.
  22622. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22623. * @return {boolean} A value of true if the Rectangle object contains the specified point; otherwise false.
  22624. */
  22625. Phaser.Rectangle.containsRect = function (a, b) {
  22626. // If the given rect has a larger volume than this one then it can never contain it
  22627. if (a.volume > b.volume)
  22628. {
  22629. return false;
  22630. }
  22631. return (a.x >= b.x && a.y >= b.y && a.right < b.right && a.bottom < b.bottom);
  22632. };
  22633. /**
  22634. * Determines whether the two Rectangles are equal.
  22635. * This method compares the x, y, width and height properties of each Rectangle.
  22636. * @method Phaser.Rectangle.equals
  22637. * @param {Phaser.Rectangle} a - The first Rectangle object.
  22638. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22639. * @return {boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false.
  22640. */
  22641. Phaser.Rectangle.equals = function (a, b) {
  22642. return (a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height);
  22643. };
  22644. /**
  22645. * Determines if the two objects (either Rectangles or Rectangle-like) have the same width and height values under strict equality.
  22646. * @method Phaser.Rectangle.sameDimensions
  22647. * @param {Rectangle-like} a - The first Rectangle object.
  22648. * @param {Rectangle-like} b - The second Rectangle object.
  22649. * @return {boolean} True if the object have equivalent values for the width and height properties.
  22650. */
  22651. Phaser.Rectangle.sameDimensions = function (a, b) {
  22652. return (a.width === b.width && a.height === b.height);
  22653. };
  22654. /**
  22655. * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0.
  22656. * @method Phaser.Rectangle.intersection
  22657. * @param {Phaser.Rectangle} a - The first Rectangle object.
  22658. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22659. * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
  22660. * @return {Phaser.Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0.
  22661. */
  22662. Phaser.Rectangle.intersection = function (a, b, output) {
  22663. if (output === undefined)
  22664. {
  22665. output = new Phaser.Rectangle();
  22666. }
  22667. if (Phaser.Rectangle.intersects(a, b))
  22668. {
  22669. output.x = Math.max(a.x, b.x);
  22670. output.y = Math.max(a.y, b.y);
  22671. output.width = Math.min(a.right, b.right) - output.x;
  22672. output.height = Math.min(a.bottom, b.bottom) - output.y;
  22673. }
  22674. return output;
  22675. };
  22676. /**
  22677. * Determines whether the two Rectangles intersect with each other.
  22678. * This method checks the x, y, width, and height properties of the Rectangles.
  22679. * @method Phaser.Rectangle.intersects
  22680. * @param {Phaser.Rectangle} a - The first Rectangle object.
  22681. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22682. * @return {boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false.
  22683. */
  22684. Phaser.Rectangle.intersects = function (a, b) {
  22685. if (a.width <= 0 || a.height <= 0 || b.width <= 0 || b.height <= 0)
  22686. {
  22687. return false;
  22688. }
  22689. return !(a.right < b.x || a.bottom < b.y || a.x > b.right || a.y > b.bottom);
  22690. };
  22691. /**
  22692. * Determines whether the object specified intersects (overlaps) with the given values.
  22693. * @method Phaser.Rectangle.intersectsRaw
  22694. * @param {number} left - The x coordinate of the left of the area.
  22695. * @param {number} right - The right coordinate of the area.
  22696. * @param {number} top - The y coordinate of the area.
  22697. * @param {number} bottom - The bottom coordinate of the area.
  22698. * @param {number} tolerance - A tolerance value to allow for an intersection test with padding, default to 0
  22699. * @return {boolean} A value of true if the specified object intersects with the Rectangle; otherwise false.
  22700. */
  22701. Phaser.Rectangle.intersectsRaw = function (a, left, right, top, bottom, tolerance) {
  22702. if (tolerance === undefined) { tolerance = 0; }
  22703. return !(left > a.right + tolerance || right < a.left - tolerance || top > a.bottom + tolerance || bottom < a.top - tolerance);
  22704. };
  22705. /**
  22706. * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles.
  22707. * @method Phaser.Rectangle.union
  22708. * @param {Phaser.Rectangle} a - The first Rectangle object.
  22709. * @param {Phaser.Rectangle} b - The second Rectangle object.
  22710. * @param {Phaser.Rectangle} [output] - Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned.
  22711. * @return {Phaser.Rectangle} A Rectangle object that is the union of the two Rectangles.
  22712. */
  22713. Phaser.Rectangle.union = function (a, b, output) {
  22714. if (output === undefined)
  22715. {
  22716. output = new Phaser.Rectangle();
  22717. }
  22718. return output.setTo(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.right, b.right) - Math.min(a.left, b.left), Math.max(a.bottom, b.bottom) - Math.min(a.top, b.top));
  22719. };
  22720. /**
  22721. * Calculates the Axis Aligned Bounding Box (or aabb) from an array of points.
  22722. *
  22723. * @method Phaser.Rectangle#aabb
  22724. * @param {Phaser.Point[]} points - The array of one or more points.
  22725. * @param {Phaser.Rectangle} [out] - Optional Rectangle to store the value in, if not supplied a new Rectangle object will be created.
  22726. * @return {Phaser.Rectangle} The new Rectangle object.
  22727. * @static
  22728. */
  22729. Phaser.Rectangle.aabb = function(points, out) {
  22730. if (out === undefined) {
  22731. out = new Phaser.Rectangle();
  22732. }
  22733. var xMax = Number.NEGATIVE_INFINITY,
  22734. xMin = Number.POSITIVE_INFINITY,
  22735. yMax = Number.NEGATIVE_INFINITY,
  22736. yMin = Number.POSITIVE_INFINITY;
  22737. points.forEach(function(point) {
  22738. if (point.x > xMax) {
  22739. xMax = point.x;
  22740. }
  22741. if (point.x < xMin) {
  22742. xMin = point.x;
  22743. }
  22744. if (point.y > yMax) {
  22745. yMax = point.y;
  22746. }
  22747. if (point.y < yMin) {
  22748. yMin = point.y;
  22749. }
  22750. });
  22751. out.setTo(xMin, yMin, xMax - xMin, yMax - yMin);
  22752. return out;
  22753. };
  22754. // Because PIXI uses its own Rectangle, we'll replace it with ours to avoid duplicating code or confusion.
  22755. PIXI.Rectangle = Phaser.Rectangle;
  22756. PIXI.EmptyRectangle = new Phaser.Rectangle(0, 0, 0, 0);
  22757. /**
  22758. * @author Mat Groves http://matgroves.com/
  22759. * @author Richard Davey <rich@photonstorm.com>
  22760. * @copyright 2016 Photon Storm Ltd.
  22761. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  22762. */
  22763. /**
  22764. * The Rounded Rectangle object is an area defined by its position and has nice rounded corners,
  22765. * as indicated by its top-left corner point (x, y) and by its width and its height.
  22766. *
  22767. * @class Phaser.RoundedRectangle
  22768. * @constructor
  22769. * @param {number} [x=0] - The x coordinate of the top-left corner of the Rectangle.
  22770. * @param {number} [y=0] - The y coordinate of the top-left corner of the Rectangle.
  22771. * @param {number} [width=0] - The width of the Rectangle. Should always be either zero or a positive value.
  22772. * @param {number} [height=0] - The height of the Rectangle. Should always be either zero or a positive value.
  22773. * @param {number} [radius=20] - Controls the radius of the rounded corners.
  22774. */
  22775. Phaser.RoundedRectangle = function(x, y, width, height, radius)
  22776. {
  22777. if (x === undefined) { x = 0; }
  22778. if (y === undefined) { y = 0; }
  22779. if (width === undefined) { width = 0; }
  22780. if (height === undefined) { height = 0; }
  22781. if (radius === undefined) { radius = 20; }
  22782. /**
  22783. * @property {number} x - The x coordinate of the top-left corner of the Rectangle.
  22784. */
  22785. this.x = x;
  22786. /**
  22787. * @property {number} y - The y coordinate of the top-left corner of the Rectangle.
  22788. */
  22789. this.y = y;
  22790. /**
  22791. * @property {number} width - The width of the Rectangle. This value should never be set to a negative.
  22792. */
  22793. this.width = width;
  22794. /**
  22795. * @property {number} height - The height of the Rectangle. This value should never be set to a negative.
  22796. */
  22797. this.height = height;
  22798. /**
  22799. * @property {number} radius - The radius of the rounded corners.
  22800. */
  22801. this.radius = radius || 20;
  22802. /**
  22803. * @property {number} type - The const type of this object.
  22804. * @readonly
  22805. */
  22806. this.type = Phaser.ROUNDEDRECTANGLE;
  22807. };
  22808. Phaser.RoundedRectangle.prototype = {
  22809. /**
  22810. * Returns a new RoundedRectangle object with the same values for the x, y, width, height and
  22811. * radius properties as this RoundedRectangle object.
  22812. *
  22813. * @method Phaser.RoundedRectangle#clone
  22814. * @return {Phaser.RoundedRectangle}
  22815. */
  22816. clone: function () {
  22817. return new Phaser.RoundedRectangle(this.x, this.y, this.width, this.height, this.radius);
  22818. },
  22819. /**
  22820. * Determines whether the specified coordinates are contained within the region defined by this Rounded Rectangle object.
  22821. *
  22822. * @method Phaser.RoundedRectangle#contains
  22823. * @param {number} x - The x coordinate of the point to test.
  22824. * @param {number} y - The y coordinate of the point to test.
  22825. * @return {boolean} A value of true if the RoundedRectangle Rectangle object contains the specified point; otherwise false.
  22826. */
  22827. contains: function (x, y) {
  22828. if (this.width <= 0 || this.height <= 0)
  22829. {
  22830. return false;
  22831. }
  22832. var x1 = this.x;
  22833. if (x >= x1 && x <= x1 + this.width)
  22834. {
  22835. var y1 = this.y;
  22836. if (y >= y1 && y <= y1 + this.height)
  22837. {
  22838. return true;
  22839. }
  22840. }
  22841. return false;
  22842. }
  22843. };
  22844. Phaser.RoundedRectangle.prototype.constructor = Phaser.RoundedRectangle;
  22845. // Because PIXI uses its own type, we'll replace it with ours to avoid duplicating code or confusion.
  22846. PIXI.RoundedRectangle = Phaser.RoundedRectangle;
  22847. /**
  22848. * @author Richard Davey <rich@photonstorm.com>
  22849. * @copyright 2016 Photon Storm Ltd.
  22850. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  22851. */
  22852. /**
  22853. * A Camera is your view into the game world. It has a position and size and renders only those objects within its field of view.
  22854. * The game automatically creates a single Stage sized camera on boot. Move the camera around the world with Phaser.Camera.x/y
  22855. *
  22856. * @class Phaser.Camera
  22857. * @constructor
  22858. * @param {Phaser.Game} game - Game reference to the currently running game.
  22859. * @param {number} id - Not being used at the moment, will be when Phaser supports multiple camera
  22860. * @param {number} x - Position of the camera on the X axis
  22861. * @param {number} y - Position of the camera on the Y axis
  22862. * @param {number} width - The width of the view rectangle
  22863. * @param {number} height - The height of the view rectangle
  22864. */
  22865. Phaser.Camera = function (game, id, x, y, width, height) {
  22866. /**
  22867. * @property {Phaser.Game} game - A reference to the currently running Game.
  22868. */
  22869. this.game = game;
  22870. /**
  22871. * @property {Phaser.World} world - A reference to the game world.
  22872. */
  22873. this.world = game.world;
  22874. /**
  22875. * @property {number} id - Reserved for future multiple camera set-ups.
  22876. * @default
  22877. */
  22878. this.id = 0;
  22879. /**
  22880. * Camera view.
  22881. * The view into the world we wish to render (by default the game dimensions).
  22882. * The x/y values are in world coordinates, not screen coordinates, the width/height is how many pixels to render.
  22883. * Sprites outside of this view are not rendered if Sprite.autoCull is set to `true`. Otherwise they are always rendered.
  22884. * @property {Phaser.Rectangle} view
  22885. */
  22886. this.view = new Phaser.Rectangle(x, y, width, height);
  22887. /**
  22888. * The Camera is bound to this Rectangle and cannot move outside of it. By default it is enabled and set to the size of the World.
  22889. * The Rectangle can be located anywhere in the world and updated as often as you like. If you don't wish the Camera to be bound
  22890. * at all then set this to null. The values can be anything and are in World coordinates, with 0,0 being the top-left of the world.
  22891. *
  22892. * @property {Phaser.Rectangle} bounds - The Rectangle in which the Camera is bounded. Set to null to allow for movement anywhere.
  22893. */
  22894. this.bounds = new Phaser.Rectangle(x, y, width, height);
  22895. /**
  22896. * @property {Phaser.Rectangle} deadzone - Moving inside this Rectangle will not cause the camera to move.
  22897. */
  22898. this.deadzone = null;
  22899. /**
  22900. * @property {boolean} visible - Whether this camera is visible or not.
  22901. * @default
  22902. */
  22903. this.visible = true;
  22904. /**
  22905. * @property {boolean} roundPx - If a Camera has roundPx set to `true` it will call `view.floor` as part of its update loop, keeping its boundary to integer values. Set this to `false` to disable this from happening.
  22906. * @default
  22907. */
  22908. this.roundPx = true;
  22909. /**
  22910. * @property {boolean} atLimit - Whether this camera is flush with the World Bounds or not.
  22911. */
  22912. this.atLimit = { x: false, y: false };
  22913. /**
  22914. * @property {Phaser.Sprite} target - If the camera is tracking a Sprite, this is a reference to it, otherwise null.
  22915. * @default
  22916. */
  22917. this.target = null;
  22918. /**
  22919. * @property {PIXI.DisplayObject} displayObject - The display object to which all game objects are added. Set by World.boot.
  22920. */
  22921. this.displayObject = null;
  22922. /**
  22923. * @property {Phaser.Point} scale - The scale of the display object to which all game objects are added. Set by World.boot.
  22924. */
  22925. this.scale = null;
  22926. /**
  22927. * @property {number} totalInView - The total number of Sprites with `autoCull` set to `true` that are visible by this Camera.
  22928. * @readonly
  22929. */
  22930. this.totalInView = 0;
  22931. /**
  22932. * The linear interpolation value to use when following a target.
  22933. * The default values of 1 means the camera will instantly snap to the target coordinates.
  22934. * A lower value, such as 0.1 means the camera will more slowly track the target, giving
  22935. * a smooth transition. You can set the horizontal and vertical values independently, and also
  22936. * adjust this value in real-time during your game.
  22937. * @property {Phaser.Point} lerp
  22938. * @default
  22939. */
  22940. this.lerp = new Phaser.Point(1, 1);
  22941. /**
  22942. * @property {Phaser.Signal} onShakeComplete - This signal is dispatched when the camera shake effect completes.
  22943. */
  22944. this.onShakeComplete = new Phaser.Signal();
  22945. /**
  22946. * @property {Phaser.Signal} onFlashComplete - This signal is dispatched when the camera flash effect completes.
  22947. */
  22948. this.onFlashComplete = new Phaser.Signal();
  22949. /**
  22950. * This signal is dispatched when the camera fade effect completes.
  22951. * When the fade effect completes you will be left with the screen black (or whatever
  22952. * color you faded to). In order to reset this call `Camera.resetFX`. This is called
  22953. * automatically when you change State.
  22954. * @property {Phaser.Signal} onFadeComplete
  22955. */
  22956. this.onFadeComplete = new Phaser.Signal();
  22957. /**
  22958. * The Graphics object used to handle camera fx such as fade and flash.
  22959. * @property {Phaser.Graphics} fx
  22960. * @protected
  22961. */
  22962. this.fx = null;
  22963. /**
  22964. * @property {Phaser.Point} _targetPosition - Internal point used to calculate target position.
  22965. * @private
  22966. */
  22967. this._targetPosition = new Phaser.Point();
  22968. /**
  22969. * @property {number} edge - Edge property.
  22970. * @private
  22971. * @default
  22972. */
  22973. this._edge = 0;
  22974. /**
  22975. * @property {Phaser.Point} position - Current position of the camera in world.
  22976. * @private
  22977. * @default
  22978. */
  22979. this._position = new Phaser.Point();
  22980. /**
  22981. * @property {Object} _shake - The shake effect container.
  22982. * @private
  22983. */
  22984. this._shake = {
  22985. intensity: 0,
  22986. duration: 0,
  22987. horizontal: false,
  22988. vertical: false,
  22989. shakeBounds: true,
  22990. x: 0,
  22991. y: 0
  22992. };
  22993. /**
  22994. * @property {number} _fxDuration - FX duration timer.
  22995. * @private
  22996. */
  22997. this._fxDuration = 0;
  22998. /**
  22999. * @property {number} _fxType - The FX type running.
  23000. * @private
  23001. */
  23002. this._fxType = 0;
  23003. /**
  23004. * @property {Phaser.Rectangle}
  23005. * @private
  23006. */
  23007. this._fixedView = new Phaser.Rectangle();
  23008. };
  23009. /**
  23010. * A follow style that uses no deadzone.
  23011. *
  23012. * @constant
  23013. * @type {number}
  23014. */
  23015. Phaser.Camera.FOLLOW_LOCKON = 0;
  23016. /**
  23017. * A follow style that uses a tall, narrow deadzone (0.33 x 0.125) with a center slightly above the view center.
  23018. *
  23019. * @constant
  23020. * @type {number}
  23021. */
  23022. Phaser.Camera.FOLLOW_PLATFORMER = 1;
  23023. /**
  23024. * A follow style that uses a square deadzone (0.25 of the larger view edge).
  23025. *
  23026. * @constant
  23027. * @type {number}
  23028. */
  23029. Phaser.Camera.FOLLOW_TOPDOWN = 2;
  23030. /**
  23031. * A follow style that uses a small square deadzone (0.125 of the larger view edge).
  23032. *
  23033. * @constant
  23034. * @type {number}
  23035. */
  23036. Phaser.Camera.FOLLOW_TOPDOWN_TIGHT = 3;
  23037. /**
  23038. * @constant
  23039. * @type {number}
  23040. */
  23041. Phaser.Camera.SHAKE_BOTH = 4;
  23042. /**
  23043. * @constant
  23044. * @type {number}
  23045. */
  23046. Phaser.Camera.SHAKE_HORIZONTAL = 5;
  23047. /**
  23048. * @constant
  23049. * @type {number}
  23050. */
  23051. Phaser.Camera.SHAKE_VERTICAL = 6;
  23052. /**
  23053. * @constant
  23054. * @type {boolean}
  23055. */
  23056. Phaser.Camera.ENABLE_FX = true;
  23057. Phaser.Camera.prototype = {
  23058. /**
  23059. * Called automatically by Phaser.World.
  23060. *
  23061. * @method Phaser.Camera#boot
  23062. * @private
  23063. */
  23064. boot: function () {
  23065. this.displayObject = this.game.world;
  23066. this.scale = this.game.world.scale;
  23067. this.game.camera = this;
  23068. if (Phaser.Graphics && Phaser.Camera.ENABLE_FX)
  23069. {
  23070. this.fx = new Phaser.Graphics(this.game);
  23071. this.game.stage.addChild(this.fx);
  23072. }
  23073. },
  23074. /**
  23075. * Camera preUpdate. Sets the total view counter to zero.
  23076. *
  23077. * @method Phaser.Camera#preUpdate
  23078. */
  23079. preUpdate: function () {
  23080. this.totalInView = 0;
  23081. },
  23082. /**
  23083. * Tell the camera which sprite to follow.
  23084. *
  23085. * You can set the follow type and a linear interpolation value.
  23086. * Use low lerp values (such as 0.1) to automatically smooth the camera motion.
  23087. *
  23088. * If you find you're getting a slight "jitter" effect when following a Sprite it's probably to do with sub-pixel rendering of the Sprite position.
  23089. * This can be disabled by setting `game.renderer.renderSession.roundPixels = true` to force full pixel rendering.
  23090. *
  23091. * @method Phaser.Camera#follow
  23092. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text} target - The object you want the camera to track. Set to null to not follow anything.
  23093. * @param {number} [style] - Leverage one of the existing {@link deadzone} presets. If you use a custom deadzone, ignore this parameter and manually specify the deadzone after calling follow().
  23094. * @param {float} [lerpX=1] - A value between 0 and 1. This value specifies the amount of linear interpolation to use when horizontally tracking the target. The closer the value to 1, the faster the camera will track.
  23095. * @param {float} [lerpY=1] - A value between 0 and 1. This value specifies the amount of linear interpolation to use when vertically tracking the target. The closer the value to 1, the faster the camera will track.
  23096. */
  23097. follow: function (target, style, lerpX, lerpY) {
  23098. if (style === undefined) { style = Phaser.Camera.FOLLOW_LOCKON; }
  23099. if (lerpX === undefined) { lerpX = 1; }
  23100. if (lerpY === undefined) { lerpY = 1; }
  23101. this.target = target;
  23102. this.lerp.set(lerpX, lerpY);
  23103. var helper;
  23104. switch (style) {
  23105. case Phaser.Camera.FOLLOW_PLATFORMER:
  23106. var w = this.width / 8;
  23107. var h = this.height / 3;
  23108. this.deadzone = new Phaser.Rectangle((this.width - w) / 2, (this.height - h) / 2 - h * 0.25, w, h);
  23109. break;
  23110. case Phaser.Camera.FOLLOW_TOPDOWN:
  23111. helper = Math.max(this.width, this.height) / 4;
  23112. this.deadzone = new Phaser.Rectangle((this.width - helper) / 2, (this.height - helper) / 2, helper, helper);
  23113. break;
  23114. case Phaser.Camera.FOLLOW_TOPDOWN_TIGHT:
  23115. helper = Math.max(this.width, this.height) / 8;
  23116. this.deadzone = new Phaser.Rectangle((this.width - helper) / 2, (this.height - helper) / 2, helper, helper);
  23117. break;
  23118. case Phaser.Camera.FOLLOW_LOCKON:
  23119. this.deadzone = null;
  23120. break;
  23121. default:
  23122. this.deadzone = null;
  23123. break;
  23124. }
  23125. },
  23126. /**
  23127. * Sets the Camera follow target to null, stopping it from following an object if it's doing so.
  23128. *
  23129. * @method Phaser.Camera#unfollow
  23130. */
  23131. unfollow: function () {
  23132. this.target = null;
  23133. },
  23134. /**
  23135. * Move the camera focus on a display object instantly.
  23136. * @method Phaser.Camera#focusOn
  23137. * @param {any} displayObject - The display object to focus the camera on. Must have visible x/y properties.
  23138. */
  23139. focusOn: function (displayObject) {
  23140. this.setPosition(Math.round(displayObject.x - this.view.halfWidth), Math.round(displayObject.y - this.view.halfHeight));
  23141. },
  23142. /**
  23143. * Move the camera focus on a location instantly.
  23144. * @method Phaser.Camera#focusOnXY
  23145. * @param {number} x - X position.
  23146. * @param {number} y - Y position.
  23147. */
  23148. focusOnXY: function (x, y) {
  23149. this.setPosition(Math.round(x - this.view.halfWidth), Math.round(y - this.view.halfHeight));
  23150. },
  23151. /**
  23152. * This creates a camera shake effect. It works by applying a random amount of additional
  23153. * spacing on the x and y axis each frame. You can control the intensity and duration
  23154. * of the effect, and if it should effect both axis or just one.
  23155. *
  23156. * When the shake effect ends the signal Camera.onShakeComplete is dispatched.
  23157. *
  23158. * @method Phaser.Camera#shake
  23159. * @param {float} [intensity=0.05] - The intensity of the camera shake. Given as a percentage of the camera size representing the maximum distance that the camera can move while shaking.
  23160. * @param {number} [duration=500] - The duration of the shake effect in milliseconds.
  23161. * @param {boolean} [force=true] - If a camera shake effect is already running and force is true it will replace the previous effect, resetting the duration.
  23162. * @param {number} [direction=Phaser.Camera.SHAKE_BOTH] - The directions in which the camera can shake. Either Phaser.Camera.SHAKE_BOTH, Phaser.Camera.SHAKE_HORIZONTAL or Phaser.Camera.SHAKE_VERTICAL.
  23163. * @param {boolean} [shakeBounds=true] - Is the effect allowed to shake the camera beyond its bounds (if set?).
  23164. * @return {boolean} True if the shake effect was started, otherwise false.
  23165. */
  23166. shake: function (intensity, duration, force, direction, shakeBounds) {
  23167. if (intensity === undefined) { intensity = 0.05; }
  23168. if (duration === undefined) { duration = 500; }
  23169. if (force === undefined) { force = true; }
  23170. if (direction === undefined) { direction = Phaser.Camera.SHAKE_BOTH; }
  23171. if (shakeBounds === undefined) { shakeBounds = true; }
  23172. if (!force && this._shake.duration > 0)
  23173. {
  23174. // Can't reset an already running shake
  23175. return false;
  23176. }
  23177. this._shake.intensity = intensity;
  23178. this._shake.duration = duration;
  23179. this._shake.shakeBounds = shakeBounds;
  23180. this._shake.x = 0;
  23181. this._shake.y = 0;
  23182. this._shake.horizontal = (direction === Phaser.Camera.SHAKE_BOTH || direction === Phaser.Camera.SHAKE_HORIZONTAL);
  23183. this._shake.vertical = (direction === Phaser.Camera.SHAKE_BOTH || direction === Phaser.Camera.SHAKE_VERTICAL);
  23184. return true;
  23185. },
  23186. /**
  23187. * This creates a camera flash effect. It works by filling the game with the solid fill
  23188. * color specified, and then fading it away to alpha 0 over the duration given.
  23189. *
  23190. * You can use this for things such as hit feedback effects.
  23191. *
  23192. * When the effect ends the signal Camera.onFlashComplete is dispatched.
  23193. *
  23194. * @method Phaser.Camera#flash
  23195. * @param {numer} [color=0xffffff] - The color of the flash effect. I.e. 0xffffff for white, 0xff0000 for red, etc.
  23196. * @param {number} [duration=500] - The duration of the flash effect in milliseconds.
  23197. * @param {boolean} [force=false] - If a camera flash or fade effect is already running and force is true it will replace the previous effect, resetting the duration.
  23198. * @param {numer} [alpha=1] - The alpha value of the color applied to the flash effect.
  23199. * @return {boolean} True if the effect was started, otherwise false.
  23200. */
  23201. flash: function (color, duration, force, alpha) {
  23202. if (color === undefined) { color = 0xffffff; }
  23203. if (duration === undefined) { duration = 500; }
  23204. if (force === undefined) { force = false; }
  23205. if (alpha === undefined) { alpha = 1; }
  23206. if (!this.fx || (!force && this._fxDuration > 0))
  23207. {
  23208. return false;
  23209. }
  23210. this.fx.clear();
  23211. this.fx.beginFill(color, alpha);
  23212. this.fx.drawRect(0, 0, this.width, this.height);
  23213. this.fx.endFill();
  23214. this.fx.alpha = 1;
  23215. this._fxDuration = duration;
  23216. this._fxType = 0;
  23217. return true;
  23218. },
  23219. /**
  23220. * This creates a camera fade effect. It works by filling the game with the
  23221. * color specified, over the duration given, ending with a solid fill.
  23222. *
  23223. * You can use this for things such as transitioning to a new scene.
  23224. *
  23225. * The game will be left 'filled' at the end of this effect, likely obscuring
  23226. * everything. In order to reset it you can call `Camera.resetFX` and it will clear the
  23227. * fade. Or you can call `Camera.flash` with the same color as the fade, and it will
  23228. * reverse the process, bringing the game back into view again.
  23229. *
  23230. * When the effect ends the signal Camera.onFadeComplete is dispatched.
  23231. *
  23232. * @method Phaser.Camera#fade
  23233. * @param {numer} [color=0x000000] - The color the game will fade to. I.e. 0x000000 for black, 0xff0000 for red, etc.
  23234. * @param {number} [duration=500] - The duration of the fade in milliseconds.
  23235. * @param {boolean} [force=false] - If a camera flash or fade effect is already running and force is true it will replace the previous effect, resetting the duration.
  23236. * @param {numer} [alpha=1] - The alpha value of the color applied to the fade effect.
  23237. * @return {boolean} True if the effect was started, otherwise false.
  23238. */
  23239. fade: function (color, duration, force, alpha) {
  23240. if (color === undefined) { color = 0x000000; }
  23241. if (duration === undefined) { duration = 500; }
  23242. if (force === undefined) { force = false; }
  23243. if (alpha === undefined) { alpha = 1; }
  23244. if (!this.fx || (!force && this._fxDuration > 0))
  23245. {
  23246. return false;
  23247. }
  23248. this.fx.clear();
  23249. this.fx.beginFill(color, alpha);
  23250. this.fx.drawRect(0, 0, this.width, this.height);
  23251. this.fx.endFill();
  23252. this.fx.alpha = 0;
  23253. this._fxDuration = duration;
  23254. this._fxType = 1;
  23255. return true;
  23256. },
  23257. /**
  23258. * The camera update loop. This is called automatically by the core game loop.
  23259. *
  23260. * @method Phaser.Camera#update
  23261. * @protected
  23262. */
  23263. update: function () {
  23264. if (this._fxDuration > 0)
  23265. {
  23266. this.updateFX();
  23267. }
  23268. if (this._shake.duration > 0)
  23269. {
  23270. this.updateShake();
  23271. }
  23272. if (this.bounds)
  23273. {
  23274. this.checkBounds();
  23275. }
  23276. if (this.roundPx)
  23277. {
  23278. this.view.floor();
  23279. this._shake.x = Math.floor(this._shake.x);
  23280. this._shake.y = Math.floor(this._shake.y);
  23281. }
  23282. this.displayObject.position.x = -this.view.x;
  23283. this.displayObject.position.y = -this.view.y;
  23284. },
  23285. /**
  23286. * Update the camera flash and fade effects.
  23287. *
  23288. * @method Phaser.Camera#updateFX
  23289. * @private
  23290. */
  23291. updateFX: function () {
  23292. if (this._fxType === 0)
  23293. {
  23294. // flash
  23295. this.fx.alpha -= this.game.time.elapsedMS / this._fxDuration;
  23296. if (this.fx.alpha <= 0)
  23297. {
  23298. this._fxDuration = 0;
  23299. this.fx.alpha = 0;
  23300. this.onFlashComplete.dispatch();
  23301. }
  23302. }
  23303. else
  23304. {
  23305. // fade
  23306. this.fx.alpha += this.game.time.elapsedMS / this._fxDuration;
  23307. if (this.fx.alpha >= 1)
  23308. {
  23309. this._fxDuration = 0;
  23310. this.fx.alpha = 1;
  23311. this.onFadeComplete.dispatch();
  23312. }
  23313. }
  23314. },
  23315. /**
  23316. * Update the camera shake effect.
  23317. *
  23318. * @method Phaser.Camera#updateShake
  23319. * @private
  23320. */
  23321. updateShake: function () {
  23322. this._shake.duration -= this.game.time.elapsedMS;
  23323. if (this._shake.duration <= 0)
  23324. {
  23325. this.onShakeComplete.dispatch();
  23326. this._shake.x = 0;
  23327. this._shake.y = 0;
  23328. }
  23329. else
  23330. {
  23331. if (this._shake.horizontal)
  23332. {
  23333. this._shake.x = this.game.rnd.frac() * this._shake.intensity * this.view.width * 2 - this._shake.intensity * this.view.width;
  23334. }
  23335. if (this._shake.vertical)
  23336. {
  23337. this._shake.y = this.game.rnd.frac() * this._shake.intensity * this.view.height * 2 - this._shake.intensity * this.view.height;
  23338. }
  23339. }
  23340. },
  23341. /**
  23342. * Internal method that handles tracking a sprite.
  23343. *
  23344. * @method Phaser.Camera#updateTarget
  23345. * @private
  23346. */
  23347. updateTarget: function () {
  23348. this._targetPosition.x = this.view.x + this.target.worldPosition.x;
  23349. this._targetPosition.y = this.view.y + this.target.worldPosition.y;
  23350. if (this.deadzone)
  23351. {
  23352. this._edge = this._targetPosition.x - this.view.x;
  23353. if (this._edge < this.deadzone.left)
  23354. {
  23355. this.view.x = this.game.math.linear(this.view.x, this._targetPosition.x - this.deadzone.left, this.lerp.x);
  23356. }
  23357. else if (this._edge > this.deadzone.right)
  23358. {
  23359. this.view.x = this.game.math.linear(this.view.x, this._targetPosition.x - this.deadzone.right, this.lerp.x);
  23360. }
  23361. this._edge = this._targetPosition.y - this.view.y;
  23362. if (this._edge < this.deadzone.top)
  23363. {
  23364. this.view.y = this.game.math.linear(this.view.y, this._targetPosition.y - this.deadzone.top, this.lerp.y);
  23365. }
  23366. else if (this._edge > this.deadzone.bottom)
  23367. {
  23368. this.view.y = this.game.math.linear(this.view.y, this._targetPosition.y - this.deadzone.bottom, this.lerp.y);
  23369. }
  23370. }
  23371. else
  23372. {
  23373. this.view.x = this.game.math.linear(this.view.x, this._targetPosition.x - this.view.halfWidth, this.lerp.x);
  23374. this.view.y = this.game.math.linear(this.view.y, this._targetPosition.y - this.view.halfHeight, this.lerp.y);
  23375. }
  23376. if (this.bounds)
  23377. {
  23378. this.checkBounds();
  23379. }
  23380. if (this.roundPx)
  23381. {
  23382. this.view.floor();
  23383. }
  23384. this.displayObject.position.x = -this.view.x;
  23385. this.displayObject.position.y = -this.view.y;
  23386. },
  23387. /**
  23388. * Update the Camera bounds to match the game world.
  23389. *
  23390. * @method Phaser.Camera#setBoundsToWorld
  23391. */
  23392. setBoundsToWorld: function () {
  23393. if (this.bounds)
  23394. {
  23395. this.bounds.copyFrom(this.game.world.bounds);
  23396. }
  23397. },
  23398. /**
  23399. * Method called to ensure the camera doesn't venture outside of the game world.
  23400. * Called automatically by Camera.update.
  23401. *
  23402. * @method Phaser.Camera#checkBounds
  23403. * @protected
  23404. */
  23405. checkBounds: function () {
  23406. this.atLimit.x = false;
  23407. this.atLimit.y = false;
  23408. var vx = this.view.x + this._shake.x;
  23409. var vw = this.view.right + this._shake.x;
  23410. var vy = this.view.y + this._shake.y;
  23411. var vh = this.view.bottom + this._shake.y;
  23412. // Make sure we didn't go outside the cameras bounds
  23413. if (vx <= this.bounds.x * this.scale.x)
  23414. {
  23415. this.atLimit.x = true;
  23416. this.view.x = this.bounds.x * this.scale.x;
  23417. if (!this._shake.shakeBounds)
  23418. {
  23419. // The camera is up against the bounds, so reset the shake
  23420. this._shake.x = 0;
  23421. }
  23422. }
  23423. else if (vw >= this.bounds.right * this.scale.x)
  23424. {
  23425. this.atLimit.x = true;
  23426. this.view.x = (this.bounds.right * this.scale.x) - this.width;
  23427. if (!this._shake.shakeBounds)
  23428. {
  23429. // The camera is up against the bounds, so reset the shake
  23430. this._shake.x = 0;
  23431. }
  23432. }
  23433. if (vy <= this.bounds.top * this.scale.y)
  23434. {
  23435. this.atLimit.y = true;
  23436. this.view.y = this.bounds.top * this.scale.y;
  23437. if (!this._shake.shakeBounds)
  23438. {
  23439. // The camera is up against the bounds, so reset the shake
  23440. this._shake.y = 0;
  23441. }
  23442. }
  23443. else if (vh >= this.bounds.bottom * this.scale.y)
  23444. {
  23445. this.atLimit.y = true;
  23446. this.view.y = (this.bounds.bottom * this.scale.y) - this.height;
  23447. if (!this._shake.shakeBounds)
  23448. {
  23449. // The camera is up against the bounds, so reset the shake
  23450. this._shake.y = 0;
  23451. }
  23452. }
  23453. },
  23454. /**
  23455. * A helper function to set both the X and Y properties of the camera at once
  23456. * without having to use game.camera.x and game.camera.y.
  23457. *
  23458. * @method Phaser.Camera#setPosition
  23459. * @param {number} x - X position.
  23460. * @param {number} y - Y position.
  23461. */
  23462. setPosition: function (x, y) {
  23463. this.view.x = x;
  23464. this.view.y = y;
  23465. if (this.bounds)
  23466. {
  23467. this.checkBounds();
  23468. }
  23469. },
  23470. /**
  23471. * Sets the size of the view rectangle given the width and height in parameters.
  23472. *
  23473. * @method Phaser.Camera#setSize
  23474. * @param {number} width - The desired width.
  23475. * @param {number} height - The desired height.
  23476. */
  23477. setSize: function (width, height) {
  23478. this.view.width = width;
  23479. this.view.height = height;
  23480. },
  23481. /**
  23482. * Resets the camera back to 0,0 and un-follows any object it may have been tracking.
  23483. * Also immediately resets any camera effects that may have been running such as
  23484. * shake, flash or fade.
  23485. *
  23486. * @method Phaser.Camera#reset
  23487. */
  23488. reset: function () {
  23489. this.target = null;
  23490. this.view.x = 0;
  23491. this.view.y = 0;
  23492. this._shake.duration = 0;
  23493. this._shake.x = 0;
  23494. this._shake.y = 0;
  23495. this.resetFX();
  23496. },
  23497. /**
  23498. * Resets any active FX, such as a fade or flash and immediately clears it.
  23499. * Useful to calling after a fade in order to remove the fade from the Stage.
  23500. *
  23501. * @method Phaser.Camera#resetFX
  23502. */
  23503. resetFX: function () {
  23504. if (this.fx)
  23505. {
  23506. this.fx.clear();
  23507. this.fx.alpha = 0;
  23508. }
  23509. this._fxDuration = 0;
  23510. }
  23511. };
  23512. Phaser.Camera.prototype.constructor = Phaser.Camera;
  23513. /**
  23514. * The Cameras x coordinate. This value is automatically clamped if it falls outside of the World bounds.
  23515. * @name Phaser.Camera#x
  23516. * @property {number} x - Gets or sets the cameras x position.
  23517. */
  23518. Object.defineProperty(Phaser.Camera.prototype, "x", {
  23519. get: function () {
  23520. return this.view.x;
  23521. },
  23522. set: function (value) {
  23523. this.view.x = value;
  23524. if (this.bounds)
  23525. {
  23526. this.checkBounds();
  23527. }
  23528. }
  23529. });
  23530. /**
  23531. * The Cameras y coordinate. This value is automatically clamped if it falls outside of the World bounds.
  23532. * @name Phaser.Camera#y
  23533. * @property {number} y - Gets or sets the cameras y position.
  23534. */
  23535. Object.defineProperty(Phaser.Camera.prototype, "y", {
  23536. get: function () {
  23537. return this.view.y;
  23538. },
  23539. set: function (value) {
  23540. this.view.y = value;
  23541. if (this.bounds)
  23542. {
  23543. this.checkBounds();
  23544. }
  23545. }
  23546. });
  23547. /**
  23548. * The Cameras position. This value is automatically clamped if it falls outside of the World bounds.
  23549. * @name Phaser.Camera#position
  23550. * @property {Phaser.Point} position - Gets or sets the cameras xy position using Phaser.Point object.
  23551. */
  23552. Object.defineProperty(Phaser.Camera.prototype, "position", {
  23553. get: function () {
  23554. this._position.set(this.view.x, this.view.y);
  23555. return this._position;
  23556. },
  23557. set: function (value) {
  23558. if (typeof value.x !== "undefined") { this.view.x = value.x; }
  23559. if (typeof value.y !== "undefined") { this.view.y = value.y; }
  23560. if (this.bounds)
  23561. {
  23562. this.checkBounds();
  23563. }
  23564. }
  23565. });
  23566. /**
  23567. * The Cameras width. By default this is the same as the Game size and should not be adjusted for now.
  23568. * @name Phaser.Camera#width
  23569. * @property {number} width - Gets or sets the cameras width.
  23570. */
  23571. Object.defineProperty(Phaser.Camera.prototype, "width", {
  23572. get: function () {
  23573. return this.view.width;
  23574. },
  23575. set: function (value) {
  23576. this.view.width = value;
  23577. }
  23578. });
  23579. /**
  23580. * The Cameras height. By default this is the same as the Game size and should not be adjusted for now.
  23581. * @name Phaser.Camera#height
  23582. * @property {number} height - Gets or sets the cameras height.
  23583. */
  23584. Object.defineProperty(Phaser.Camera.prototype, "height", {
  23585. get: function () {
  23586. return this.view.height;
  23587. },
  23588. set: function (value) {
  23589. this.view.height = value;
  23590. }
  23591. });
  23592. /**
  23593. * The Cameras shake intensity.
  23594. * @name Phaser.Camera#shakeIntensity
  23595. * @property {number} shakeIntensity - Gets or sets the cameras shake intensity.
  23596. */
  23597. Object.defineProperty(Phaser.Camera.prototype, "shakeIntensity", {
  23598. get: function () {
  23599. return this._shake.intensity;
  23600. },
  23601. set: function (value) {
  23602. this._shake.intensity = value;
  23603. }
  23604. });
  23605. /**
  23606. * Immobile {@link #view} rectangle. Its top-left is always (0, 0). You can use this align fixedToCamera objects.
  23607. * @name Phaser.Camera#fixedView
  23608. * @property {Phaser.Rectangle} fixedView
  23609. * @readonly
  23610. */
  23611. Object.defineProperty(Phaser.Camera.prototype, "fixedView", {
  23612. get: function () {
  23613. this._fixedView.setTo(0, 0, this.view.width, this.view.height);
  23614. return this._fixedView;
  23615. }
  23616. });
  23617. /**
  23618. * @author Richard Davey <rich@photonstorm.com>
  23619. * @copyright 2016 Photon Storm Ltd.
  23620. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  23621. */
  23622. /**
  23623. * This is a base State class which can be extended if you are creating your own game.
  23624. * It provides quick access to common functions such as the camera, cache, input, match, sound and more.
  23625. *
  23626. * #### Callbacks
  23627. *
  23628. * | start | preload | loaded | paused | stop |
  23629. * |-------|-------------|------------|--------------|----------|
  23630. * | init | | | | |
  23631. * | | preload | create | paused | |
  23632. * | | loadUpdate* | update* | pauseUpdate* | |
  23633. * | | | preRender* | | |
  23634. * | | loadRender* | render* | render* | |
  23635. * | | | | resumed | |
  23636. * | | | | | shutdown |
  23637. *
  23638. * Update and render calls (*) are repeated.
  23639. *
  23640. * If your State has a constructor, it will be invoked exactly once, during {@link {@link Phaser.StateManager#add}.
  23641. *
  23642. * @class Phaser.State
  23643. * @constructor
  23644. */
  23645. Phaser.State = function () {
  23646. /**
  23647. * @property {Phaser.Game} game - This is a reference to the currently running Game.
  23648. */
  23649. this.game = null;
  23650. /**
  23651. * @property {string} key - The string based identifier given to the State when added into the State Manager.
  23652. */
  23653. this.key = '';
  23654. /**
  23655. * @property {Phaser.GameObjectFactory} add - A reference to the GameObjectFactory which can be used to add new objects to the World.
  23656. */
  23657. this.add = null;
  23658. /**
  23659. * @property {Phaser.GameObjectCreator} make - A reference to the GameObjectCreator which can be used to make new objects.
  23660. */
  23661. this.make = null;
  23662. /**
  23663. * @property {Phaser.Camera} camera - A handy reference to World.camera.
  23664. */
  23665. this.camera = null;
  23666. /**
  23667. * @property {Phaser.Cache} cache - A reference to the game cache which contains any loaded or generated assets, such as images, sound and more.
  23668. */
  23669. this.cache = null;
  23670. /**
  23671. * @property {Phaser.Input} input - A reference to the Input Manager.
  23672. */
  23673. this.input = null;
  23674. /**
  23675. * @property {Phaser.Loader} load - A reference to the Loader, which you mostly use in the preload method of your state to load external assets.
  23676. */
  23677. this.load = null;
  23678. /**
  23679. * @property {Phaser.Math} math - A reference to Math class with lots of helpful functions.
  23680. */
  23681. this.math = null;
  23682. /**
  23683. * @property {Phaser.SoundManager} sound - A reference to the Sound Manager which can create, play and stop sounds, as well as adjust global volume.
  23684. */
  23685. this.sound = null;
  23686. /**
  23687. * @property {Phaser.ScaleManager} scale - A reference to the Scale Manager which controls the way the game scales on different displays.
  23688. */
  23689. this.scale = null;
  23690. /**
  23691. * @property {Phaser.Stage} stage - A reference to the Stage.
  23692. */
  23693. this.stage = null;
  23694. /**
  23695. * @property {Phaser.StateManager} stage - A reference to the State Manager, which controls state changes.
  23696. */
  23697. this.state = null;
  23698. /**
  23699. * @property {Phaser.Time} time - A reference to the game clock and timed events system.
  23700. */
  23701. this.time = null;
  23702. /**
  23703. * @property {Phaser.TweenManager} tweens - A reference to the tween manager.
  23704. */
  23705. this.tweens = null;
  23706. /**
  23707. * @property {Phaser.World} world - A reference to the game world. All objects live in the Game World and its size is not bound by the display resolution.
  23708. */
  23709. this.world = null;
  23710. /**
  23711. * @property {Phaser.Particles} particles - The Particle Manager. It is called during the core gameloop and updates any Particle Emitters it has created.
  23712. */
  23713. this.particles = null;
  23714. /**
  23715. * @property {Phaser.Physics} physics - A reference to the physics manager which looks after the different physics systems available within Phaser.
  23716. */
  23717. this.physics = null;
  23718. /**
  23719. * @property {Phaser.RandomDataGenerator} rnd - A reference to the seeded and repeatable random data generator.
  23720. */
  23721. this.rnd = null;
  23722. };
  23723. Phaser.State.prototype = {
  23724. /**
  23725. * init is the very first function called when your State starts up. It's called before preload, create or anything else.
  23726. * If you need to route the game away to another State you could do so here, or if you need to prepare a set of variables
  23727. * or objects before the preloading starts.
  23728. *
  23729. * @method Phaser.State#init
  23730. * @param {...any} args - Any extra arguments passed to {@link Phaser.StateManager#start} or {@link Phaser.StateManager#restart}.
  23731. */
  23732. init: function () {
  23733. },
  23734. /**
  23735. * preload is called first. Normally you'd use this to load your game assets (or those needed for the current State)
  23736. * You shouldn't create any objects in this method that require assets that you're also loading in this method, as
  23737. * they won't yet be available.
  23738. *
  23739. * @method Phaser.State#preload
  23740. * @param {Phaser.Game} game
  23741. */
  23742. preload: function () {
  23743. },
  23744. /**
  23745. * loadUpdate is called during the Loader process. This only happens if you've set one or more assets to load in the preload method.
  23746. *
  23747. * @method Phaser.State#loadUpdate
  23748. * @param {Phaser.Game} game
  23749. */
  23750. loadUpdate: function () {
  23751. },
  23752. /**
  23753. * loadRender is called during the Loader process. This only happens if you've set one or more assets to load in the preload method.
  23754. * The difference between loadRender and render is that any objects you render in this method you must be sure their assets exist.
  23755. *
  23756. * @method Phaser.State#loadRender
  23757. * @param {Phaser.Game} game
  23758. */
  23759. loadRender: function () {
  23760. },
  23761. /**
  23762. * create is called once preload has completed, this includes the loading of any assets from the Loader.
  23763. * If you don't have a preload method then create is the first method called in your State.
  23764. *
  23765. * @method Phaser.State#create
  23766. * @param {Phaser.Game} game
  23767. */
  23768. create: function () {
  23769. },
  23770. /**
  23771. * The update method is left empty for your own use.
  23772. * It is called during the core game loop AFTER debug, physics, plugins and the Stage have had their preUpdate methods called.
  23773. * It is called BEFORE Stage, Tweens, Sounds, Input, Physics, Particles and Plugins have had their postUpdate methods called.
  23774. *
  23775. * @method Phaser.State#update
  23776. * @param {Phaser.Game} game
  23777. */
  23778. update: function () {
  23779. },
  23780. /**
  23781. * The preRender method is called after all Game Objects have been updated, but before any rendering takes place.
  23782. *
  23783. * @method Phaser.State#preRender
  23784. * @param {Phaser.Game} game
  23785. * @param {number} elapsedTime
  23786. */
  23787. preRender: function () {
  23788. },
  23789. /**
  23790. * Nearly all display objects in Phaser render automatically, you don't need to tell them to render.
  23791. * However the render method is called AFTER the game renderer and plugins have rendered, so you're able to do any
  23792. * final post-processing style effects here. Note that this happens before plugins postRender takes place.
  23793. *
  23794. * @method Phaser.State#render
  23795. * @param {Phaser.Game} game
  23796. */
  23797. render: function () {
  23798. },
  23799. /**
  23800. * If your game is set to Scalemode RESIZE then each time the browser resizes it will call this function, passing in the new width and height.
  23801. *
  23802. * @method Phaser.State#resize
  23803. * @param {number} width
  23804. * @param {number} height
  23805. */
  23806. resize: function () {
  23807. },
  23808. /**
  23809. * This method will be called if the core game loop is paused.
  23810. *
  23811. * @method Phaser.State#paused
  23812. * @param {Phaser.Game} game
  23813. */
  23814. paused: function () {
  23815. },
  23816. /**
  23817. * This method will be called when the core game loop resumes from a paused state.
  23818. *
  23819. * @method Phaser.State#resumed
  23820. * @param {Phaser.Game} game
  23821. */
  23822. resumed: function () {
  23823. },
  23824. /**
  23825. * pauseUpdate is called while the game is paused instead of preUpdate, update and postUpdate.
  23826. *
  23827. * @method Phaser.State#pauseUpdate
  23828. * @param {Phaser.Game} game
  23829. */
  23830. pauseUpdate: function () {
  23831. },
  23832. /**
  23833. * This method will be called when the State is shutdown (i.e. you switch to another state from this one).
  23834. *
  23835. * @method Phaser.State#shutdown
  23836. * @param {Phaser.Game} game
  23837. */
  23838. shutdown: function () {
  23839. }
  23840. };
  23841. Phaser.State.prototype.constructor = Phaser.State;
  23842. /* jshint newcap: false */
  23843. /**
  23844. * @author Richard Davey <rich@photonstorm.com>
  23845. * @copyright 2016 Photon Storm Ltd.
  23846. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  23847. */
  23848. /**
  23849. * The State Manager is responsible for loading, setting up and switching game states.
  23850. *
  23851. * @class Phaser.StateManager
  23852. * @constructor
  23853. * @param {Phaser.Game} game - A reference to the currently running game.
  23854. * @param {Phaser.State|Object} [pendingState=null] - A State object to seed the manager with.
  23855. */
  23856. Phaser.StateManager = function (game, pendingState) {
  23857. /**
  23858. * @property {Phaser.Game} game - A reference to the currently running game.
  23859. */
  23860. this.game = game;
  23861. /**
  23862. * @property {object} states - The object containing Phaser.States.
  23863. */
  23864. this.states = {};
  23865. /**
  23866. * @property {Phaser.State} _pendingState - The state to be switched to in the next frame.
  23867. * @private
  23868. */
  23869. this._pendingState = null;
  23870. if (typeof pendingState !== 'undefined' && pendingState !== null)
  23871. {
  23872. this._pendingState = pendingState;
  23873. }
  23874. /**
  23875. * @property {boolean} _clearWorld - Clear the world when we switch state?
  23876. * @private
  23877. */
  23878. this._clearWorld = false;
  23879. /**
  23880. * @property {boolean} _clearCache - Clear the cache when we switch state?
  23881. * @private
  23882. */
  23883. this._clearCache = false;
  23884. /**
  23885. * @property {boolean} _created - Flag that sets if the State has been created or not.
  23886. * @private
  23887. */
  23888. this._created = false;
  23889. /**
  23890. * @property {any[]} _args - Temporary container when you pass vars from one State to another.
  23891. * @private
  23892. */
  23893. this._args = [];
  23894. /**
  23895. * @property {string} current - The current active State object.
  23896. * @default
  23897. */
  23898. this.current = '';
  23899. /**
  23900. * onStateChange is a Phaser.Signal that is dispatched whenever the game changes state.
  23901. *
  23902. * It is dispatched only when the new state is started, which isn't usually at the same time as StateManager.start
  23903. * is called because state swapping is done in sync with the game loop. It is dispatched *before* any of the new states
  23904. * methods (such as preload and create) are called, and *after* the previous states shutdown method has been run.
  23905. *
  23906. * The callback you specify is sent two parameters: the string based key of the new state,
  23907. * and the second parameter is the string based key of the old / previous state.
  23908. *
  23909. * @property {Phaser.Signal} onStateChange
  23910. */
  23911. this.onStateChange = new Phaser.Signal();
  23912. /**
  23913. * @property {function} onInitCallback - This is called when the state is set as the active state.
  23914. * @default
  23915. */
  23916. this.onInitCallback = null;
  23917. /**
  23918. * @property {function} onPreloadCallback - This is called when the state starts to load assets.
  23919. * @default
  23920. */
  23921. this.onPreloadCallback = null;
  23922. /**
  23923. * @property {function} onCreateCallback - This is called when the state preload has finished and creation begins.
  23924. * @default
  23925. */
  23926. this.onCreateCallback = null;
  23927. /**
  23928. * @property {function} onUpdateCallback - This is called when the state is updated, every game loop. It doesn't happen during preload (@see onLoadUpdateCallback).
  23929. * @default
  23930. */
  23931. this.onUpdateCallback = null;
  23932. /**
  23933. * @property {function} onRenderCallback - This is called post-render. It doesn't happen during preload (see onLoadRenderCallback).
  23934. * @default
  23935. */
  23936. this.onRenderCallback = null;
  23937. /**
  23938. * @property {function} onResizeCallback - This is called if ScaleManager.scalemode is RESIZE and a resize event occurs. It's passed the new width and height.
  23939. * @default
  23940. */
  23941. this.onResizeCallback = null;
  23942. /**
  23943. * @property {function} onPreRenderCallback - This is called before the state is rendered and before the stage is cleared but after all game objects have had their final properties adjusted.
  23944. * @default
  23945. */
  23946. this.onPreRenderCallback = null;
  23947. /**
  23948. * @property {function} onLoadUpdateCallback - This is called when the State is updated during the preload phase.
  23949. * @default
  23950. */
  23951. this.onLoadUpdateCallback = null;
  23952. /**
  23953. * @property {function} onLoadRenderCallback - This is called when the State is rendered during the preload phase.
  23954. * @default
  23955. */
  23956. this.onLoadRenderCallback = null;
  23957. /**
  23958. * @property {function} onPausedCallback - This is called when the game is paused.
  23959. * @default
  23960. */
  23961. this.onPausedCallback = null;
  23962. /**
  23963. * @property {function} onResumedCallback - This is called when the game is resumed from a paused state.
  23964. * @default
  23965. */
  23966. this.onResumedCallback = null;
  23967. /**
  23968. * @property {function} onPauseUpdateCallback - This is called every frame while the game is paused.
  23969. * @default
  23970. */
  23971. this.onPauseUpdateCallback = null;
  23972. /**
  23973. * @property {function} onShutDownCallback - This is called when the state is shut down (i.e. swapped to another state).
  23974. * @default
  23975. */
  23976. this.onShutDownCallback = null;
  23977. };
  23978. Phaser.StateManager.prototype = {
  23979. /**
  23980. * The Boot handler is called by Phaser.Game when it first starts up.
  23981. * @method Phaser.StateManager#boot
  23982. * @private
  23983. */
  23984. boot: function () {
  23985. this.game.onPause.add(this.pause, this);
  23986. this.game.onResume.add(this.resume, this);
  23987. if (this._pendingState !== null && typeof this._pendingState !== 'string')
  23988. {
  23989. this.add('default', this._pendingState, true);
  23990. }
  23991. },
  23992. /**
  23993. * Adds a new State into the StateManager. You must give each State a unique key by which you'll identify it.
  23994. *
  23995. * The State can be any of
  23996. *
  23997. * - a plain JavaScript object containing at least one required callback (see {@link #checkState})
  23998. * - an instance of {@link Phaser.State}
  23999. * - an instance of a class extending Phaser.State
  24000. * - a constructor function (class)
  24001. *
  24002. * If a function is given a new state object will be created by calling it, passing the current {@link Phaser.Game game} as the first argument.
  24003. *
  24004. * @method Phaser.StateManager#add
  24005. * @param {string} key - A unique key you use to reference this state, i.e. "MainMenu", "Level1".
  24006. * @param {Phaser.State|object|function} state - The state you want to switch to.
  24007. * @param {boolean} [autoStart=false] - If true the State will be started immediately after adding it.
  24008. */
  24009. add: function (key, state, autoStart) {
  24010. if (autoStart === undefined) { autoStart = false; }
  24011. var newState;
  24012. if (state instanceof Phaser.State)
  24013. {
  24014. newState = state;
  24015. }
  24016. else if (typeof state === 'object')
  24017. {
  24018. newState = state;
  24019. newState.game = this.game;
  24020. }
  24021. else if (typeof state === 'function')
  24022. {
  24023. newState = new state(this.game);
  24024. }
  24025. this.states[key] = newState;
  24026. if (autoStart)
  24027. {
  24028. if (this.game.isBooted)
  24029. {
  24030. this.start(key);
  24031. }
  24032. else
  24033. {
  24034. this._pendingState = key;
  24035. }
  24036. }
  24037. return newState;
  24038. },
  24039. /**
  24040. * Delete the given state.
  24041. * @method Phaser.StateManager#remove
  24042. * @param {string} key - A unique key you use to reference this state, i.e. "MainMenu", "Level1".
  24043. */
  24044. remove: function (key) {
  24045. if (this.current === key)
  24046. {
  24047. this.callbackContext = null;
  24048. this.onInitCallback = null;
  24049. this.onShutDownCallback = null;
  24050. this.onPreloadCallback = null;
  24051. this.onLoadRenderCallback = null;
  24052. this.onLoadUpdateCallback = null;
  24053. this.onCreateCallback = null;
  24054. this.onUpdateCallback = null;
  24055. this.onPreRenderCallback = null;
  24056. this.onRenderCallback = null;
  24057. this.onResizeCallback = null;
  24058. this.onPausedCallback = null;
  24059. this.onResumedCallback = null;
  24060. this.onPauseUpdateCallback = null;
  24061. }
  24062. delete this.states[key];
  24063. },
  24064. /**
  24065. * Start the given State. If a State is already running then State.shutDown will be called (if it exists) before switching to the new State.
  24066. *
  24067. * @method Phaser.StateManager#start
  24068. * @param {string} key - The key of the state you want to start.
  24069. * @param {boolean} [clearWorld=true] - Clear everything in the world? This clears the World display list fully (but not the Stage, so if you've added your own objects to the Stage they will need managing directly)
  24070. * @param {boolean} [clearCache=false] - Clear the Game.Cache? This purges out all loaded assets. The default is false and you must have clearWorld=true if you want to clearCache as well.
  24071. * @param {...*} parameter - Additional parameters that will be passed to the State.init function (if it has one).
  24072. */
  24073. start: function (key, clearWorld, clearCache) {
  24074. if (clearWorld === undefined) { clearWorld = true; }
  24075. if (clearCache === undefined) { clearCache = false; }
  24076. if (this.checkState(key))
  24077. {
  24078. // Place the state in the queue. It will be started the next time the game loop begins.
  24079. this._pendingState = key;
  24080. this._clearWorld = clearWorld;
  24081. this._clearCache = clearCache;
  24082. if (arguments.length > 3)
  24083. {
  24084. this._args = Array.prototype.splice.call(arguments, 3);
  24085. }
  24086. }
  24087. },
  24088. /**
  24089. * Restarts the current State. State.shutDown will be called (if it exists) before the State is restarted.
  24090. *
  24091. * @method Phaser.StateManager#restart
  24092. * @param {boolean} [clearWorld=true] - Clear everything in the world? This clears the World display list fully (but not the Stage, so if you've added your own objects to the Stage they will need managing directly)
  24093. * @param {boolean} [clearCache=false] - Clear the Game.Cache? This purges out all loaded assets. The default is false and you must have clearWorld=true if you want to clearCache as well.
  24094. * @param {...*} parameter - Additional parameters that will be passed to the State.init function if it has one.
  24095. */
  24096. restart: function (clearWorld, clearCache) {
  24097. if (clearWorld === undefined) { clearWorld = true; }
  24098. if (clearCache === undefined) { clearCache = false; }
  24099. // Place the state in the queue. It will be started the next time the game loop starts.
  24100. this._pendingState = this.current;
  24101. this._clearWorld = clearWorld;
  24102. this._clearCache = clearCache;
  24103. if (arguments.length > 2)
  24104. {
  24105. this._args = Array.prototype.slice.call(arguments, 2);
  24106. }
  24107. },
  24108. /**
  24109. * Used by onInit and onShutdown when those functions don't exist on the state
  24110. * @method Phaser.StateManager#dummy
  24111. * @private
  24112. */
  24113. dummy: function () {
  24114. },
  24115. /**
  24116. * preUpdate is called right at the start of the game loop. It is responsible for changing to a new state that was requested previously.
  24117. *
  24118. * @method Phaser.StateManager#preUpdate
  24119. */
  24120. preUpdate: function () {
  24121. if (this._pendingState && this.game.isBooted)
  24122. {
  24123. var previousStateKey = this.current;
  24124. // Already got a state running?
  24125. this.clearCurrentState();
  24126. this.setCurrentState(this._pendingState);
  24127. this.onStateChange.dispatch(this.current, previousStateKey);
  24128. if (this.current !== this._pendingState)
  24129. {
  24130. return;
  24131. }
  24132. else
  24133. {
  24134. this._pendingState = null;
  24135. }
  24136. // If StateManager.start has been called from the init of a State that ALSO has a preload, then
  24137. // onPreloadCallback will be set, but must be ignored
  24138. if (this.onPreloadCallback)
  24139. {
  24140. this.game.load.reset(true);
  24141. this.onPreloadCallback.call(this.callbackContext, this.game);
  24142. // Is the loader empty?
  24143. if (this.game.load.totalQueuedFiles() === 0 && this.game.load.totalQueuedPacks() === 0)
  24144. {
  24145. this.loadComplete();
  24146. }
  24147. else
  24148. {
  24149. // Start the loader going as we have something in the queue
  24150. this.game.load.start();
  24151. }
  24152. }
  24153. else
  24154. {
  24155. // No init? Then there was nothing to load either
  24156. this.loadComplete();
  24157. }
  24158. }
  24159. },
  24160. /**
  24161. * This method clears the current State, calling its shutdown callback. The process also removes any active tweens,
  24162. * resets the camera, resets input, clears physics, removes timers and if set clears the world and cache too.
  24163. *
  24164. * @method Phaser.StateManager#clearCurrentState
  24165. */
  24166. clearCurrentState: function () {
  24167. if (this.current)
  24168. {
  24169. if (this.onShutDownCallback)
  24170. {
  24171. this.onShutDownCallback.call(this.callbackContext, this.game);
  24172. }
  24173. this.game.tweens.removeAll();
  24174. this.game.camera.reset();
  24175. this.game.input.reset(true);
  24176. this.game.physics.clear();
  24177. this.game.time.removeAll();
  24178. this.game.scale.reset(this._clearWorld);
  24179. if (this.game.debug)
  24180. {
  24181. this.game.debug.reset();
  24182. }
  24183. if (this._clearWorld)
  24184. {
  24185. this.game.world.shutdown();
  24186. if (this._clearCache)
  24187. {
  24188. this.game.cache.destroy();
  24189. }
  24190. }
  24191. }
  24192. },
  24193. /**
  24194. * Checks if a given phaser state is valid. A State is considered valid if it has at least one of the core functions: preload, create, update or render.
  24195. *
  24196. * @method Phaser.StateManager#checkState
  24197. * @param {string} key - The key of the state you want to check.
  24198. * @return {boolean} true if the State has the required functions, otherwise false.
  24199. */
  24200. checkState: function (key) {
  24201. var state = this.states[key];
  24202. if (state)
  24203. {
  24204. if (state.preload || state.create || state.update || state.render)
  24205. {
  24206. return true;
  24207. }
  24208. else
  24209. {
  24210. console.warn("Invalid Phaser State object given. Must contain at least a one of the required functions: preload, create, update or render");
  24211. return false;
  24212. }
  24213. }
  24214. else
  24215. {
  24216. console.warn("Phaser.StateManager - No state found with the key: " + key);
  24217. return false;
  24218. }
  24219. },
  24220. /**
  24221. * Links game properties to the State given by the key.
  24222. *
  24223. * @method Phaser.StateManager#link
  24224. * @param {string} key - State key.
  24225. * @protected
  24226. */
  24227. link: function (key) {
  24228. this.states[key].game = this.game;
  24229. this.states[key].add = this.game.add;
  24230. this.states[key].make = this.game.make;
  24231. this.states[key].camera = this.game.camera;
  24232. this.states[key].cache = this.game.cache;
  24233. this.states[key].input = this.game.input;
  24234. this.states[key].load = this.game.load;
  24235. this.states[key].math = this.game.math;
  24236. this.states[key].sound = this.game.sound;
  24237. this.states[key].scale = this.game.scale;
  24238. this.states[key].state = this;
  24239. this.states[key].stage = this.game.stage;
  24240. this.states[key].time = this.game.time;
  24241. this.states[key].tweens = this.game.tweens;
  24242. this.states[key].world = this.game.world;
  24243. this.states[key].particles = this.game.particles;
  24244. this.states[key].rnd = this.game.rnd;
  24245. this.states[key].physics = this.game.physics;
  24246. this.states[key].key = key;
  24247. },
  24248. /**
  24249. * Nulls all State level Phaser properties, including a reference to Game.
  24250. *
  24251. * @method Phaser.StateManager#unlink
  24252. * @param {string} key - State key.
  24253. * @protected
  24254. */
  24255. unlink: function (key) {
  24256. if (this.states[key])
  24257. {
  24258. this.states[key].game = null;
  24259. this.states[key].add = null;
  24260. this.states[key].make = null;
  24261. this.states[key].camera = null;
  24262. this.states[key].cache = null;
  24263. this.states[key].input = null;
  24264. this.states[key].load = null;
  24265. this.states[key].math = null;
  24266. this.states[key].sound = null;
  24267. this.states[key].scale = null;
  24268. this.states[key].state = null;
  24269. this.states[key].stage = null;
  24270. this.states[key].time = null;
  24271. this.states[key].tweens = null;
  24272. this.states[key].world = null;
  24273. this.states[key].particles = null;
  24274. this.states[key].rnd = null;
  24275. this.states[key].physics = null;
  24276. }
  24277. },
  24278. /**
  24279. * Sets the current State. Should not be called directly (use StateManager.start)
  24280. *
  24281. * @method Phaser.StateManager#setCurrentState
  24282. * @param {string} key - State key.
  24283. * @private
  24284. */
  24285. setCurrentState: function (key) {
  24286. this.callbackContext = this.states[key];
  24287. this.link(key);
  24288. // Used when the state is set as being the current active state
  24289. this.onInitCallback = this.states[key]['init'] || this.dummy;
  24290. this.onPreloadCallback = this.states[key]['preload'] || null;
  24291. this.onLoadRenderCallback = this.states[key]['loadRender'] || null;
  24292. this.onLoadUpdateCallback = this.states[key]['loadUpdate'] || null;
  24293. this.onCreateCallback = this.states[key]['create'] || null;
  24294. this.onUpdateCallback = this.states[key]['update'] || null;
  24295. this.onPreRenderCallback = this.states[key]['preRender'] || null;
  24296. this.onRenderCallback = this.states[key]['render'] || null;
  24297. this.onResizeCallback = this.states[key]['resize'] || null;
  24298. this.onPausedCallback = this.states[key]['paused'] || null;
  24299. this.onResumedCallback = this.states[key]['resumed'] || null;
  24300. this.onPauseUpdateCallback = this.states[key]['pauseUpdate'] || null;
  24301. // Used when the state is no longer the current active state
  24302. this.onShutDownCallback = this.states[key]['shutdown'] || this.dummy;
  24303. // Reset the physics system, but not on the first state start
  24304. if (this.current !== '')
  24305. {
  24306. this.game.physics.reset();
  24307. }
  24308. this.current = key;
  24309. this._created = false;
  24310. // At this point key and pendingState should equal each other
  24311. this.onInitCallback.apply(this.callbackContext, this._args);
  24312. // If they no longer do then the init callback hit StateManager.start
  24313. if (key === this._pendingState)
  24314. {
  24315. this._args = [];
  24316. }
  24317. this.game._kickstart = true;
  24318. },
  24319. /**
  24320. * Gets the current State.
  24321. *
  24322. * @method Phaser.StateManager#getCurrentState
  24323. * @return {Phaser.State}
  24324. * @public
  24325. */
  24326. getCurrentState: function() {
  24327. return this.states[this.current];
  24328. },
  24329. /**
  24330. * @method Phaser.StateManager#loadComplete
  24331. * @protected
  24332. */
  24333. loadComplete: function () {
  24334. // Make sure to do load-update one last time before state is set to _created
  24335. if (this._created === false && this.onLoadUpdateCallback)
  24336. {
  24337. this.onLoadUpdateCallback.call(this.callbackContext, this.game);
  24338. }
  24339. if (this._created === false && this.onCreateCallback)
  24340. {
  24341. this._created = true;
  24342. this.onCreateCallback.call(this.callbackContext, this.game);
  24343. }
  24344. else
  24345. {
  24346. this._created = true;
  24347. }
  24348. },
  24349. /**
  24350. * @method Phaser.StateManager#pause
  24351. * @protected
  24352. */
  24353. pause: function () {
  24354. if (this._created && this.onPausedCallback)
  24355. {
  24356. this.onPausedCallback.call(this.callbackContext, this.game);
  24357. }
  24358. },
  24359. /**
  24360. * @method Phaser.StateManager#resume
  24361. * @protected
  24362. */
  24363. resume: function () {
  24364. if (this._created && this.onResumedCallback)
  24365. {
  24366. this.onResumedCallback.call(this.callbackContext, this.game);
  24367. }
  24368. },
  24369. /**
  24370. * @method Phaser.StateManager#update
  24371. * @protected
  24372. */
  24373. update: function () {
  24374. if (this._created)
  24375. {
  24376. if (this.onUpdateCallback)
  24377. {
  24378. this.onUpdateCallback.call(this.callbackContext, this.game);
  24379. }
  24380. }
  24381. else
  24382. {
  24383. if (this.onLoadUpdateCallback)
  24384. {
  24385. this.onLoadUpdateCallback.call(this.callbackContext, this.game);
  24386. }
  24387. }
  24388. },
  24389. /**
  24390. * @method Phaser.StateManager#pauseUpdate
  24391. * @protected
  24392. */
  24393. pauseUpdate: function () {
  24394. if (this._created)
  24395. {
  24396. if (this.onPauseUpdateCallback)
  24397. {
  24398. this.onPauseUpdateCallback.call(this.callbackContext, this.game);
  24399. }
  24400. }
  24401. else
  24402. {
  24403. if (this.onLoadUpdateCallback)
  24404. {
  24405. this.onLoadUpdateCallback.call(this.callbackContext, this.game);
  24406. }
  24407. }
  24408. },
  24409. /**
  24410. * @method Phaser.StateManager#preRender
  24411. * @protected
  24412. * @param {number} elapsedTime - The time elapsed since the last update.
  24413. */
  24414. preRender: function (elapsedTime) {
  24415. if (this._created && this.onPreRenderCallback)
  24416. {
  24417. this.onPreRenderCallback.call(this.callbackContext, this.game, elapsedTime);
  24418. }
  24419. },
  24420. /**
  24421. * @method Phaser.StateManager#resize
  24422. * @protected
  24423. */
  24424. resize: function (width, height) {
  24425. if (this.onResizeCallback)
  24426. {
  24427. this.onResizeCallback.call(this.callbackContext, width, height);
  24428. }
  24429. },
  24430. /**
  24431. * @method Phaser.StateManager#render
  24432. * @protected
  24433. */
  24434. render: function () {
  24435. if (this._created)
  24436. {
  24437. if (this.onRenderCallback)
  24438. {
  24439. if (this.game.renderType === Phaser.CANVAS)
  24440. {
  24441. this.game.context.save();
  24442. this.game.context.setTransform(1, 0, 0, 1, 0, 0);
  24443. this.onRenderCallback.call(this.callbackContext, this.game);
  24444. this.game.context.restore();
  24445. }
  24446. else
  24447. {
  24448. this.onRenderCallback.call(this.callbackContext, this.game);
  24449. }
  24450. }
  24451. }
  24452. else
  24453. {
  24454. if (this.onLoadRenderCallback)
  24455. {
  24456. this.onLoadRenderCallback.call(this.callbackContext, this.game);
  24457. }
  24458. }
  24459. },
  24460. /**
  24461. * Removes all StateManager callback references to the State object, nulls the game reference and clears the States object.
  24462. * You don't recover from this without rebuilding the Phaser instance again.
  24463. * @method Phaser.StateManager#destroy
  24464. */
  24465. destroy: function () {
  24466. this._clearWorld = true;
  24467. this._clearCache = true;
  24468. this.clearCurrentState();
  24469. this.callbackContext = null;
  24470. this.onInitCallback = null;
  24471. this.onShutDownCallback = null;
  24472. this.onPreloadCallback = null;
  24473. this.onLoadRenderCallback = null;
  24474. this.onLoadUpdateCallback = null;
  24475. this.onCreateCallback = null;
  24476. this.onUpdateCallback = null;
  24477. this.onRenderCallback = null;
  24478. this.onPausedCallback = null;
  24479. this.onResumedCallback = null;
  24480. this.onPauseUpdateCallback = null;
  24481. this.game = null;
  24482. this.states = {};
  24483. this._pendingState = null;
  24484. this.current = '';
  24485. }
  24486. };
  24487. Phaser.StateManager.prototype.constructor = Phaser.StateManager;
  24488. /**
  24489. * @name Phaser.StateManager#created
  24490. * @property {boolean} created - True if the current state has had its `create` method run (if it has one, if not this is true by default).
  24491. * @readOnly
  24492. */
  24493. Object.defineProperty(Phaser.StateManager.prototype, "created", {
  24494. get: function () {
  24495. return this._created;
  24496. }
  24497. });
  24498. /**
  24499. * "It's like nailing jelly to a kitten" - Gary Penn
  24500. */
  24501. /**
  24502. * @author Miller Medeiros http://millermedeiros.github.com/js-signals/
  24503. * @author Richard Davey <rich@photonstorm.com>
  24504. * @copyright 2016 Photon Storm Ltd.
  24505. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  24506. */
  24507. /**
  24508. * Signals are what Phaser uses to handle events and event dispatching.
  24509. * You can listen for a Signal by binding a callback / function to it.
  24510. * This is done by using either `Signal.add` or `Signal.addOnce`.
  24511. *
  24512. * For example you can listen for a touch or click event from the Input Manager
  24513. * by using its `onDown` Signal:
  24514. *
  24515. * `game.input.onDown.add(function() { ... });`
  24516. *
  24517. * Rather than inline your function, you can pass a reference:
  24518. *
  24519. * `game.input.onDown.add(clicked, this);`
  24520. * `function clicked () { ... }`
  24521. *
  24522. * In this case the second argument (`this`) is the context in which your function should be called.
  24523. *
  24524. * Now every time the InputManager dispatches the `onDown` signal (or event), your function
  24525. * will be called.
  24526. *
  24527. * Multiple callbacks can be bound to the same signal.
  24528. * They're ordered first by their `priority` arguments and then by the order in which they were added.
  24529. * If a callback calls {@link #halt} or returns `false`, any remaining callbacks are skipped.
  24530. *
  24531. * Very often a Signal will send arguments to your function.
  24532. * This is specific to the Signal itself.
  24533. * If you're unsure then check the documentation, or failing that simply do:
  24534. *
  24535. * `Signal.add(function() { console.log(arguments); })`
  24536. *
  24537. * and it will log all of the arguments your function received from the Signal.
  24538. *
  24539. * Sprites have lots of default signals you can listen to in their Events class, such as:
  24540. *
  24541. * `sprite.events.onKilled`
  24542. *
  24543. * Which is called automatically whenever the Sprite is killed.
  24544. * There are lots of other events, see the Events component for a list.
  24545. *
  24546. * As well as listening to pre-defined Signals you can also create your own:
  24547. *
  24548. * `var mySignal = new Phaser.Signal();`
  24549. *
  24550. * This creates a new Signal. You can bind a callback to it:
  24551. *
  24552. * `mySignal.add(myCallback, this);`
  24553. *
  24554. * and then finally when ready you can dispatch the Signal:
  24555. *
  24556. * `mySignal.dispatch(your arguments);`
  24557. *
  24558. * And your callback will be invoked. See the dispatch method for more details.
  24559. *
  24560. * @class Phaser.Signal
  24561. * @constructor
  24562. */
  24563. Phaser.Signal = function () {};
  24564. Phaser.Signal.prototype = {
  24565. /**
  24566. * @property {?Array.<Phaser.SignalBinding>} _bindings - Internal variable.
  24567. * @private
  24568. */
  24569. _bindings: null,
  24570. /**
  24571. * @property {any} _prevParams - Internal variable.
  24572. * @private
  24573. */
  24574. _prevParams: null,
  24575. /**
  24576. * Memorize the previously dispatched event?
  24577. *
  24578. * If an event has been memorized it is automatically dispatched when a new listener is added with {@link #add} or {@link #addOnce}.
  24579. * Use {@link #forget} to clear any currently memorized event.
  24580. *
  24581. * @property {boolean} memorize
  24582. */
  24583. memorize: false,
  24584. /**
  24585. * @property {boolean} _shouldPropagate
  24586. * @private
  24587. */
  24588. _shouldPropagate: true,
  24589. /**
  24590. * Is the Signal active? Only active signals will broadcast dispatched events.
  24591. *
  24592. * Setting this property during a dispatch will only affect the next dispatch. To stop the propagation of a signal from a listener use {@link #halt}.
  24593. *
  24594. * @property {boolean} active
  24595. * @default
  24596. */
  24597. active: true,
  24598. /**
  24599. * @property {function} _boundDispatch - The bound dispatch function, if any.
  24600. * @private
  24601. */
  24602. _boundDispatch: false,
  24603. /**
  24604. * @method Phaser.Signal#validateListener
  24605. * @param {function} listener - Signal handler function.
  24606. * @param {string} fnName - Function name.
  24607. * @private
  24608. */
  24609. validateListener: function (listener, fnName) {
  24610. if (typeof listener !== 'function')
  24611. {
  24612. throw new Error('Phaser.Signal: listener is a required param of {fn}() and should be a Function.'.replace('{fn}', fnName));
  24613. }
  24614. },
  24615. /**
  24616. * @method Phaser.Signal#_registerListener
  24617. * @private
  24618. * @param {function} listener - Signal handler function.
  24619. * @param {boolean} isOnce - Should the listener only be called once?
  24620. * @param {object} [listenerContext] - The context under which the listener is invoked.
  24621. * @param {number} [priority] - The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added. (default = 0).
  24622. * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
  24623. */
  24624. _registerListener: function (listener, isOnce, listenerContext, priority, args) {
  24625. var prevIndex = this._indexOfListener(listener, listenerContext);
  24626. var binding;
  24627. if (prevIndex !== -1)
  24628. {
  24629. binding = this._bindings[prevIndex];
  24630. if (binding.isOnce() !== isOnce)
  24631. {
  24632. throw new Error('You cannot add' + (isOnce ? '' : 'Once') + '() then add' + (!isOnce ? '' : 'Once') + '() the same listener without removing the relationship first.');
  24633. }
  24634. }
  24635. else
  24636. {
  24637. binding = new Phaser.SignalBinding(this, listener, isOnce, listenerContext, priority, args);
  24638. this._addBinding(binding);
  24639. }
  24640. if (this.memorize && this._prevParams)
  24641. {
  24642. binding.execute(this._prevParams);
  24643. }
  24644. return binding;
  24645. },
  24646. /**
  24647. * @method Phaser.Signal#_addBinding
  24648. * @private
  24649. * @param {Phaser.SignalBinding} binding - An Object representing the binding between the Signal and listener.
  24650. */
  24651. _addBinding: function (binding) {
  24652. if (!this._bindings)
  24653. {
  24654. this._bindings = [];
  24655. }
  24656. // Simplified insertion sort
  24657. var n = this._bindings.length;
  24658. do {
  24659. n--;
  24660. }
  24661. while (this._bindings[n] && binding._priority <= this._bindings[n]._priority);
  24662. this._bindings.splice(n + 1, 0, binding);
  24663. },
  24664. /**
  24665. * @method Phaser.Signal#_indexOfListener
  24666. * @private
  24667. * @param {function} listener - Signal handler function.
  24668. * @param {object} [context=null] - Signal handler function.
  24669. * @return {number} The index of the listener within the private bindings array.
  24670. */
  24671. _indexOfListener: function (listener, context) {
  24672. if (!this._bindings)
  24673. {
  24674. return -1;
  24675. }
  24676. if (context === undefined) { context = null; }
  24677. var n = this._bindings.length;
  24678. var cur;
  24679. while (n--)
  24680. {
  24681. cur = this._bindings[n];
  24682. if (cur._listener === listener && cur.context === context)
  24683. {
  24684. return n;
  24685. }
  24686. }
  24687. return -1;
  24688. },
  24689. /**
  24690. * Check if a specific listener is attached.
  24691. *
  24692. * @method Phaser.Signal#has
  24693. * @param {function} listener - Signal handler function.
  24694. * @param {object} [context] - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  24695. * @return {boolean} If Signal has the specified listener.
  24696. */
  24697. has: function (listener, context) {
  24698. return this._indexOfListener(listener, context) !== -1;
  24699. },
  24700. /**
  24701. * Add an event listener for this signal.
  24702. *
  24703. * An event listener is a callback with a related context and priority.
  24704. *
  24705. * You can optionally provide extra arguments which will be passed to the callback after any internal parameters.
  24706. *
  24707. * For example: `Phaser.Key.onDown` when dispatched will send the Phaser.Key object that caused the signal as the first parameter.
  24708. * Any arguments you've specified after `priority` will be sent as well:
  24709. *
  24710. * `fireButton.onDown.add(shoot, this, 0, 'lazer', 100);`
  24711. *
  24712. * When onDown dispatches it will call the `shoot` callback passing it: `Phaser.Key, 'lazer', 100`.
  24713. *
  24714. * Where the first parameter is the one that Key.onDown dispatches internally and 'lazer',
  24715. * and the value 100 were the custom arguments given in the call to 'add'.
  24716. *
  24717. * If the callback calls {@link #halt} or returns `false`, any remaining callbacks bound to this Signal are skipped.
  24718. *
  24719. * @method Phaser.Signal#add
  24720. * @param {function} listener - The function to call when this Signal is dispatched.
  24721. * @param {object} [listenerContext] - The context under which the listener will be executed (i.e. the object that should represent the `this` variable).
  24722. * @param {number} [priority] - The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added (default = 0)
  24723. * @param {...any} [args=(none)] - Additional arguments to pass to the callback (listener) function. They will be appended after any arguments usually dispatched.
  24724. * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
  24725. */
  24726. add: function (listener, listenerContext, priority) {
  24727. this.validateListener(listener, 'add');
  24728. var args = [];
  24729. if (arguments.length > 3)
  24730. {
  24731. for (var i = 3; i < arguments.length; i++)
  24732. {
  24733. args.push(arguments[i]);
  24734. }
  24735. }
  24736. return this._registerListener(listener, false, listenerContext, priority, args);
  24737. },
  24738. /**
  24739. * Add a one-time listener - the listener is automatically removed after the first execution.
  24740. *
  24741. * If there is as {@link Phaser.Signal#memorize memorized} event then it will be dispatched and
  24742. * the listener will be removed immediately.
  24743. *
  24744. * @method Phaser.Signal#addOnce
  24745. * @param {function} listener - The function to call when this Signal is dispatched.
  24746. * @param {object} [listenerContext] - The context under which the listener will be executed (i.e. the object that should represent the `this` variable).
  24747. * @param {number} [priority] - The priority level of the event listener. Listeners with higher priority will be executed before listeners with lower priority. Listeners with same priority level will be executed at the same order as they were added (default = 0)
  24748. * @param {...any} [args=(none)] - Additional arguments to pass to the callback (listener) function. They will be appended after any arguments usually dispatched.
  24749. * @return {Phaser.SignalBinding} An Object representing the binding between the Signal and listener.
  24750. */
  24751. addOnce: function (listener, listenerContext, priority) {
  24752. this.validateListener(listener, 'addOnce');
  24753. var args = [];
  24754. if (arguments.length > 3)
  24755. {
  24756. for (var i = 3; i < arguments.length; i++)
  24757. {
  24758. args.push(arguments[i]);
  24759. }
  24760. }
  24761. return this._registerListener(listener, true, listenerContext, priority, args);
  24762. },
  24763. /**
  24764. * Remove a single event listener.
  24765. *
  24766. * @method Phaser.Signal#remove
  24767. * @param {function} listener - Handler function that should be removed.
  24768. * @param {object} [context=null] - Execution context (since you can add the same handler multiple times if executing in a different context).
  24769. * @return {function} Listener handler function.
  24770. */
  24771. remove: function (listener, context) {
  24772. this.validateListener(listener, 'remove');
  24773. var i = this._indexOfListener(listener, context);
  24774. if (i !== -1)
  24775. {
  24776. this._bindings[i]._destroy(); //no reason to a Phaser.SignalBinding exist if it isn't attached to a signal
  24777. this._bindings.splice(i, 1);
  24778. }
  24779. return listener;
  24780. },
  24781. /**
  24782. * Remove all event listeners.
  24783. *
  24784. * @method Phaser.Signal#removeAll
  24785. * @param {object} [context=null] - If specified only listeners for the given context will be removed.
  24786. */
  24787. removeAll: function (context) {
  24788. if (context === undefined) { context = null; }
  24789. if (!this._bindings)
  24790. {
  24791. return;
  24792. }
  24793. var n = this._bindings.length;
  24794. while (n--)
  24795. {
  24796. if (context)
  24797. {
  24798. if (this._bindings[n].context === context)
  24799. {
  24800. this._bindings[n]._destroy();
  24801. this._bindings.splice(n, 1);
  24802. }
  24803. }
  24804. else
  24805. {
  24806. this._bindings[n]._destroy();
  24807. }
  24808. }
  24809. if (!context)
  24810. {
  24811. this._bindings.length = 0;
  24812. }
  24813. },
  24814. /**
  24815. * Gets the total number of listeners attached to this Signal.
  24816. *
  24817. * @method Phaser.Signal#getNumListeners
  24818. * @return {integer} Number of listeners attached to the Signal.
  24819. */
  24820. getNumListeners: function () {
  24821. return this._bindings ? this._bindings.length : 0;
  24822. },
  24823. /**
  24824. * Stop propagation of the event, blocking the dispatch to next listener on the queue.
  24825. *
  24826. * This should be called only during event dispatch as calling it before/after dispatch won't affect another broadcast.
  24827. * See {@link #active} to enable/disable the signal entirely.
  24828. *
  24829. * @method Phaser.Signal#halt
  24830. */
  24831. halt: function () {
  24832. this._shouldPropagate = false;
  24833. },
  24834. /**
  24835. * Dispatch / broadcast the event to all listeners.
  24836. *
  24837. * To create an instance-bound dispatch for this Signal, use {@link #boundDispatch}.
  24838. *
  24839. * @method Phaser.Signal#dispatch
  24840. * @param {any} [params] - Parameters that should be passed to each handler.
  24841. */
  24842. dispatch: function () {
  24843. if (!this.active || !this._bindings)
  24844. {
  24845. return;
  24846. }
  24847. var paramsArr = Array.prototype.slice.call(arguments);
  24848. var n = this._bindings.length;
  24849. var bindings;
  24850. if (this.memorize)
  24851. {
  24852. this._prevParams = paramsArr;
  24853. }
  24854. if (!n)
  24855. {
  24856. // Should come after memorize
  24857. return;
  24858. }
  24859. bindings = this._bindings.slice(); //clone array in case add/remove items during dispatch
  24860. this._shouldPropagate = true; //in case `halt` was called before dispatch or during the previous dispatch.
  24861. //execute all callbacks until end of the list or until a callback returns `false` or stops propagation
  24862. //reverse loop since listeners with higher priority will be added at the end of the list
  24863. do {
  24864. n--;
  24865. }
  24866. while (bindings[n] && this._shouldPropagate && bindings[n].execute(paramsArr) !== false);
  24867. },
  24868. /**
  24869. * Forget the currently {@link Phaser.Signal#memorize memorized} event, if any.
  24870. *
  24871. * @method Phaser.Signal#forget
  24872. */
  24873. forget: function() {
  24874. if (this._prevParams)
  24875. {
  24876. this._prevParams = null;
  24877. }
  24878. },
  24879. /**
  24880. * Dispose the signal - no more events can be dispatched.
  24881. *
  24882. * This removes all event listeners and clears references to external objects.
  24883. * Calling methods on a disposed objects results in undefined behavior.
  24884. *
  24885. * @method Phaser.Signal#dispose
  24886. */
  24887. dispose: function () {
  24888. this.removeAll();
  24889. this._bindings = null;
  24890. if (this._prevParams)
  24891. {
  24892. this._prevParams = null;
  24893. }
  24894. },
  24895. /**
  24896. * A string representation of the object.
  24897. *
  24898. * @method Phaser.Signal#toString
  24899. * @return {string} String representation of the object.
  24900. */
  24901. toString: function () {
  24902. return '[Phaser.Signal active:'+ this.active +' numListeners:'+ this.getNumListeners() +']';
  24903. }
  24904. };
  24905. /**
  24906. * Create a `dispatch` function that maintains a binding to the original Signal context.
  24907. *
  24908. * Use the resulting value if the dispatch function needs to be passed somewhere
  24909. * or called independently of the Signal object.
  24910. *
  24911. * @memberof Phaser.Signal
  24912. * @property {function} boundDispatch
  24913. */
  24914. Object.defineProperty(Phaser.Signal.prototype, "boundDispatch", {
  24915. get: function () {
  24916. var _this = this;
  24917. return this._boundDispatch || (this._boundDispatch = function () {
  24918. return _this.dispatch.apply(_this, arguments);
  24919. });
  24920. }
  24921. });
  24922. Phaser.Signal.prototype.constructor = Phaser.Signal;
  24923. /**
  24924. * @author Miller Medeiros http://millermedeiros.github.com/js-signals/
  24925. * @author Richard Davey <rich@photonstorm.com>
  24926. * @copyright 2016 Photon Storm Ltd.
  24927. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  24928. */
  24929. /**
  24930. * Object that represents a binding between a Signal and a listener function.
  24931. * This is an internal constructor and shouldn't be created directly.
  24932. * Inspired by Joa Ebert AS3 SignalBinding and Robert Penner's Slot classes.
  24933. *
  24934. * @class Phaser.SignalBinding
  24935. * @constructor
  24936. * @param {Phaser.Signal} signal - Reference to Signal object that listener is currently bound to.
  24937. * @param {function} listener - Handler function bound to the signal.
  24938. * @param {boolean} isOnce - If binding should be executed just once.
  24939. * @param {object} [listenerContext=null] - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  24940. * @param {number} [priority] - The priority level of the event listener. (default = 0).
  24941. * @param {...any} [args=(none)] - Additional arguments to pass to the callback (listener) function. They will be appended after any arguments usually dispatched.
  24942. */
  24943. Phaser.SignalBinding = function (signal, listener, isOnce, listenerContext, priority, args) {
  24944. /**
  24945. * @property {Phaser.Game} _listener - Handler function bound to the signal.
  24946. * @private
  24947. */
  24948. this._listener = listener;
  24949. if (isOnce)
  24950. {
  24951. this._isOnce = true;
  24952. }
  24953. if (listenerContext != null) /* not null/undefined */
  24954. {
  24955. this.context = listenerContext;
  24956. }
  24957. /**
  24958. * @property {Phaser.Signal} _signal - Reference to Signal object that listener is currently bound to.
  24959. * @private
  24960. */
  24961. this._signal = signal;
  24962. if (priority)
  24963. {
  24964. this._priority = priority;
  24965. }
  24966. if (args && args.length)
  24967. {
  24968. this._args = args;
  24969. }
  24970. };
  24971. Phaser.SignalBinding.prototype = {
  24972. /**
  24973. * @property {?object} context - Context on which listener will be executed (object that should represent the `this` variable inside listener function).
  24974. */
  24975. context: null,
  24976. /**
  24977. * @property {boolean} _isOnce - If binding should be executed just once.
  24978. * @private
  24979. */
  24980. _isOnce: false,
  24981. /**
  24982. * @property {number} _priority - Listener priority.
  24983. * @private
  24984. */
  24985. _priority: 0,
  24986. /**
  24987. * @property {array} _args - Listener arguments.
  24988. * @private
  24989. */
  24990. _args: null,
  24991. /**
  24992. * @property {number} callCount - The number of times the handler function has been called.
  24993. */
  24994. callCount: 0,
  24995. /**
  24996. * If binding is active and should be executed.
  24997. * @property {boolean} active
  24998. * @default
  24999. */
  25000. active: true,
  25001. /**
  25002. * Default parameters passed to listener during `Signal.dispatch` and `SignalBinding.execute` (curried parameters).
  25003. * @property {array|null} params
  25004. * @default
  25005. */
  25006. params: null,
  25007. /**
  25008. * Call listener passing arbitrary parameters.
  25009. * If binding was added using `Signal.addOnce()` it will be automatically removed from signal dispatch queue, this method is used internally for the signal dispatch.
  25010. * @method Phaser.SignalBinding#execute
  25011. * @param {any[]} [paramsArr] - Array of parameters that should be passed to the listener.
  25012. * @return {any} Value returned by the listener.
  25013. */
  25014. execute: function(paramsArr) {
  25015. var handlerReturn, params;
  25016. if (this.active && !!this._listener)
  25017. {
  25018. params = this.params ? this.params.concat(paramsArr) : paramsArr;
  25019. if (this._args)
  25020. {
  25021. params = params.concat(this._args);
  25022. }
  25023. handlerReturn = this._listener.apply(this.context, params);
  25024. this.callCount++;
  25025. if (this._isOnce)
  25026. {
  25027. this.detach();
  25028. }
  25029. }
  25030. return handlerReturn;
  25031. },
  25032. /**
  25033. * Detach binding from signal.
  25034. * alias to: @see mySignal.remove(myBinding.getListener());
  25035. * @method Phaser.SignalBinding#detach
  25036. * @return {function|null} Handler function bound to the signal or `null` if binding was previously detached.
  25037. */
  25038. detach: function () {
  25039. return this.isBound() ? this._signal.remove(this._listener, this.context) : null;
  25040. },
  25041. /**
  25042. * @method Phaser.SignalBinding#isBound
  25043. * @return {boolean} True if binding is still bound to the signal and has a listener.
  25044. */
  25045. isBound: function () {
  25046. return (!!this._signal && !!this._listener);
  25047. },
  25048. /**
  25049. * @method Phaser.SignalBinding#isOnce
  25050. * @return {boolean} If SignalBinding will only be executed once.
  25051. */
  25052. isOnce: function () {
  25053. return this._isOnce;
  25054. },
  25055. /**
  25056. * @method Phaser.SignalBinding#getListener
  25057. * @return {function} Handler function bound to the signal.
  25058. */
  25059. getListener: function () {
  25060. return this._listener;
  25061. },
  25062. /**
  25063. * @method Phaser.SignalBinding#getSignal
  25064. * @return {Phaser.Signal} Signal that listener is currently bound to.
  25065. */
  25066. getSignal: function () {
  25067. return this._signal;
  25068. },
  25069. /**
  25070. * Delete instance properties
  25071. * @method Phaser.SignalBinding#_destroy
  25072. * @private
  25073. */
  25074. _destroy: function () {
  25075. delete this._signal;
  25076. delete this._listener;
  25077. delete this.context;
  25078. },
  25079. /**
  25080. * @method Phaser.SignalBinding#toString
  25081. * @return {string} String representation of the object.
  25082. */
  25083. toString: function () {
  25084. return '[Phaser.SignalBinding isOnce:' + this._isOnce +', isBound:'+ this.isBound() +', active:' + this.active + ']';
  25085. }
  25086. };
  25087. Phaser.SignalBinding.prototype.constructor = Phaser.SignalBinding;
  25088. /**
  25089. * @author Richard Davey <rich@photonstorm.com>
  25090. * @author Mat Groves (@Doormat23)
  25091. * @copyright 2016 Photon Storm Ltd.
  25092. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  25093. */
  25094. /**
  25095. * This is a base Filter class to use for any Phaser filter development.
  25096. * If you want to make a custom filter, this should be your base class.
  25097. *
  25098. * The default uniforms, types and values for all Filters are:
  25099. *
  25100. * ```javascript
  25101. * resolution: { type: '2f', value: { x: 256, y: 256 }}
  25102. * time: { type: '1f', value: 0 }
  25103. * mouse: { type: '2f', value: { x: 0.0, y: 0.0 } }
  25104. * date: { type: '4fv', value: [ d.getFullYear(), d.getMonth(), d.getDate(), d.getHours() *60 * 60 + d.getMinutes() * 60 + d.getSeconds() ] }
  25105. * sampleRate: { type: '1f', value: 44100.0 }
  25106. * iChannel0: { type: 'sampler2D', value: null, textureData: { repeat: true } }
  25107. * iChannel1: { type: 'sampler2D', value: null, textureData: { repeat: true } }
  25108. * iChannel2: { type: 'sampler2D', value: null, textureData: { repeat: true } }
  25109. * iChannel3: { type: 'sampler2D', value: null, textureData: { repeat: true } }
  25110. * ```
  25111. *
  25112. * The vast majority of filters (including all of those that ship with Phaser) use fragment shaders, and
  25113. * therefore only work in WebGL and are not supported by Canvas at all.
  25114. *
  25115. * @class Phaser.Filter
  25116. * @constructor
  25117. * @param {Phaser.Game} game - A reference to the currently running game.
  25118. * @param {object} [uniforms] - Uniform mappings object. The uniforms are added on the default uniforms, or replace them if the keys are the same.
  25119. * @param {Array|string} [fragmentSrc] - The fragment shader code. Either an array, one element per line of code, or a string.
  25120. */
  25121. Phaser.Filter = function (game, uniforms, fragmentSrc) {
  25122. /**
  25123. * @property {Phaser.Game} game - A reference to the currently running game.
  25124. */
  25125. this.game = game;
  25126. /**
  25127. * @property {number} type - The const type of this object, either Phaser.WEBGL_FILTER or Phaser.CANVAS_FILTER.
  25128. * @default
  25129. */
  25130. this.type = Phaser.WEBGL_FILTER;
  25131. /**
  25132. * An array of passes - some filters contain a few steps this array simply stores the steps in a linear fashion.
  25133. * For example the blur filter has two passes blurX and blurY.
  25134. * @property {array} passes - An array of filter objects.
  25135. * @private
  25136. */
  25137. this.passes = [ this ];
  25138. /**
  25139. * @property {array} shaders - Array an array of shaders.
  25140. * @private
  25141. */
  25142. this.shaders = [];
  25143. /**
  25144. * @property {boolean} dirty - Internal PIXI var.
  25145. * @default
  25146. */
  25147. this.dirty = true;
  25148. /**
  25149. * @property {number} padding - Internal PIXI var.
  25150. * @default
  25151. */
  25152. this.padding = 0;
  25153. /**
  25154. * @property {Phaser.Point} prevPoint - The previous position of the pointer (we don't update the uniform if the same)
  25155. */
  25156. this.prevPoint = new Phaser.Point();
  25157. /*
  25158. * The supported types are: 1f, 1fv, 1i, 2f, 2fv, 2i, 2iv, 3f, 3fv, 3i, 3iv, 4f, 4fv, 4i, 4iv, mat2, mat3, mat4 and sampler2D.
  25159. */
  25160. var d = new Date();
  25161. /**
  25162. * @property {object} uniforms - Default uniform mappings. Compatible with ShaderToy and GLSLSandbox.
  25163. */
  25164. this.uniforms = {
  25165. resolution: { type: '2f', value: { x: 256, y: 256 }},
  25166. time: { type: '1f', value: 0 },
  25167. mouse: { type: '2f', value: { x: 0.0, y: 0.0 } },
  25168. date: { type: '4fv', value: [ d.getFullYear(), d.getMonth(), d.getDate(), d.getHours() *60 * 60 + d.getMinutes() * 60 + d.getSeconds() ] },
  25169. sampleRate: { type: '1f', value: 44100.0 },
  25170. iChannel0: { type: 'sampler2D', value: null, textureData: { repeat: true } },
  25171. iChannel1: { type: 'sampler2D', value: null, textureData: { repeat: true } },
  25172. iChannel2: { type: 'sampler2D', value: null, textureData: { repeat: true } },
  25173. iChannel3: { type: 'sampler2D', value: null, textureData: { repeat: true } }
  25174. };
  25175. // Copy over / replace any passed in the constructor
  25176. if (uniforms)
  25177. {
  25178. for (var key in uniforms)
  25179. {
  25180. this.uniforms[key] = uniforms[key];
  25181. }
  25182. }
  25183. // If fragmentSrc is a string, split it based on new-lines into an array
  25184. if (typeof fragmentSrc === 'string')
  25185. {
  25186. fragmentSrc = fragmentSrc.split('\n');
  25187. }
  25188. /**
  25189. * @property {array|string} fragmentSrc - The fragment shader code.
  25190. */
  25191. this.fragmentSrc = fragmentSrc || [];
  25192. };
  25193. Phaser.Filter.prototype = {
  25194. /**
  25195. * This should be over-ridden. Will receive a variable number of arguments.
  25196. *
  25197. * @method Phaser.Filter#init
  25198. */
  25199. init: function () {
  25200. // This should be over-ridden. Will receive a variable number of arguments.
  25201. },
  25202. /**
  25203. * Set the resolution uniforms on the filter.
  25204. *
  25205. * @method Phaser.Filter#setResolution
  25206. * @param {number} width - The width of the display.
  25207. * @param {number} height - The height of the display.
  25208. */
  25209. setResolution: function (width, height) {
  25210. this.uniforms.resolution.value.x = width;
  25211. this.uniforms.resolution.value.y = height;
  25212. },
  25213. /**
  25214. * Updates the filter.
  25215. *
  25216. * @method Phaser.Filter#update
  25217. * @param {Phaser.Pointer} [pointer] - A Pointer object to use for the filter. The coordinates are mapped to the mouse uniform.
  25218. */
  25219. update: function (pointer) {
  25220. if (pointer)
  25221. {
  25222. var x = pointer.x / this.game.width;
  25223. var y = 1 - pointer.y / this.game.height;
  25224. if (x !== this.prevPoint.x || y !== this.prevPoint.y)
  25225. {
  25226. this.uniforms.mouse.value.x = x.toFixed(2);
  25227. this.uniforms.mouse.value.y = y.toFixed(2);
  25228. this.prevPoint.set(x, y);
  25229. }
  25230. }
  25231. this.uniforms.time.value = this.game.time.totalElapsedSeconds();
  25232. },
  25233. /**
  25234. * Creates a new Phaser.Image object using a blank texture and assigns
  25235. * this Filter to it. The image is then added to the world.
  25236. *
  25237. * If you don't provide width and height values then Filter.width and Filter.height are used.
  25238. *
  25239. * If you do provide width and height values then this filter will be resized to match those
  25240. * values.
  25241. *
  25242. * @method Phaser.Filter#addToWorld
  25243. * @param {number} [x=0] - The x coordinate to place the Image at.
  25244. * @param {number} [y=0] - The y coordinate to place the Image at.
  25245. * @param {number} [width] - The width of the Image. If not specified (or null) it will use Filter.width. If specified Filter.width will be set to this value.
  25246. * @param {number} [height] - The height of the Image. If not specified (or null) it will use Filter.height. If specified Filter.height will be set to this value.
  25247. * @param {number} [anchorX=0] - Set the x anchor point of the Image. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  25248. * @param {number} [anchorY=0] - Set the y anchor point of the Image. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  25249. * @return {Phaser.Image} The newly added Image object.
  25250. */
  25251. addToWorld: function (x, y, width, height, anchorX, anchorY) {
  25252. if (anchorX === undefined) { anchorX = 0; }
  25253. if (anchorY === undefined) { anchorY = 0; }
  25254. if (width !== undefined && width !== null)
  25255. {
  25256. this.width = width;
  25257. }
  25258. else
  25259. {
  25260. width = this.width;
  25261. }
  25262. if (height !== undefined && height !== null)
  25263. {
  25264. this.height = height;
  25265. }
  25266. else
  25267. {
  25268. height = this.height;
  25269. }
  25270. var image = this.game.add.image(x, y, Phaser.Cache.DEFAULT);
  25271. image.width = width;
  25272. image.height = height;
  25273. image.anchor.set(anchorX, anchorY);
  25274. image.filters = [ this ];
  25275. return image;
  25276. },
  25277. /**
  25278. * Syncs the uniforms between the class object and the shaders.
  25279. *
  25280. * @method Phaser.Filter#syncUniforms
  25281. */
  25282. syncUniforms: function () {
  25283. for (var i = 0; i < this.shaders.length; i++)
  25284. {
  25285. this.shaders[i].dirty = true;
  25286. }
  25287. },
  25288. /**
  25289. * Clear down this Filter and null out references to game.
  25290. *
  25291. * @method Phaser.Filter#destroy
  25292. */
  25293. destroy: function () {
  25294. this.passes.length = 0;
  25295. this.shaders.length = 0;
  25296. this.fragmentSrc.length = 0;
  25297. this.game = null;
  25298. this.uniforms = null;
  25299. this.prevPoint = null;
  25300. }
  25301. };
  25302. Phaser.Filter.prototype.constructor = Phaser.Filter;
  25303. /**
  25304. * @name Phaser.Filter#width
  25305. * @property {number} width - The width (resolution uniform)
  25306. */
  25307. Object.defineProperty(Phaser.Filter.prototype, 'width', {
  25308. get: function () {
  25309. return this.uniforms.resolution.value.x;
  25310. },
  25311. set: function (value) {
  25312. this.uniforms.resolution.value.x = value;
  25313. }
  25314. });
  25315. /**
  25316. * @name Phaser.Filter#height
  25317. * @property {number} height - The height (resolution uniform)
  25318. */
  25319. Object.defineProperty(Phaser.Filter.prototype, 'height', {
  25320. get: function () {
  25321. return this.uniforms.resolution.value.y;
  25322. },
  25323. set: function (value) {
  25324. this.uniforms.resolution.value.y = value;
  25325. }
  25326. });
  25327. /**
  25328. * @author Richard Davey <rich@photonstorm.com>
  25329. * @copyright 2016 Photon Storm Ltd.
  25330. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  25331. */
  25332. /**
  25333. * This is a base Plugin template to use for any Phaser plugin development.
  25334. *
  25335. * ##### Callbacks
  25336. *
  25337. * add | active | visible | remove
  25338. * -----|-------------|-------------|--------
  25339. * init | | |
  25340. * | preUpdate* | |
  25341. * | update* | render* |
  25342. * | postUpdate* | postRender* |
  25343. * | | | destroy
  25344. *
  25345. * Update and render calls are repeated (*).
  25346. *
  25347. * @class Phaser.Plugin
  25348. * @constructor
  25349. * @param {Phaser.Game} game - A reference to the currently running game.
  25350. * @param {any} parent - The object that owns this plugin, usually Phaser.PluginManager.
  25351. */
  25352. Phaser.Plugin = function (game, parent) {
  25353. if (parent === undefined) { parent = null; }
  25354. /**
  25355. * @property {Phaser.Game} game - A reference to the currently running game.
  25356. */
  25357. this.game = game;
  25358. /**
  25359. * @property {any} parent - The parent of this plugin. If added to the PluginManager the parent will be set to that, otherwise it will be null.
  25360. */
  25361. this.parent = parent;
  25362. /**
  25363. * @property {boolean} active - A Plugin with active=true has its preUpdate and update methods called by the parent, otherwise they are skipped.
  25364. * @default
  25365. */
  25366. this.active = false;
  25367. /**
  25368. * @property {boolean} visible - A Plugin with visible=true has its render and postRender methods called by the parent, otherwise they are skipped.
  25369. * @default
  25370. */
  25371. this.visible = false;
  25372. /**
  25373. * @property {boolean} hasPreUpdate - A flag to indicate if this plugin has a preUpdate method.
  25374. * @default
  25375. */
  25376. this.hasPreUpdate = false;
  25377. /**
  25378. * @property {boolean} hasUpdate - A flag to indicate if this plugin has an update method.
  25379. * @default
  25380. */
  25381. this.hasUpdate = false;
  25382. /**
  25383. * @property {boolean} hasPostUpdate - A flag to indicate if this plugin has a postUpdate method.
  25384. * @default
  25385. */
  25386. this.hasPostUpdate = false;
  25387. /**
  25388. * @property {boolean} hasRender - A flag to indicate if this plugin has a render method.
  25389. * @default
  25390. */
  25391. this.hasRender = false;
  25392. /**
  25393. * @property {boolean} hasPostRender - A flag to indicate if this plugin has a postRender method.
  25394. * @default
  25395. */
  25396. this.hasPostRender = false;
  25397. };
  25398. Phaser.Plugin.prototype = {
  25399. /**
  25400. * Pre-update is called at the very start of the update cycle, before any other subsystems have been updated (including Physics).
  25401. * It is only called if active is set to true.
  25402. * @method Phaser.Plugin#preUpdate
  25403. */
  25404. preUpdate: function () {
  25405. },
  25406. /**
  25407. * Update is called after all the core subsystems (Input, Tweens, Sound, etc) and the State have updated, but before the render.
  25408. * It is only called if active is set to true.
  25409. * @method Phaser.Plugin#update
  25410. */
  25411. update: function () {
  25412. },
  25413. /**
  25414. * Render is called right after the Game Renderer completes, but before the State.render.
  25415. * It is only called if visible is set to true.
  25416. * @method Phaser.Plugin#render
  25417. */
  25418. render: function () {
  25419. },
  25420. /**
  25421. * Post-render is called after the Game Renderer and State.render have run.
  25422. * It is only called if visible is set to true.
  25423. * @method Phaser.Plugin#postRender
  25424. */
  25425. postRender: function () {
  25426. },
  25427. /**
  25428. * Clear down this Plugin and null out references
  25429. * @method Phaser.Plugin#destroy
  25430. */
  25431. destroy: function () {
  25432. this.game = null;
  25433. this.parent = null;
  25434. this.active = false;
  25435. this.visible = false;
  25436. }
  25437. };
  25438. Phaser.Plugin.prototype.constructor = Phaser.Plugin;
  25439. /* jshint newcap: false */
  25440. /**
  25441. * @author Richard Davey <rich@photonstorm.com>
  25442. * @copyright 2016 Photon Storm Ltd.
  25443. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  25444. */
  25445. /**
  25446. * The Plugin Manager is responsible for the loading, running and unloading of Phaser Plugins.
  25447. *
  25448. * @class Phaser.PluginManager
  25449. * @constructor
  25450. * @param {Phaser.Game} game - A reference to the currently running game.
  25451. */
  25452. Phaser.PluginManager = function(game) {
  25453. /**
  25454. * @property {Phaser.Game} game - A reference to the currently running game.
  25455. */
  25456. this.game = game;
  25457. /**
  25458. * @property {Phaser.Plugin[]} plugins - An array of all the plugins being managed by this PluginManager.
  25459. */
  25460. this.plugins = [];
  25461. /**
  25462. * @property {number} _len - Internal cache var.
  25463. * @private
  25464. */
  25465. this._len = 0;
  25466. /**
  25467. * @property {number} _i - Internal cache var.
  25468. * @private
  25469. */
  25470. this._i = 0;
  25471. };
  25472. Phaser.PluginManager.prototype = {
  25473. /**
  25474. * Add a new Plugin into the PluginManager.
  25475. * The Plugin must have 2 properties: game and parent. Plugin.game is set to the game reference the PluginManager uses, and parent is set to the PluginManager.
  25476. *
  25477. * @method Phaser.PluginManager#add
  25478. * @param {object|Phaser.Plugin} plugin - The Plugin to add into the PluginManager. This can be a function or an existing object.
  25479. * @param {...*} parameter - Additional arguments that will be passed to the Plugin.init method.
  25480. * @return {Phaser.Plugin} The Plugin that was added to the manager.
  25481. */
  25482. add: function (plugin) {
  25483. var args = Array.prototype.slice.call(arguments, 1);
  25484. var result = false;
  25485. // Prototype?
  25486. if (typeof plugin === 'function')
  25487. {
  25488. plugin = new plugin(this.game, this);
  25489. }
  25490. else
  25491. {
  25492. plugin.game = this.game;
  25493. plugin.parent = this;
  25494. }
  25495. // Check for methods now to avoid having to do this every loop
  25496. if (typeof plugin['preUpdate'] === 'function')
  25497. {
  25498. plugin.hasPreUpdate = true;
  25499. result = true;
  25500. }
  25501. if (typeof plugin['update'] === 'function')
  25502. {
  25503. plugin.hasUpdate = true;
  25504. result = true;
  25505. }
  25506. if (typeof plugin['postUpdate'] === 'function')
  25507. {
  25508. plugin.hasPostUpdate = true;
  25509. result = true;
  25510. }
  25511. if (typeof plugin['render'] === 'function')
  25512. {
  25513. plugin.hasRender = true;
  25514. result = true;
  25515. }
  25516. if (typeof plugin['postRender'] === 'function')
  25517. {
  25518. plugin.hasPostRender = true;
  25519. result = true;
  25520. }
  25521. // The plugin must have at least one of the above functions to be added to the PluginManager.
  25522. if (result)
  25523. {
  25524. if (plugin.hasPreUpdate || plugin.hasUpdate || plugin.hasPostUpdate)
  25525. {
  25526. plugin.active = true;
  25527. }
  25528. if (plugin.hasRender || plugin.hasPostRender)
  25529. {
  25530. plugin.visible = true;
  25531. }
  25532. this._len = this.plugins.push(plugin);
  25533. // Allows plugins to run potentially destructive code outside of the constructor, and only if being added to the PluginManager
  25534. if (typeof plugin['init'] === 'function')
  25535. {
  25536. plugin.init.apply(plugin, args);
  25537. }
  25538. return plugin;
  25539. }
  25540. else
  25541. {
  25542. return null;
  25543. }
  25544. },
  25545. /**
  25546. * Remove a Plugin from the PluginManager. It calls Plugin.destroy on the plugin before removing it from the manager.
  25547. *
  25548. * @method Phaser.PluginManager#remove
  25549. * @param {Phaser.Plugin} plugin - The plugin to be removed.
  25550. * @param {boolean} [destroy=true] - Call destroy on the plugin that is removed?
  25551. */
  25552. remove: function (plugin, destroy) {
  25553. if (destroy === undefined) { destroy = true; }
  25554. this._i = this._len;
  25555. while (this._i--)
  25556. {
  25557. if (this.plugins[this._i] === plugin)
  25558. {
  25559. if (destroy)
  25560. {
  25561. plugin.destroy();
  25562. }
  25563. this.plugins.splice(this._i, 1);
  25564. this._len--;
  25565. return;
  25566. }
  25567. }
  25568. },
  25569. /**
  25570. * Remove all Plugins from the PluginManager. It calls Plugin.destroy on every plugin before removing it from the manager.
  25571. *
  25572. * @method Phaser.PluginManager#removeAll
  25573. */
  25574. removeAll: function() {
  25575. this._i = this._len;
  25576. while (this._i--)
  25577. {
  25578. this.plugins[this._i].destroy();
  25579. }
  25580. this.plugins.length = 0;
  25581. this._len = 0;
  25582. },
  25583. /**
  25584. * Pre-update is called at the very start of the update cycle, before any other subsystems have been updated (including Physics).
  25585. * It only calls plugins who have active=true.
  25586. *
  25587. * @method Phaser.PluginManager#preUpdate
  25588. */
  25589. preUpdate: function () {
  25590. this._i = this._len;
  25591. while (this._i--)
  25592. {
  25593. if (this.plugins[this._i].active && this.plugins[this._i].hasPreUpdate)
  25594. {
  25595. this.plugins[this._i].preUpdate();
  25596. }
  25597. }
  25598. },
  25599. /**
  25600. * Update is called after all the core subsystems (Input, Tweens, Sound, etc) and the State have updated, but before the render.
  25601. * It only calls plugins who have active=true.
  25602. *
  25603. * @method Phaser.PluginManager#update
  25604. */
  25605. update: function () {
  25606. this._i = this._len;
  25607. while (this._i--)
  25608. {
  25609. if (this.plugins[this._i].active && this.plugins[this._i].hasUpdate)
  25610. {
  25611. this.plugins[this._i].update();
  25612. }
  25613. }
  25614. },
  25615. /**
  25616. * PostUpdate is the last thing to be called before the world render.
  25617. * In particular, it is called after the world postUpdate, which means the camera has been adjusted.
  25618. * It only calls plugins who have active=true.
  25619. *
  25620. * @method Phaser.PluginManager#postUpdate
  25621. */
  25622. postUpdate: function () {
  25623. this._i = this._len;
  25624. while (this._i--)
  25625. {
  25626. if (this.plugins[this._i].active && this.plugins[this._i].hasPostUpdate)
  25627. {
  25628. this.plugins[this._i].postUpdate();
  25629. }
  25630. }
  25631. },
  25632. /**
  25633. * Render is called right after the Game Renderer completes, but before the State.render.
  25634. * It only calls plugins who have visible=true.
  25635. *
  25636. * @method Phaser.PluginManager#render
  25637. */
  25638. render: function () {
  25639. this._i = this._len;
  25640. while (this._i--)
  25641. {
  25642. if (this.plugins[this._i].visible && this.plugins[this._i].hasRender)
  25643. {
  25644. this.plugins[this._i].render();
  25645. }
  25646. }
  25647. },
  25648. /**
  25649. * Post-render is called after the Game Renderer and State.render have run.
  25650. * It only calls plugins who have visible=true.
  25651. *
  25652. * @method Phaser.PluginManager#postRender
  25653. */
  25654. postRender: function () {
  25655. this._i = this._len;
  25656. while (this._i--)
  25657. {
  25658. if (this.plugins[this._i].visible && this.plugins[this._i].hasPostRender)
  25659. {
  25660. this.plugins[this._i].postRender();
  25661. }
  25662. }
  25663. },
  25664. /**
  25665. * Clear down this PluginManager, calls destroy on every plugin and nulls out references.
  25666. *
  25667. * @method Phaser.PluginManager#destroy
  25668. */
  25669. destroy: function () {
  25670. this.removeAll();
  25671. this.game = null;
  25672. }
  25673. };
  25674. Phaser.PluginManager.prototype.constructor = Phaser.PluginManager;
  25675. /**
  25676. * @author Richard Davey <rich@photonstorm.com>
  25677. * @copyright 2016 Photon Storm Ltd.
  25678. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  25679. */
  25680. /**
  25681. * The Stage controls root level display objects upon which everything is displayed.
  25682. * It also handles browser visibility handling and the pausing due to loss of focus.
  25683. *
  25684. * @class Phaser.Stage
  25685. * @extends PIXI.DisplayObjectContainer
  25686. * @constructor
  25687. * @param {Phaser.Game} game - Game reference to the currently running game.
  25688. */
  25689. Phaser.Stage = function (game) {
  25690. /**
  25691. * @property {Phaser.Game} game - A reference to the currently running Game.
  25692. */
  25693. this.game = game;
  25694. PIXI.DisplayObjectContainer.call(this);
  25695. /**
  25696. * @property {string} name - The name of this object.
  25697. * @default
  25698. */
  25699. this.name = '_stage_root';
  25700. /**
  25701. * By default if the browser tab loses focus the game will pause.
  25702. * You can stop that behavior by setting this property to true.
  25703. * Note that the browser can still elect to pause your game if it wishes to do so,
  25704. * for example swapping to another browser tab. This will cause the RAF callback to halt,
  25705. * effectively pausing your game, even though no in-game pause event is triggered if you enable this property.
  25706. * @property {boolean} disableVisibilityChange
  25707. * @default
  25708. */
  25709. this.disableVisibilityChange = false;
  25710. /**
  25711. * @property {boolean} exists - If exists is true the Stage and all children are updated, otherwise it is skipped.
  25712. * @default
  25713. */
  25714. this.exists = true;
  25715. /**
  25716. * @property {Phaser.Matrix} worldTransform - Current transform of the object based on world (parent) factors
  25717. * @private
  25718. * @readOnly
  25719. */
  25720. this.worldTransform = new Phaser.Matrix();
  25721. /**
  25722. * @property {Phaser.Stage} stage - The stage reference (the Stage is its own stage)
  25723. * @private
  25724. * @readOnly
  25725. */
  25726. this.stage = this;
  25727. /**
  25728. * @property {number} currentRenderOrderID - Reset each frame, keeps a count of the total number of objects updated.
  25729. */
  25730. this.currentRenderOrderID = 0;
  25731. /**
  25732. * @property {string} hiddenVar - The page visibility API event name.
  25733. * @private
  25734. */
  25735. this._hiddenVar = 'hidden';
  25736. /**
  25737. * @property {function} _onChange - The blur/focus event handler.
  25738. * @private
  25739. */
  25740. this._onChange = null;
  25741. /**
  25742. * @property {number} _bgColor - Stage background color object. Populated by setBackgroundColor.
  25743. * @private
  25744. */
  25745. this._bgColor = { r: 0, g: 0, b: 0, a: 0, color: 0, rgba: '#000000' };
  25746. if (!this.game.transparent)
  25747. {
  25748. // transparent = 0,0,0,0 - otherwise r,g,b,1
  25749. this._bgColor.a = 1;
  25750. }
  25751. if (game.config)
  25752. {
  25753. this.parseConfig(game.config);
  25754. }
  25755. };
  25756. Phaser.Stage.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  25757. Phaser.Stage.prototype.constructor = Phaser.Stage;
  25758. /**
  25759. * Parses a Game configuration object.
  25760. *
  25761. * @method Phaser.Stage#parseConfig
  25762. * @protected
  25763. * @param {object} config -The configuration object to parse.
  25764. */
  25765. Phaser.Stage.prototype.parseConfig = function (config) {
  25766. if (config['disableVisibilityChange'])
  25767. {
  25768. this.disableVisibilityChange = config['disableVisibilityChange'];
  25769. }
  25770. if (config['backgroundColor'])
  25771. {
  25772. this.setBackgroundColor(config['backgroundColor']);
  25773. }
  25774. };
  25775. /**
  25776. * Initialises the stage and adds the event listeners.
  25777. * @method Phaser.Stage#boot
  25778. * @private
  25779. */
  25780. Phaser.Stage.prototype.boot = function () {
  25781. Phaser.DOM.getOffset(this.game.canvas, this.offset);
  25782. Phaser.Canvas.setUserSelect(this.game.canvas, 'none');
  25783. Phaser.Canvas.setTouchAction(this.game.canvas, 'none');
  25784. this.checkVisibility();
  25785. };
  25786. /**
  25787. * This is called automatically after the plugins preUpdate and before the State.update.
  25788. * Most objects have preUpdate methods and it's where initial movement and positioning is done.
  25789. *
  25790. * @method Phaser.Stage#preUpdate
  25791. */
  25792. Phaser.Stage.prototype.preUpdate = function () {
  25793. this.currentRenderOrderID = 0;
  25794. // This can't loop in reverse, we need the renderOrderID to be in sequence
  25795. var i = 0;
  25796. while (i < this.children.length)
  25797. {
  25798. var child = this.children[i];
  25799. child.preUpdate();
  25800. if (this === child.parent)
  25801. {
  25802. i++;
  25803. }
  25804. }
  25805. };
  25806. /**
  25807. * This is called automatically after the State.update, but before particles or plugins update.
  25808. *
  25809. * @method Phaser.Stage#update
  25810. */
  25811. Phaser.Stage.prototype.update = function () {
  25812. // Goes in reverse, because it's highly likely the child will destroy itself in `update`
  25813. var i = this.children.length;
  25814. while (i--)
  25815. {
  25816. this.children[i].update();
  25817. }
  25818. };
  25819. /**
  25820. * This is called automatically before the renderer runs and after the plugins have updated.
  25821. * In postUpdate this is where all the final physics calculations and object positioning happens.
  25822. * The objects are processed in the order of the display list.
  25823. *
  25824. * @method Phaser.Stage#postUpdate
  25825. */
  25826. Phaser.Stage.prototype.postUpdate = function () {
  25827. // Apply the camera shake, fade, bounds, etc
  25828. this.game.camera.update();
  25829. // Camera target first?
  25830. if (this.game.camera.target)
  25831. {
  25832. this.game.camera.target.postUpdate();
  25833. this.updateTransform();
  25834. this.game.camera.updateTarget();
  25835. }
  25836. for (var i = 0; i < this.children.length; i++)
  25837. {
  25838. this.children[i].postUpdate();
  25839. }
  25840. this.updateTransform();
  25841. };
  25842. /**
  25843. * Updates the transforms for all objects on the display list.
  25844. * This overrides the Pixi default as we don't need the interactionManager, but do need the game property check.
  25845. *
  25846. * @method Phaser.Stage#updateTransform
  25847. */
  25848. Phaser.Stage.prototype.updateTransform = function () {
  25849. this.worldAlpha = 1;
  25850. for (var i = 0; i < this.children.length; i++)
  25851. {
  25852. this.children[i].updateTransform();
  25853. }
  25854. };
  25855. /**
  25856. * Starts a page visibility event listener running, or window.onpagehide/onpageshow if not supported by the browser.
  25857. * Also listens for window.onblur and window.onfocus.
  25858. *
  25859. * @method Phaser.Stage#checkVisibility
  25860. */
  25861. Phaser.Stage.prototype.checkVisibility = function () {
  25862. if (document.hidden !== undefined)
  25863. {
  25864. this._hiddenVar = 'visibilitychange';
  25865. }
  25866. else if (document.webkitHidden !== undefined)
  25867. {
  25868. this._hiddenVar = 'webkitvisibilitychange';
  25869. }
  25870. else if (document.mozHidden !== undefined)
  25871. {
  25872. this._hiddenVar = 'mozvisibilitychange';
  25873. }
  25874. else if (document.msHidden !== undefined)
  25875. {
  25876. this._hiddenVar = 'msvisibilitychange';
  25877. }
  25878. else
  25879. {
  25880. this._hiddenVar = null;
  25881. }
  25882. var _this = this;
  25883. this._onChange = function (event) {
  25884. return _this.visibilityChange(event);
  25885. };
  25886. this._onClick = function (event) {
  25887. if ((document.hasFocus !== undefined) && !document.hasFocus())
  25888. {
  25889. _this.visibilityChange(event);
  25890. }
  25891. };
  25892. // Does browser support it? If not (like in IE9 or old Android) we need to fall back to blur/focus
  25893. if (this._hiddenVar)
  25894. {
  25895. document.addEventListener(this._hiddenVar, this._onChange, false);
  25896. }
  25897. window.onblur = this._onChange;
  25898. window.onfocus = this._onChange;
  25899. window.onpagehide = this._onChange;
  25900. window.onpageshow = this._onChange;
  25901. window.addEventListener('click', this._onClick);
  25902. if (this.game.device.cocoonJSApp)
  25903. {
  25904. CocoonJS.App.onSuspended.addEventListener(function () {
  25905. Phaser.Stage.prototype.visibilityChange.call(_this, { type: "pause" });
  25906. });
  25907. CocoonJS.App.onActivated.addEventListener(function () {
  25908. Phaser.Stage.prototype.visibilityChange.call(_this, { type: "resume" });
  25909. });
  25910. }
  25911. };
  25912. /**
  25913. * This method is called when the document visibility is changed.
  25914. *
  25915. * - `blur` and `pagehide` events trigger {@link Phaser.Game#onBlur}. They {@link Phaser.Game#gamePaused pause the game} unless {@link #disableVisibilityChange} is on.
  25916. * - `click`, `focus`, and `pageshow` trigger {@link Phaser.Game#onFocus}. They {@link Phaser.Game#gameResumed resume the game} unless {@link #disableVisibilityChange} is on.
  25917. * - `visibilitychange` (hidden) and CocoonJS's `onSuspended` {@link Phaser.Game#gamePaused pause the game} unless {@link #disableVisibilityChange} is on.
  25918. * - `visibilitychange` (visible) and CocoonJS's `onActivated` {@link Phaser.Game#gameResumed resume the game} unless {@link #disableVisibilityChange} is on.
  25919. *
  25920. * @method Phaser.Stage#visibilityChange
  25921. * @param {Event} event - Its type will be used to decide whether the game should be paused or not.
  25922. */
  25923. Phaser.Stage.prototype.visibilityChange = function (event) {
  25924. // These events always trigger the Game#onBlur or Game#onFocus signals.
  25925. switch (event.type)
  25926. {
  25927. case 'blur':
  25928. case 'pagehide':
  25929. this.game.focusLoss(event);
  25930. return;
  25931. case 'click':
  25932. case 'focus':
  25933. case 'pageshow':
  25934. this.game.focusGain(event);
  25935. return;
  25936. }
  25937. if (this.disableVisibilityChange)
  25938. {
  25939. return;
  25940. }
  25941. if (document.hidden || document.mozHidden || document.msHidden || document.webkitHidden || event.type === "pause")
  25942. {
  25943. this.game.gamePaused(event);
  25944. }
  25945. else
  25946. {
  25947. this.game.gameResumed(event);
  25948. }
  25949. };
  25950. /**
  25951. * Sets the background color for the Stage.
  25952. *
  25953. * The color can be given as a hex string (`'#RRGGBB'`), a CSS color string (`'rgb(r,g,b)'`), or a numeric value (`0xRRGGBB`).
  25954. *
  25955. * An alpha channel is _not_ supported and will be ignored.
  25956. *
  25957. * If you've set your game to be {@link Phaser.Game#transparent transparent} then calls to setBackgroundColor are ignored.
  25958. *
  25959. * If {@link Phaser.Game#clearBeforeRender} is off then the background color won't appear.
  25960. *
  25961. * @method Phaser.Stage#setBackgroundColor
  25962. * @param {number|string} color - The color of the background.
  25963. */
  25964. Phaser.Stage.prototype.setBackgroundColor = function (color) {
  25965. if (this.game.transparent) { return; }
  25966. Phaser.Color.valueToColor(color, this._bgColor);
  25967. Phaser.Color.updateColor(this._bgColor);
  25968. // For gl.clearColor (canvas uses _bgColor.rgba)
  25969. this._bgColor.r /= 255;
  25970. this._bgColor.g /= 255;
  25971. this._bgColor.b /= 255;
  25972. this._bgColor.a = 1;
  25973. };
  25974. /**
  25975. * Destroys the Stage and removes event listeners.
  25976. *
  25977. * @method Phaser.Stage#destroy
  25978. */
  25979. Phaser.Stage.prototype.destroy = function () {
  25980. if (this._hiddenVar)
  25981. {
  25982. document.removeEventListener(this._hiddenVar, this._onChange, false);
  25983. }
  25984. window.onpagehide = null;
  25985. window.onpageshow = null;
  25986. window.onblur = null;
  25987. window.onfocus = null;
  25988. window.removeEventListener('click', this._onClick);
  25989. };
  25990. /**
  25991. * @name Phaser.Stage#backgroundColor
  25992. * @property {number|string} backgroundColor - Gets and sets the background color of the stage. The color can be given as a number: 0xff0000 or a hex string: '#ff0000'
  25993. * @see Phaser.Stage#setBackgroundColor
  25994. */
  25995. Object.defineProperty(Phaser.Stage.prototype, "backgroundColor", {
  25996. get: function () {
  25997. return this._bgColor.color;
  25998. },
  25999. set: function (color) {
  26000. this.setBackgroundColor(color);
  26001. }
  26002. });
  26003. /**
  26004. * Enable or disable texture smoothing for all objects on this Stage. Only works for bitmap/image textures. Smoothing is enabled by default.
  26005. *
  26006. * @name Phaser.Stage#smoothed
  26007. * @property {boolean} smoothed - Set to true to smooth all sprites rendered on this Stage, or false to disable smoothing (great for pixel art)
  26008. */
  26009. Object.defineProperty(Phaser.Stage.prototype, "smoothed", {
  26010. get: function () {
  26011. return PIXI.scaleModes.DEFAULT === PIXI.scaleModes.LINEAR;
  26012. },
  26013. set: function (value) {
  26014. if (value)
  26015. {
  26016. PIXI.scaleModes.DEFAULT = PIXI.scaleModes.LINEAR;
  26017. }
  26018. else
  26019. {
  26020. PIXI.scaleModes.DEFAULT = PIXI.scaleModes.NEAREST;
  26021. }
  26022. }
  26023. });
  26024. /**
  26025. * @author Richard Davey <rich@photonstorm.com>
  26026. * @copyright 2016 Photon Storm Ltd.
  26027. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  26028. */
  26029. /**
  26030. * A Group is a container for {@link DisplayObject display objects} including {@link Phaser.Sprite Sprites} and {@link Phaser.Image Images}.
  26031. *
  26032. * Groups form the logical tree structure of the display/scene graph where local transformations are applied to children.
  26033. * For instance, all children are also moved/rotated/scaled when the group is moved/rotated/scaled.
  26034. *
  26035. * In addition, Groups provides support for fast pooling and object recycling.
  26036. *
  26037. * Groups are also display objects and can be nested as children within other Groups.
  26038. *
  26039. * @class Phaser.Group
  26040. * @extends PIXI.DisplayObjectContainer
  26041. * @param {Phaser.Game} game - A reference to the currently running game.
  26042. * @param {DisplayObject|null} [parent=(game world)] - The parent Group (or other {@link DisplayObject}) that this group will be added to.
  26043. * If undefined/unspecified the Group will be added to the {@link Phaser.Game#world Game World}; if null the Group will not be added to any parent.
  26044. * @param {string} [name='group'] - A name for this group. Not used internally but useful for debugging.
  26045. * @param {boolean} [addToStage=false] - If true this group will be added directly to the Game.Stage instead of Game.World.
  26046. * @param {boolean} [enableBody=false] - If true all Sprites created with {@link #create} or {@link #createMulitple} will have a physics body created on them. Change the body type with {@link #physicsBodyType}.
  26047. * @param {integer} [physicsBodyType=0] - The physics body type to use when physics bodies are automatically added. See {@link #physicsBodyType} for values.
  26048. */
  26049. Phaser.Group = function (game, parent, name, addToStage, enableBody, physicsBodyType) {
  26050. if (addToStage === undefined) { addToStage = false; }
  26051. if (enableBody === undefined) { enableBody = false; }
  26052. if (physicsBodyType === undefined) { physicsBodyType = Phaser.Physics.ARCADE; }
  26053. /**
  26054. * A reference to the currently running Game.
  26055. * @property {Phaser.Game} game
  26056. * @protected
  26057. */
  26058. this.game = game;
  26059. if (parent === undefined)
  26060. {
  26061. parent = game.world;
  26062. }
  26063. /**
  26064. * A name for this group. Not used internally but useful for debugging.
  26065. * @property {string} name
  26066. */
  26067. this.name = name || 'group';
  26068. /**
  26069. * The z-depth value of this object within its parent container/Group - the World is a Group as well.
  26070. * This value must be unique for each child in a Group.
  26071. * @property {integer} z
  26072. * @readOnly
  26073. */
  26074. this.z = 0;
  26075. PIXI.DisplayObjectContainer.call(this);
  26076. if (addToStage)
  26077. {
  26078. this.game.stage.addChild(this);
  26079. this.z = this.game.stage.children.length;
  26080. }
  26081. else
  26082. {
  26083. if (parent)
  26084. {
  26085. parent.addChild(this);
  26086. this.z = parent.children.length;
  26087. }
  26088. }
  26089. /**
  26090. * Internal Phaser Type value.
  26091. * @property {integer} type
  26092. * @protected
  26093. */
  26094. this.type = Phaser.GROUP;
  26095. /**
  26096. * @property {number} physicsType - The const physics body type of this object.
  26097. * @readonly
  26098. */
  26099. this.physicsType = Phaser.GROUP;
  26100. /**
  26101. * The alive property is useful for Groups that are children of other Groups and need to be included/excluded in checks like forEachAlive.
  26102. * @property {boolean} alive
  26103. * @default
  26104. */
  26105. this.alive = true;
  26106. /**
  26107. * If exists is false the group will be excluded from collision checks and filters such as {@link #forEachExists}. The group will not call `preUpdate` and `postUpdate` on its children and the children will not receive physics updates or camera/world boundary checks. The group will still be {@link #visible} and will still call `update` on its children (unless {@link #updateOnlyExistingChildren} is true).
  26108. * @property {boolean} exists
  26109. * @default
  26110. */
  26111. this.exists = true;
  26112. /**
  26113. * A group with `ignoreDestroy` set to `true` ignores all calls to its `destroy` method.
  26114. * @property {boolean} ignoreDestroy
  26115. * @default
  26116. */
  26117. this.ignoreDestroy = false;
  26118. /**
  26119. * A Group is that has `pendingDestroy` set to `true` is flagged to have its destroy method
  26120. * called on the next logic update.
  26121. * You can set it directly to flag the Group to be destroyed on its next update.
  26122. *
  26123. * This is extremely useful if you wish to destroy a Group from within one of its own callbacks
  26124. * or a callback of one of its children.
  26125. *
  26126. * @property {boolean} pendingDestroy
  26127. */
  26128. this.pendingDestroy = false;
  26129. /**
  26130. * The type of objects that will be created when using {@link #create} or {@link #createMultiple}.
  26131. *
  26132. * It should extend either Sprite or Image and accept the same constructor arguments: `(game, x, y, key, frame)`.
  26133. *
  26134. * @property {function} classType
  26135. * @default {@link Phaser.Sprite}
  26136. */
  26137. this.classType = Phaser.Sprite;
  26138. /**
  26139. * The current display object that the group cursor is pointing to, if any. (Can be set manually.)
  26140. *
  26141. * The cursor is a way to iterate through the children in a Group using {@link #next} and {@link #previous}.
  26142. * @property {?DisplayObject} cursor
  26143. */
  26144. this.cursor = null;
  26145. /**
  26146. * A Group with `inputEnableChildren` set to `true` will automatically call `inputEnabled = true`
  26147. * on any children _added_ to, or _created by_, this Group.
  26148. *
  26149. * If there are children already in the Group at the time you set this property, they are not changed.
  26150. *
  26151. * @property {boolean} inputEnableChildren
  26152. * @default
  26153. */
  26154. this.inputEnableChildren = false;
  26155. /**
  26156. * Skip children with `exists = false` in {@link #update}.
  26157. *
  26158. * @property {boolean} updateOnlyExistingChildren
  26159. * @default
  26160. */
  26161. this.updateOnlyExistingChildren = false;
  26162. /**
  26163. * This Signal is dispatched whenever a child of this Group emits an onInputDown signal as a result
  26164. * of having been interacted with by a Pointer. You can bind functions to this Signal instead of to
  26165. * every child Sprite.
  26166. *
  26167. * This Signal is sent 2 arguments: A reference to the Sprite that triggered the signal, and
  26168. * a reference to the Pointer that caused it.
  26169. *
  26170. * @property {Phaser.Signal} onChildInputDown
  26171. */
  26172. this.onChildInputDown = new Phaser.Signal();
  26173. /**
  26174. * This Signal is dispatched whenever a child of this Group emits an onInputUp signal as a result
  26175. * of having been interacted with by a Pointer. You can bind functions to this Signal instead of to
  26176. * every child Sprite.
  26177. *
  26178. * This Signal is sent 3 arguments: A reference to the Sprite that triggered the signal,
  26179. * a reference to the Pointer that caused it, and a boolean value `isOver` that tells you if the Pointer
  26180. * is still over the Sprite or not.
  26181. *
  26182. * @property {Phaser.Signal} onChildInputUp
  26183. */
  26184. this.onChildInputUp = new Phaser.Signal();
  26185. /**
  26186. * This Signal is dispatched whenever a child of this Group emits an onInputOver signal as a result
  26187. * of having been interacted with by a Pointer. You can bind functions to this Signal instead of to
  26188. * every child Sprite.
  26189. *
  26190. * This Signal is sent 2 arguments: A reference to the Sprite that triggered the signal, and
  26191. * a reference to the Pointer that caused it.
  26192. *
  26193. * @property {Phaser.Signal} onChildInputOver
  26194. */
  26195. this.onChildInputOver = new Phaser.Signal();
  26196. /**
  26197. * This Signal is dispatched whenever a child of this Group emits an onInputOut signal as a result
  26198. * of having been interacted with by a Pointer. You can bind functions to this Signal instead of to
  26199. * every child Sprite.
  26200. *
  26201. * This Signal is sent 2 arguments: A reference to the Sprite that triggered the signal, and
  26202. * a reference to the Pointer that caused it.
  26203. *
  26204. * @property {Phaser.Signal} onChildInputOut
  26205. */
  26206. this.onChildInputOut = new Phaser.Signal();
  26207. /**
  26208. * If true all Sprites created by, or added to this group, will have a physics body enabled on them.
  26209. *
  26210. * If there are children already in the Group at the time you set this property, they are not changed.
  26211. *
  26212. * The default body type is controlled with {@link #physicsBodyType}.
  26213. * @property {boolean} enableBody
  26214. */
  26215. this.enableBody = enableBody;
  26216. /**
  26217. * If true when a physics body is created (via {@link #enableBody}) it will create a physics debug object as well.
  26218. *
  26219. * This only works for P2 bodies.
  26220. * @property {boolean} enableBodyDebug
  26221. * @default
  26222. */
  26223. this.enableBodyDebug = false;
  26224. /**
  26225. * If {@link #enableBody} is true this is the type of physics body that is created on new Sprites.
  26226. *
  26227. * The valid values are {@link Phaser.Physics.ARCADE}, {@link Phaser.Physics.P2JS}, {@link Phaser.Physics.NINJA}, etc.
  26228. * @property {integer} physicsBodyType
  26229. */
  26230. this.physicsBodyType = physicsBodyType;
  26231. /**
  26232. * If this Group contains Arcade Physics Sprites you can set a custom sort direction via this property.
  26233. *
  26234. * It should be set to one of the Phaser.Physics.Arcade sort direction constants:
  26235. *
  26236. * Phaser.Physics.Arcade.SORT_NONE
  26237. * Phaser.Physics.Arcade.LEFT_RIGHT
  26238. * Phaser.Physics.Arcade.RIGHT_LEFT
  26239. * Phaser.Physics.Arcade.TOP_BOTTOM
  26240. * Phaser.Physics.Arcade.BOTTOM_TOP
  26241. *
  26242. * If set to `null` the Group will use whatever Phaser.Physics.Arcade.sortDirection is set to. This is the default behavior.
  26243. *
  26244. * @property {integer} physicsSortDirection
  26245. * @default
  26246. */
  26247. this.physicsSortDirection = null;
  26248. /**
  26249. * This signal is dispatched when the group is destroyed.
  26250. * @property {Phaser.Signal} onDestroy
  26251. */
  26252. this.onDestroy = new Phaser.Signal();
  26253. /**
  26254. * @property {integer} cursorIndex - The current index of the Group cursor. Advance it with Group.next.
  26255. * @readOnly
  26256. */
  26257. this.cursorIndex = 0;
  26258. /**
  26259. * A Group that is fixed to the camera uses its x/y coordinates as offsets from the top left of the camera. These are stored in Group.cameraOffset.
  26260. *
  26261. * Note that the cameraOffset values are in addition to any parent in the display list.
  26262. * So if this Group was in a Group that has x: 200, then this will be added to the cameraOffset.x
  26263. *
  26264. * @property {boolean} fixedToCamera
  26265. */
  26266. this.fixedToCamera = false;
  26267. /**
  26268. * If this object is {@link #fixedToCamera} then this stores the x/y position offset relative to the top-left of the camera view.
  26269. * If the parent of this Group is also `fixedToCamera` then the offset here is in addition to that and should typically be disabled.
  26270. * @property {Phaser.Point} cameraOffset
  26271. */
  26272. this.cameraOffset = new Phaser.Point();
  26273. /**
  26274. * The hash array is an array belonging to this Group into which you can add any of its children via Group.addToHash and Group.removeFromHash.
  26275. *
  26276. * Only children of this Group can be added to and removed from the hash.
  26277. *
  26278. * This hash is used automatically by Phaser Arcade Physics in order to perform non z-index based destructive sorting.
  26279. * However if you don't use Arcade Physics, or this isn't a physics enabled Group, then you can use the hash to perform your own
  26280. * sorting and filtering of Group children without touching their z-index (and therefore display draw order)
  26281. *
  26282. * @property {array} hash
  26283. */
  26284. this.hash = [];
  26285. /**
  26286. * The property on which children are sorted.
  26287. * @property {string} _sortProperty
  26288. * @private
  26289. */
  26290. this._sortProperty = 'z';
  26291. };
  26292. Phaser.Group.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  26293. Phaser.Group.prototype.constructor = Phaser.Group;
  26294. /**
  26295. * A returnType value, as specified in {@link #iterate} eg.
  26296. * @constant
  26297. * @type {integer}
  26298. */
  26299. Phaser.Group.RETURN_NONE = 0;
  26300. /**
  26301. * A returnType value, as specified in {@link #iterate} eg.
  26302. * @constant
  26303. * @type {integer}
  26304. */
  26305. Phaser.Group.RETURN_TOTAL = 1;
  26306. /**
  26307. * A returnType value, as specified in {@link #iterate} eg.
  26308. * @constant
  26309. * @type {integer}
  26310. */
  26311. Phaser.Group.RETURN_CHILD = 2;
  26312. /**
  26313. * A returnType value, as specified in {@link #iterate} eg.
  26314. * @constant
  26315. * @type {integer}
  26316. */
  26317. Phaser.Group.RETURN_ALL = 3;
  26318. /**
  26319. * A sort ordering value, as specified in {@link #sort} eg.
  26320. * @constant
  26321. * @type {integer}
  26322. */
  26323. Phaser.Group.SORT_ASCENDING = -1;
  26324. /**
  26325. * A sort ordering value, as specified in {@link #sort} eg.
  26326. * @constant
  26327. * @type {integer}
  26328. */
  26329. Phaser.Group.SORT_DESCENDING = 1;
  26330. /**
  26331. * Adds an existing object as the top child in this group.
  26332. *
  26333. * The child is automatically added to the top of the group, and is displayed above every previous child.
  26334. *
  26335. * Or if the _optional_ index is specified, the child is added at the location specified by the index value,
  26336. * this allows you to control child ordering.
  26337. *
  26338. * If the child was already in this Group, it is simply returned, and nothing else happens to it.
  26339. *
  26340. * If `Group.enableBody` is set, then a physics body will be created on the object, so long as one does not already exist.
  26341. *
  26342. * If `Group.inputEnableChildren` is set, then an Input Handler will be created on the object, so long as one does not already exist.
  26343. *
  26344. * Use {@link #addAt} to control where a child is added. Use {@link #create} to create and add a new child.
  26345. *
  26346. * @method Phaser.Group#add
  26347. * @param {DisplayObject} child - The display object to add as a child.
  26348. * @param {boolean} [silent=false] - If true the child will not dispatch the `onAddedToGroup` event.
  26349. * @param {integer} [index] - The index within the group to insert the child to. Where 0 is the bottom of the Group.
  26350. * @return {DisplayObject} The child that was added to the group.
  26351. */
  26352. Phaser.Group.prototype.add = function (child, silent, index) {
  26353. if (silent === undefined) { silent = false; }
  26354. if (child.parent === this)
  26355. {
  26356. return child;
  26357. }
  26358. if (child.body && child.parent && child.parent.hash)
  26359. {
  26360. child.parent.removeFromHash(child);
  26361. }
  26362. if (index === undefined)
  26363. {
  26364. child.z = this.children.length;
  26365. this.addChild(child);
  26366. }
  26367. else
  26368. {
  26369. this.addChildAt(child, index);
  26370. this.updateZ();
  26371. }
  26372. if (this.enableBody && child.hasOwnProperty('body') && child.body === null)
  26373. {
  26374. this.game.physics.enable(child, this.physicsBodyType);
  26375. }
  26376. else if (child.body)
  26377. {
  26378. this.addToHash(child);
  26379. }
  26380. if (this.inputEnableChildren && (!child.input || child.inputEnabled))
  26381. {
  26382. child.inputEnabled = true;
  26383. }
  26384. if (!silent && child.events)
  26385. {
  26386. child.events.onAddedToGroup$dispatch(child, this);
  26387. }
  26388. if (this.cursor === null)
  26389. {
  26390. this.cursor = child;
  26391. }
  26392. return child;
  26393. };
  26394. /**
  26395. * Adds an existing object to this group.
  26396. *
  26397. * The child is added to the group at the location specified by the index value, this allows you to control child ordering.
  26398. *
  26399. * If `Group.enableBody` is set, then a physics body will be created on the object, so long as one does not already exist.
  26400. *
  26401. * If `Group.inputEnableChildren` is set, then an Input Handler will be created on the object, so long as one does not already exist.
  26402. *
  26403. * @method Phaser.Group#addAt
  26404. * @param {DisplayObject} child - The display object to add as a child.
  26405. * @param {integer} [index=0] - The index within the group to insert the child to.
  26406. * @param {boolean} [silent=false] - If true the child will not dispatch the `onAddedToGroup` event.
  26407. * @return {DisplayObject} The child that was added to the group.
  26408. */
  26409. Phaser.Group.prototype.addAt = function (child, index, silent) {
  26410. return this.add(child, silent, index);
  26411. };
  26412. /**
  26413. * Adds a child of this Group into the hash array.
  26414. * This call will return false if the child is not a child of this Group, or is already in the hash.
  26415. *
  26416. * @method Phaser.Group#addToHash
  26417. * @param {DisplayObject} child - The display object to add to this Groups hash. Must be a member of this Group already and not present in the hash.
  26418. * @return {boolean} True if the child was successfully added to the hash, otherwise false.
  26419. */
  26420. Phaser.Group.prototype.addToHash = function (child) {
  26421. if (child.parent === this)
  26422. {
  26423. var index = this.hash.indexOf(child);
  26424. if (index === -1)
  26425. {
  26426. this.hash.push(child);
  26427. return true;
  26428. }
  26429. }
  26430. return false;
  26431. };
  26432. /**
  26433. * Removes a child of this Group from the hash array.
  26434. * This call will return false if the child is not in the hash.
  26435. *
  26436. * @method Phaser.Group#removeFromHash
  26437. * @param {DisplayObject} child - The display object to remove from this Groups hash. Must be a member of this Group and in the hash.
  26438. * @return {boolean} True if the child was successfully removed from the hash, otherwise false.
  26439. */
  26440. Phaser.Group.prototype.removeFromHash = function (child) {
  26441. if (child)
  26442. {
  26443. var index = this.hash.indexOf(child);
  26444. if (index !== -1)
  26445. {
  26446. this.hash.splice(index, 1);
  26447. return true;
  26448. }
  26449. }
  26450. return false;
  26451. };
  26452. /**
  26453. * Adds an array of existing Display Objects to this Group.
  26454. *
  26455. * The Display Objects are automatically added to the top of this Group, and will render on-top of everything already in this Group.
  26456. *
  26457. * As well as an array you can also pass another Group as the first argument. In this case all of the children from that
  26458. * Group will be removed from it and added into this Group.
  26459. *
  26460. * If `Group.enableBody` is set, then a physics body will be created on the objects, so long as one does not already exist.
  26461. *
  26462. * If `Group.inputEnableChildren` is set, then an Input Handler will be created on the objects, so long as one does not already exist.
  26463. *
  26464. * @method Phaser.Group#addMultiple
  26465. * @param {DisplayObject[]|Phaser.Group} children - An array of display objects or a Phaser.Group. If a Group is given then *all* children will be moved from it.
  26466. * @param {boolean} [silent=false] - If true the children will not dispatch the `onAddedToGroup` event.
  26467. * @return {DisplayObject[]|Phaser.Group} The array of children or Group of children that were added to this Group.
  26468. */
  26469. Phaser.Group.prototype.addMultiple = function (children, silent) {
  26470. if (children instanceof Phaser.Group)
  26471. {
  26472. children.moveAll(this, silent);
  26473. }
  26474. else if (Array.isArray(children))
  26475. {
  26476. for (var i = 0; i < children.length; i++)
  26477. {
  26478. this.add(children[i], silent);
  26479. }
  26480. }
  26481. return children;
  26482. };
  26483. /**
  26484. * Returns the child found at the given index within this group.
  26485. *
  26486. * @method Phaser.Group#getAt
  26487. * @param {integer} index - The index to return the child from.
  26488. * @return {DisplayObject|integer} The child that was found at the given index, or -1 for an invalid index.
  26489. */
  26490. Phaser.Group.prototype.getAt = function (index) {
  26491. if (index < 0 || index >= this.children.length)
  26492. {
  26493. return -1;
  26494. }
  26495. else
  26496. {
  26497. return this.getChildAt(index);
  26498. }
  26499. };
  26500. /**
  26501. * Creates a new Phaser.Sprite object and adds it to the top of this group.
  26502. *
  26503. * Use {@link #classType} to change the type of object created.
  26504. *
  26505. * The child is automatically added to the top of the group, and is displayed above every previous child.
  26506. *
  26507. * Or if the _optional_ index is specified, the child is added at the location specified by the index value,
  26508. * this allows you to control child ordering.
  26509. *
  26510. * If `Group.enableBody` is set, then a physics body will be created on the object, so long as one does not already exist.
  26511. *
  26512. * If `Group.inputEnableChildren` is set, then an Input Handler will be created on the object, so long as one does not already exist.
  26513. *
  26514. * @method Phaser.Group#create
  26515. * @param {number} x - The x coordinate to display the newly created Sprite at. The value is in relation to the group.x point.
  26516. * @param {number} y - The y coordinate to display the newly created Sprite at. The value is in relation to the group.y point.
  26517. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache Image entry, or an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  26518. * @param {string|number} [frame] - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  26519. * @param {boolean} [exists=true] - The default exists state of the Sprite.
  26520. * @param {integer} [index] - The index within the group to insert the child to. Where 0 is the bottom of the Group.
  26521. * @return {DisplayObject} The child that was created: will be a {@link Phaser.Sprite} unless {@link #classType} has been changed.
  26522. */
  26523. Phaser.Group.prototype.create = function (x, y, key, frame, exists, index) {
  26524. if (exists === undefined) { exists = true; }
  26525. var child = new this.classType(this.game, x, y, key, frame);
  26526. child.exists = exists;
  26527. child.visible = exists;
  26528. child.alive = exists;
  26529. return this.add(child, false, index);
  26530. };
  26531. /**
  26532. * Creates multiple Phaser.Sprite objects and adds them to the top of this Group.
  26533. *
  26534. * This method is useful if you need to quickly generate a pool of sprites, such as bullets.
  26535. *
  26536. * Use {@link #classType} to change the type of object created.
  26537. *
  26538. * You can provide an array as the `key` and / or `frame` arguments. When you do this
  26539. * it will create `quantity` Sprites for every key (and frame) in the arrays.
  26540. *
  26541. * For example:
  26542. *
  26543. * `createMultiple(25, ['ball', 'carrot'])`
  26544. *
  26545. * In the above code there are 2 keys (ball and carrot) which means that 50 sprites will be
  26546. * created in total, 25 of each. You can also have the `frame` as an array:
  26547. *
  26548. * `createMultiple(5, 'bricks', [0, 1, 2, 3])`
  26549. *
  26550. * In the above there is one key (bricks), which is a sprite sheet. The frames array tells
  26551. * this method to use frames 0, 1, 2 and 3. So in total it will create 20 sprites, because
  26552. * the quantity was set to 5, so that is 5 brick sprites of frame 0, 5 brick sprites with
  26553. * frame 1, and so on.
  26554. *
  26555. * If you set both the key and frame arguments to be arrays then understand it will create
  26556. * a total quantity of sprites equal to the size of both arrays times each other. I.e.:
  26557. *
  26558. * `createMultiple(20, ['diamonds', 'balls'], [0, 1, 2])`
  26559. *
  26560. * The above will create 20 'diamonds' of frame 0, 20 with frame 1 and 20 with frame 2.
  26561. * It will then create 20 'balls' of frame 0, 20 with frame 1 and 20 with frame 2.
  26562. * In total it will have created 120 sprites.
  26563. *
  26564. * By default the Sprites will have their `exists` property set to `false`, and they will be
  26565. * positioned at 0x0, relative to the `Group.x / y` values.
  26566. *
  26567. * If `Group.enableBody` is set, then a physics body will be created on the objects, so long as one does not already exist.
  26568. *
  26569. * If `Group.inputEnableChildren` is set, then an Input Handler will be created on the objects, so long as one does not already exist.
  26570. *
  26571. * @method Phaser.Group#createMultiple
  26572. * @param {integer} quantity - The number of Sprites to create.
  26573. * @param {string|array} key - The Cache key of the image that the Sprites will use. Or an Array of keys. See the description for details on how the quantity applies when arrays are used.
  26574. * @param {integer|string|array} [frame=0] - If the Sprite image contains multiple frames you can specify which one to use here. Or an Array of frames. See the description for details on how the quantity applies when arrays are used.
  26575. * @param {boolean} [exists=false] - The default exists state of the Sprite.
  26576. * @param {function} [callback] - The function that will be called for each applicable child. It will be passed the new child and the loop index (0 through quantity - 1).
  26577. * @param {object} [callbackContext] - The context in which the function should be called (usually 'this'). The default context is the new child.
  26578. * @return {array} An array containing all of the Sprites that were created.
  26579. */
  26580. Phaser.Group.prototype.createMultiple = function (quantity, key, frame, exists, callback, callbackContext) {
  26581. if (frame === undefined) { frame = 0; }
  26582. if (exists === undefined) { exists = false; }
  26583. if (!Array.isArray(key))
  26584. {
  26585. key = [ key ];
  26586. }
  26587. if (!Array.isArray(frame))
  26588. {
  26589. frame = [ frame ];
  26590. }
  26591. var _this = this;
  26592. var children = [];
  26593. key.forEach(function(singleKey) {
  26594. frame.forEach(function(singleFrame) {
  26595. for (var i = 0; i < quantity; i++)
  26596. {
  26597. var child = _this.create(0, 0, singleKey, singleFrame, exists);
  26598. if (callback) { callback.call(callbackContext || child, child, i); }
  26599. children.push(child);
  26600. }
  26601. });
  26602. });
  26603. return children;
  26604. };
  26605. /**
  26606. * Internal method that re-applies all of the children's Z values.
  26607. *
  26608. * This must be called whenever children ordering is altered so that their `z` indices are correctly updated.
  26609. *
  26610. * @method Phaser.Group#updateZ
  26611. * @protected
  26612. */
  26613. Phaser.Group.prototype.updateZ = function () {
  26614. var i = this.children.length;
  26615. while (i--)
  26616. {
  26617. this.children[i].z = i;
  26618. }
  26619. };
  26620. /**
  26621. * This method iterates through all children in the Group (regardless if they are visible or exist)
  26622. * and then changes their position so they are arranged in a Grid formation. Children must have
  26623. * the `alignTo` method in order to be positioned by this call. All default Phaser Game Objects have
  26624. * this.
  26625. *
  26626. * The grid dimensions are determined by the first four arguments. The `width` and `height` arguments
  26627. * relate to the width and height of the grid respectively.
  26628. *
  26629. * For example if the Group had 100 children in it:
  26630. *
  26631. * `Group.align(10, 10, 32, 32)`
  26632. *
  26633. * This will align all of the children into a grid formation of 10x10, using 32 pixels per
  26634. * grid cell. If you want a wider grid, you could do:
  26635. *
  26636. * `Group.align(25, 4, 32, 32)`
  26637. *
  26638. * This will align the children into a grid of 25x4, again using 32 pixels per grid cell.
  26639. *
  26640. * You can choose to set _either_ the `width` or `height` value to -1. Doing so tells the method
  26641. * to keep on aligning children until there are no children left. For example if this Group had
  26642. * 48 children in it, the following:
  26643. *
  26644. * `Group.align(-1, 8, 32, 32)`
  26645. *
  26646. * ... will align the children so that there are 8 children vertically (the second argument),
  26647. * and each row will contain 6 sprites, except the last one, which will contain 5 (totaling 48)
  26648. *
  26649. * You can also do:
  26650. *
  26651. * `Group.align(10, -1, 32, 32)`
  26652. *
  26653. * In this case it will create a grid 10 wide, and as tall as it needs to be in order to fit
  26654. * all of the children in.
  26655. *
  26656. * The `position` property allows you to control where in each grid cell the child is positioned.
  26657. * This is a constant and can be one of `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`,
  26658. * `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`, `Phaser.CENTER`, `Phaser.RIGHT_CENTER`,
  26659. * `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`.
  26660. *
  26661. * The final argument; `offset` lets you start the alignment from a specific child index.
  26662. *
  26663. * @method Phaser.Group#align
  26664. * @param {integer} width - The width of the grid in items (not pixels). Set to -1 for a dynamic width. If -1 then you must set an explicit height value.
  26665. * @param {integer} height - The height of the grid in items (not pixels). Set to -1 for a dynamic height. If -1 then you must set an explicit width value.
  26666. * @param {integer} cellWidth - The width of each grid cell, in pixels.
  26667. * @param {integer} cellHeight - The height of each grid cell, in pixels.
  26668. * @param {integer} [position] - The position constant. One of `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`, `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`.
  26669. * @param {integer} [offset=0] - Optional index to start the alignment from. Defaults to zero, the first child in the Group, but can be set to any valid child index value.
  26670. * @return {boolean} True if the Group children were aligned, otherwise false.
  26671. */
  26672. Phaser.Group.prototype.align = function (width, height, cellWidth, cellHeight, position, offset) {
  26673. if (position === undefined) { position = Phaser.TOP_LEFT; }
  26674. if (offset === undefined) { offset = 0; }
  26675. if (this.children.length === 0 || offset > this.children.length || (width === -1 && height === -1))
  26676. {
  26677. return false;
  26678. }
  26679. var r = new Phaser.Rectangle(0, 0, cellWidth, cellHeight);
  26680. var w = (width * cellWidth);
  26681. var h = (height * cellHeight);
  26682. for (var i = offset; i < this.children.length; i++)
  26683. {
  26684. var child = this.children[i];
  26685. if (child['alignIn'])
  26686. {
  26687. child.alignIn(r, position);
  26688. }
  26689. else
  26690. {
  26691. continue;
  26692. }
  26693. if (width === -1)
  26694. {
  26695. // We keep laying them out horizontally until we've done them all
  26696. r.y += cellHeight;
  26697. if (r.y === h)
  26698. {
  26699. r.x += cellWidth;
  26700. r.y = 0;
  26701. }
  26702. }
  26703. else if (height === -1)
  26704. {
  26705. // We keep laying them out vertically until we've done them all
  26706. r.x += cellWidth;
  26707. if (r.x === w)
  26708. {
  26709. r.x = 0;
  26710. r.y += cellHeight;
  26711. }
  26712. }
  26713. else
  26714. {
  26715. // We keep laying them out until we hit the column limit
  26716. r.x += cellWidth;
  26717. if (r.x === w)
  26718. {
  26719. r.x = 0;
  26720. r.y += cellHeight;
  26721. if (r.y === h)
  26722. {
  26723. // We've hit the column limit, so return, even if there are children left
  26724. return true;
  26725. }
  26726. }
  26727. }
  26728. }
  26729. return true;
  26730. };
  26731. /**
  26732. * Sets the group cursor to the first child in the group.
  26733. *
  26734. * If the optional index parameter is given it sets the cursor to the object at that index instead.
  26735. *
  26736. * @method Phaser.Group#resetCursor
  26737. * @param {integer} [index=0] - Set the cursor to point to a specific index.
  26738. * @return {any} The child the cursor now points to.
  26739. */
  26740. Phaser.Group.prototype.resetCursor = function (index) {
  26741. if (index === undefined) { index = 0; }
  26742. if (index > this.children.length - 1)
  26743. {
  26744. index = 0;
  26745. }
  26746. if (this.cursor)
  26747. {
  26748. this.cursorIndex = index;
  26749. this.cursor = this.children[this.cursorIndex];
  26750. return this.cursor;
  26751. }
  26752. };
  26753. /**
  26754. * Advances the group cursor to the next (higher) object in the group.
  26755. *
  26756. * If the cursor is at the end of the group (top child) it is moved the start of the group (bottom child).
  26757. *
  26758. * @method Phaser.Group#next
  26759. * @return {any} The child the cursor now points to.
  26760. */
  26761. Phaser.Group.prototype.next = function () {
  26762. if (this.cursor)
  26763. {
  26764. // Wrap the cursor?
  26765. if (this.cursorIndex >= this.children.length - 1)
  26766. {
  26767. this.cursorIndex = 0;
  26768. }
  26769. else
  26770. {
  26771. this.cursorIndex++;
  26772. }
  26773. this.cursor = this.children[this.cursorIndex];
  26774. return this.cursor;
  26775. }
  26776. };
  26777. /**
  26778. * Moves the group cursor to the previous (lower) child in the group.
  26779. *
  26780. * If the cursor is at the start of the group (bottom child) it is moved to the end (top child).
  26781. *
  26782. * @method Phaser.Group#previous
  26783. * @return {any} The child the cursor now points to.
  26784. */
  26785. Phaser.Group.prototype.previous = function () {
  26786. if (this.cursor)
  26787. {
  26788. // Wrap the cursor?
  26789. if (this.cursorIndex === 0)
  26790. {
  26791. this.cursorIndex = this.children.length - 1;
  26792. }
  26793. else
  26794. {
  26795. this.cursorIndex--;
  26796. }
  26797. this.cursor = this.children[this.cursorIndex];
  26798. return this.cursor;
  26799. }
  26800. };
  26801. /**
  26802. * Swaps the position of two children in this group.
  26803. *
  26804. * Both children must be in this group, a child cannot be swapped with itself, and unparented children cannot be swapped.
  26805. *
  26806. * @method Phaser.Group#swap
  26807. * @param {any} child1 - The first child to swap.
  26808. * @param {any} child2 - The second child to swap.
  26809. */
  26810. Phaser.Group.prototype.swap = function (child1, child2) {
  26811. this.swapChildren(child1, child2);
  26812. this.updateZ();
  26813. };
  26814. /**
  26815. * Brings the given child to the top of this group so it renders above all other children.
  26816. *
  26817. * @method Phaser.Group#bringToTop
  26818. * @param {any} child - The child to bring to the top of this group.
  26819. * @return {any} The child that was moved.
  26820. */
  26821. Phaser.Group.prototype.bringToTop = function (child) {
  26822. if (child.parent === this && this.getIndex(child) < this.children.length)
  26823. {
  26824. this.remove(child, false, true);
  26825. this.add(child, true);
  26826. }
  26827. return child;
  26828. };
  26829. /**
  26830. * Sends the given child to the bottom of this group so it renders below all other children.
  26831. *
  26832. * @method Phaser.Group#sendToBack
  26833. * @param {any} child - The child to send to the bottom of this group.
  26834. * @return {any} The child that was moved.
  26835. */
  26836. Phaser.Group.prototype.sendToBack = function (child) {
  26837. if (child.parent === this && this.getIndex(child) > 0)
  26838. {
  26839. this.remove(child, false, true);
  26840. this.addAt(child, 0, true);
  26841. }
  26842. return child;
  26843. };
  26844. /**
  26845. * Moves the given child up one place in this group unless it's already at the top.
  26846. *
  26847. * @method Phaser.Group#moveUp
  26848. * @param {any} child - The child to move up in the group.
  26849. * @return {any} The child that was moved.
  26850. */
  26851. Phaser.Group.prototype.moveUp = function (child) {
  26852. if (child.parent === this && this.getIndex(child) < this.children.length - 1)
  26853. {
  26854. var a = this.getIndex(child);
  26855. var b = this.getAt(a + 1);
  26856. if (b)
  26857. {
  26858. this.swap(child, b);
  26859. }
  26860. }
  26861. return child;
  26862. };
  26863. /**
  26864. * Moves the given child down one place in this group unless it's already at the bottom.
  26865. *
  26866. * @method Phaser.Group#moveDown
  26867. * @param {any} child - The child to move down in the group.
  26868. * @return {any} The child that was moved.
  26869. */
  26870. Phaser.Group.prototype.moveDown = function (child) {
  26871. if (child.parent === this && this.getIndex(child) > 0)
  26872. {
  26873. var a = this.getIndex(child);
  26874. var b = this.getAt(a - 1);
  26875. if (b)
  26876. {
  26877. this.swap(child, b);
  26878. }
  26879. }
  26880. return child;
  26881. };
  26882. /**
  26883. * Positions the child found at the given index within this group to the given x and y coordinates.
  26884. *
  26885. * @method Phaser.Group#xy
  26886. * @param {integer} index - The index of the child in the group to set the position of.
  26887. * @param {number} x - The new x position of the child.
  26888. * @param {number} y - The new y position of the child.
  26889. */
  26890. Phaser.Group.prototype.xy = function (index, x, y) {
  26891. if (index < 0 || index > this.children.length)
  26892. {
  26893. return -1;
  26894. }
  26895. else
  26896. {
  26897. this.getChildAt(index).x = x;
  26898. this.getChildAt(index).y = y;
  26899. }
  26900. };
  26901. /**
  26902. * Reverses all children in this group.
  26903. *
  26904. * This operation applies only to immediate children and does not propagate to subgroups.
  26905. *
  26906. * @method Phaser.Group#reverse
  26907. */
  26908. Phaser.Group.prototype.reverse = function () {
  26909. this.children.reverse();
  26910. this.updateZ();
  26911. };
  26912. /**
  26913. * Get the index position of the given child in this group, which should match the child's `z` property.
  26914. *
  26915. * @method Phaser.Group#getIndex
  26916. * @param {any} child - The child to get the index for.
  26917. * @return {integer} The index of the child or -1 if it's not a member of this group.
  26918. */
  26919. Phaser.Group.prototype.getIndex = function (child) {
  26920. return this.children.indexOf(child);
  26921. };
  26922. /**
  26923. * Searches the Group for the first instance of a child with the `name`
  26924. * property matching the given argument. Should more than one child have
  26925. * the same name only the first instance is returned.
  26926. *
  26927. * @method Phaser.Group#getByName
  26928. * @param {string} name - The name to search for.
  26929. * @return {any} The first child with a matching name, or null if none were found.
  26930. */
  26931. Phaser.Group.prototype.getByName = function (name) {
  26932. for (var i = 0; i < this.children.length; i++)
  26933. {
  26934. if (this.children[i].name === name)
  26935. {
  26936. return this.children[i];
  26937. }
  26938. }
  26939. return null;
  26940. };
  26941. /**
  26942. * Replaces a child of this Group with the given newChild. The newChild cannot be a member of this Group.
  26943. *
  26944. * If `Group.enableBody` is set, then a physics body will be created on the object, so long as one does not already exist.
  26945. *
  26946. * If `Group.inputEnableChildren` is set, then an Input Handler will be created on the object, so long as one does not already exist.
  26947. *
  26948. * @method Phaser.Group#replace
  26949. * @param {any} oldChild - The child in this group that will be replaced.
  26950. * @param {any} newChild - The child to be inserted into this group.
  26951. * @return {any} Returns the oldChild that was replaced within this group.
  26952. */
  26953. Phaser.Group.prototype.replace = function (oldChild, newChild) {
  26954. var index = this.getIndex(oldChild);
  26955. if (index !== -1)
  26956. {
  26957. if (newChild.parent)
  26958. {
  26959. if (newChild.parent instanceof Phaser.Group)
  26960. {
  26961. newChild.parent.remove(newChild);
  26962. }
  26963. else
  26964. {
  26965. newChild.parent.removeChild(newChild);
  26966. }
  26967. }
  26968. this.remove(oldChild);
  26969. this.addAt(newChild, index);
  26970. return oldChild;
  26971. }
  26972. };
  26973. /**
  26974. * Checks if the child has the given property.
  26975. *
  26976. * Will scan up to 4 levels deep only.
  26977. *
  26978. * @method Phaser.Group#hasProperty
  26979. * @param {any} child - The child to check for the existence of the property on.
  26980. * @param {string[]} key - An array of strings that make up the property.
  26981. * @return {boolean} True if the child has the property, otherwise false.
  26982. */
  26983. Phaser.Group.prototype.hasProperty = function (child, key) {
  26984. var len = key.length;
  26985. if (len === 1 && key[0] in child)
  26986. {
  26987. return true;
  26988. }
  26989. else if (len === 2 && key[0] in child && key[1] in child[key[0]])
  26990. {
  26991. return true;
  26992. }
  26993. else if (len === 3 && key[0] in child && key[1] in child[key[0]] && key[2] in child[key[0]][key[1]])
  26994. {
  26995. return true;
  26996. }
  26997. else if (len === 4 && key[0] in child && key[1] in child[key[0]] && key[2] in child[key[0]][key[1]] && key[3] in child[key[0]][key[1]][key[2]])
  26998. {
  26999. return true;
  27000. }
  27001. return false;
  27002. };
  27003. /**
  27004. * Sets a property to the given value on the child. The operation parameter controls how the value is set.
  27005. *
  27006. * The operations are:
  27007. * - 0: set the existing value to the given value; if force is `true` a new property will be created if needed
  27008. * - 1: will add the given value to the value already present.
  27009. * - 2: will subtract the given value from the value already present.
  27010. * - 3: will multiply the value already present by the given value.
  27011. * - 4: will divide the value already present by the given value.
  27012. *
  27013. * @method Phaser.Group#setProperty
  27014. * @param {any} child - The child to set the property value on.
  27015. * @param {array} key - An array of strings that make up the property that will be set.
  27016. * @param {any} value - The value that will be set.
  27017. * @param {integer} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
  27018. * @param {boolean} [force=false] - If `force` is true then the property will be set on the child regardless if it already exists or not. If false and the property doesn't exist, nothing will be set.
  27019. * @return {boolean} True if the property was set, false if not.
  27020. */
  27021. Phaser.Group.prototype.setProperty = function (child, key, value, operation, force) {
  27022. if (force === undefined) { force = false; }
  27023. operation = operation || 0;
  27024. // As ugly as this approach looks, and although it's limited to a depth of only 4, it's much faster than a for loop or object iteration.
  27025. // 0 = Equals
  27026. // 1 = Add
  27027. // 2 = Subtract
  27028. // 3 = Multiply
  27029. // 4 = Divide
  27030. // We can't force a property in and the child doesn't have it, so abort.
  27031. // Equally we can't add, subtract, multiply or divide a property value if it doesn't exist, so abort in those cases too.
  27032. if (!this.hasProperty(child, key) && (!force || operation > 0))
  27033. {
  27034. return false;
  27035. }
  27036. var len = key.length;
  27037. if (len === 1)
  27038. {
  27039. if (operation === 0) { child[key[0]] = value; }
  27040. else if (operation === 1) { child[key[0]] += value; }
  27041. else if (operation === 2) { child[key[0]] -= value; }
  27042. else if (operation === 3) { child[key[0]] *= value; }
  27043. else if (operation === 4) { child[key[0]] /= value; }
  27044. }
  27045. else if (len === 2)
  27046. {
  27047. if (operation === 0) { child[key[0]][key[1]] = value; }
  27048. else if (operation === 1) { child[key[0]][key[1]] += value; }
  27049. else if (operation === 2) { child[key[0]][key[1]] -= value; }
  27050. else if (operation === 3) { child[key[0]][key[1]] *= value; }
  27051. else if (operation === 4) { child[key[0]][key[1]] /= value; }
  27052. }
  27053. else if (len === 3)
  27054. {
  27055. if (operation === 0) { child[key[0]][key[1]][key[2]] = value; }
  27056. else if (operation === 1) { child[key[0]][key[1]][key[2]] += value; }
  27057. else if (operation === 2) { child[key[0]][key[1]][key[2]] -= value; }
  27058. else if (operation === 3) { child[key[0]][key[1]][key[2]] *= value; }
  27059. else if (operation === 4) { child[key[0]][key[1]][key[2]] /= value; }
  27060. }
  27061. else if (len === 4)
  27062. {
  27063. if (operation === 0) { child[key[0]][key[1]][key[2]][key[3]] = value; }
  27064. else if (operation === 1) { child[key[0]][key[1]][key[2]][key[3]] += value; }
  27065. else if (operation === 2) { child[key[0]][key[1]][key[2]][key[3]] -= value; }
  27066. else if (operation === 3) { child[key[0]][key[1]][key[2]][key[3]] *= value; }
  27067. else if (operation === 4) { child[key[0]][key[1]][key[2]][key[3]] /= value; }
  27068. }
  27069. return true;
  27070. };
  27071. /**
  27072. * Checks a property for the given value on the child.
  27073. *
  27074. * @method Phaser.Group#checkProperty
  27075. * @param {any} child - The child to check the property value on.
  27076. * @param {string} key - The property, as a string, to be checked. For example: 'body.velocity.x'
  27077. * @param {any} value - The value that will be checked.
  27078. * @param {boolean} [force=false] - Also return false if the property is missing or undefined (regardless of the `value` argument).
  27079. * @return {boolean} True if `child` is a child of this Group and the property was equal to value, false if not.
  27080. */
  27081. Phaser.Group.prototype.checkProperty = function (child, key, value, force) {
  27082. if (force === undefined) { force = false; }
  27083. if (this !== child.parent)
  27084. {
  27085. return false;
  27086. }
  27087. var result = Phaser.Utils.getProperty(child, key);
  27088. if (((result === undefined) && force) || (result !== value))
  27089. {
  27090. return false;
  27091. }
  27092. return true;
  27093. };
  27094. /**
  27095. * Quickly set a property on a single child of this group to a new value.
  27096. *
  27097. * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
  27098. *
  27099. * @method Phaser.Group#set
  27100. * @param {Phaser.Sprite} child - The child to set the property on.
  27101. * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
  27102. * @param {any} value - The value that will be set.
  27103. * @param {boolean} [checkAlive=false] - If set then the child will only be updated if alive=true.
  27104. * @param {boolean} [checkVisible=false] - If set then the child will only be updated if visible=true.
  27105. * @param {integer} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
  27106. * @param {boolean} [force=false] - If `force` is true then the property will be set on the child regardless if it already exists or not. If false and the property doesn't exist, nothing will be set.
  27107. * @return {boolean} True if the property was set, false if not.
  27108. */
  27109. Phaser.Group.prototype.set = function (child, key, value, checkAlive, checkVisible, operation, force) {
  27110. if (force === undefined) { force = false; }
  27111. key = key.split('.');
  27112. if (checkAlive === undefined) { checkAlive = false; }
  27113. if (checkVisible === undefined) { checkVisible = false; }
  27114. if ((checkAlive === false || (checkAlive && child.alive)) && (checkVisible === false || (checkVisible && child.visible)))
  27115. {
  27116. return this.setProperty(child, key, value, operation, force);
  27117. }
  27118. };
  27119. /**
  27120. * Quickly set the same property across all children of this group to a new value.
  27121. *
  27122. * This call doesn't descend down children, so if you have a Group inside of this group, the property will be set on the group but not its children.
  27123. * If you need that ability please see `Group.setAllChildren`.
  27124. *
  27125. * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
  27126. *
  27127. * @method Phaser.Group#setAll
  27128. * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
  27129. * @param {any} value - The value that will be set.
  27130. * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. This includes any Groups that are children.
  27131. * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. This includes any Groups that are children.
  27132. * @param {integer} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
  27133. * @param {boolean} [force=false] - If `force` is true then the property will be set on the child regardless if it already exists or not. If false and the property doesn't exist, nothing will be set.
  27134. */
  27135. Phaser.Group.prototype.setAll = function (key, value, checkAlive, checkVisible, operation, force) {
  27136. if (checkAlive === undefined) { checkAlive = false; }
  27137. if (checkVisible === undefined) { checkVisible = false; }
  27138. if (force === undefined) { force = false; }
  27139. key = key.split('.');
  27140. operation = operation || 0;
  27141. for (var i = 0; i < this.children.length; i++)
  27142. {
  27143. if ((!checkAlive || (checkAlive && this.children[i].alive)) && (!checkVisible || (checkVisible && this.children[i].visible)))
  27144. {
  27145. this.setProperty(this.children[i], key, value, operation, force);
  27146. }
  27147. }
  27148. };
  27149. /**
  27150. * Quickly set the same property across all children of this group, and any child Groups, to a new value.
  27151. *
  27152. * If this group contains other Groups then the same property is set across their children as well, iterating down until it reaches the bottom.
  27153. * Unlike with `setAll` the property is NOT set on child Groups itself.
  27154. *
  27155. * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication.
  27156. *
  27157. * @method Phaser.Group#setAllChildren
  27158. * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x'
  27159. * @param {any} value - The value that will be set.
  27160. * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. This includes any Groups that are children.
  27161. * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. This includes any Groups that are children.
  27162. * @param {integer} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it.
  27163. * @param {boolean} [force=false] - If `force` is true then the property will be set on the child regardless if it already exists or not. If false and the property doesn't exist, nothing will be set.
  27164. */
  27165. Phaser.Group.prototype.setAllChildren = function (key, value, checkAlive, checkVisible, operation, force) {
  27166. if (checkAlive === undefined) { checkAlive = false; }
  27167. if (checkVisible === undefined) { checkVisible = false; }
  27168. if (force === undefined) { force = false; }
  27169. operation = operation || 0;
  27170. for (var i = 0; i < this.children.length; i++)
  27171. {
  27172. if ((!checkAlive || (checkAlive && this.children[i].alive)) && (!checkVisible || (checkVisible && this.children[i].visible)))
  27173. {
  27174. if (this.children[i] instanceof Phaser.Group)
  27175. {
  27176. this.children[i].setAllChildren(key, value, checkAlive, checkVisible, operation, force);
  27177. }
  27178. else
  27179. {
  27180. this.setProperty(this.children[i], key.split('.'), value, operation, force);
  27181. }
  27182. }
  27183. }
  27184. };
  27185. /**
  27186. * Test that the same property across all children of this group is equal to the given value.
  27187. *
  27188. * This call doesn't descend down children, so if you have a Group inside of this group, the property will be checked on the group but not its children.
  27189. *
  27190. * @method Phaser.Group#checkAll
  27191. * @param {string} key - The property, as a string, to be checked. For example: 'body.velocity.x'
  27192. * @param {any} value - The value that will be checked.
  27193. * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be checked. This includes any Groups that are children.
  27194. * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be checked. This includes any Groups that are children.
  27195. * @param {boolean} [force=false] - Also return false if the property is missing or undefined (regardless of the `value` argument).
  27196. * @return {boolean} - True if all eligible children have the given property value (but see `force`); otherwise false.
  27197. */
  27198. Phaser.Group.prototype.checkAll = function (key, value, checkAlive, checkVisible, force) {
  27199. if (checkAlive === undefined) { checkAlive = false; }
  27200. if (checkVisible === undefined) { checkVisible = false; }
  27201. if (force === undefined) { force = false; }
  27202. for (var i = 0; i < this.children.length; i++)
  27203. {
  27204. var child = this.children[i];
  27205. if ((!checkAlive || (checkAlive && child.alive)) && (!checkVisible || (checkVisible && child.visible)))
  27206. {
  27207. if (!this.checkProperty(child, key, value, force))
  27208. {
  27209. return false;
  27210. }
  27211. }
  27212. }
  27213. return true;
  27214. };
  27215. /**
  27216. * Test that at least one child of this group has the given property value.
  27217. *
  27218. * This call doesn't descend down children, so if you have a Group inside of this group, the property will be checked on the group but not its children.
  27219. *
  27220. * @method Phaser.Group#checkAny
  27221. * @param {string} key - The property, as a string, to be checked. For example: 'body.velocity.x'
  27222. * @param {any} value - The value that will be checked.
  27223. * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be checked. This includes any Groups that are children.
  27224. * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be checked. This includes any Groups that are children.
  27225. * @return {boolean} - True if at least one eligible child has the given property value; otherwise false.
  27226. */
  27227. Phaser.Group.prototype.checkAny = function (key, value, checkAlive, checkVisible) {
  27228. if (checkAlive === undefined) { checkAlive = false; }
  27229. if (checkVisible === undefined) { checkVisible = false; }
  27230. for (var i = 0; i < this.children.length; i++)
  27231. {
  27232. var child = this.children[i];
  27233. if ((!checkAlive || (checkAlive && child.alive)) && (!checkVisible || (checkVisible && child.visible)))
  27234. {
  27235. if (this.checkProperty(child, key, value))
  27236. {
  27237. return true;
  27238. }
  27239. }
  27240. }
  27241. return false;
  27242. };
  27243. /**
  27244. * Adds the amount to the given property on all children in this group.
  27245. *
  27246. * `Group.addAll('x', 10)` will add 10 to the child.x value for each child.
  27247. *
  27248. * @method Phaser.Group#addAll
  27249. * @param {string} property - The property to increment, for example 'body.velocity.x' or 'angle'.
  27250. * @param {number} amount - The amount to increment the property by. If child.x = 10 then addAll('x', 40) would make child.x = 50.
  27251. * @param {boolean} [checkAlive] - If true the property will only be changed if the child is alive.
  27252. * @param {boolean} [checkVisible] - If true the property will only be changed if the child is visible.
  27253. */
  27254. Phaser.Group.prototype.addAll = function (property, amount, checkAlive, checkVisible) {
  27255. this.setAll(property, amount, checkAlive, checkVisible, 1);
  27256. };
  27257. /**
  27258. * Subtracts the amount from the given property on all children in this group.
  27259. *
  27260. * `Group.subAll('x', 10)` will minus 10 from the child.x value for each child.
  27261. *
  27262. * @method Phaser.Group#subAll
  27263. * @param {string} property - The property to decrement, for example 'body.velocity.x' or 'angle'.
  27264. * @param {number} amount - The amount to subtract from the property. If child.x = 50 then subAll('x', 40) would make child.x = 10.
  27265. * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
  27266. * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
  27267. */
  27268. Phaser.Group.prototype.subAll = function (property, amount, checkAlive, checkVisible) {
  27269. this.setAll(property, amount, checkAlive, checkVisible, 2);
  27270. };
  27271. /**
  27272. * Multiplies the given property by the amount on all children in this group.
  27273. *
  27274. * `Group.multiplyAll('x', 2)` will x2 the child.x value for each child.
  27275. *
  27276. * @method Phaser.Group#multiplyAll
  27277. * @param {string} property - The property to multiply, for example 'body.velocity.x' or 'angle'.
  27278. * @param {number} amount - The amount to multiply the property by. If child.x = 10 then multiplyAll('x', 2) would make child.x = 20.
  27279. * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
  27280. * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
  27281. */
  27282. Phaser.Group.prototype.multiplyAll = function (property, amount, checkAlive, checkVisible) {
  27283. this.setAll(property, amount, checkAlive, checkVisible, 3);
  27284. };
  27285. /**
  27286. * Divides the given property by the amount on all children in this group.
  27287. *
  27288. * `Group.divideAll('x', 2)` will half the child.x value for each child.
  27289. *
  27290. * @method Phaser.Group#divideAll
  27291. * @param {string} property - The property to divide, for example 'body.velocity.x' or 'angle'.
  27292. * @param {number} amount - The amount to divide the property by. If child.x = 100 then divideAll('x', 2) would make child.x = 50.
  27293. * @param {boolean} checkAlive - If true the property will only be changed if the child is alive.
  27294. * @param {boolean} checkVisible - If true the property will only be changed if the child is visible.
  27295. */
  27296. Phaser.Group.prototype.divideAll = function (property, amount, checkAlive, checkVisible) {
  27297. this.setAll(property, amount, checkAlive, checkVisible, 4);
  27298. };
  27299. /**
  27300. * Sets {@link #alive}, {@link #exists}, and {@link #visible} to false.
  27301. *
  27302. * @method Phaser.Group#kill
  27303. */
  27304. Phaser.Group.prototype.kill = function () {
  27305. this.alive = false;
  27306. this.exists = false;
  27307. this.visible = false;
  27308. };
  27309. /**
  27310. * Kills all children having exists=true.
  27311. *
  27312. * @method Phaser.Group#killAll
  27313. */
  27314. Phaser.Group.prototype.killAll = function () {
  27315. this.callAllExists('kill', true);
  27316. };
  27317. /**
  27318. * Sets {@link #alive}, {@link #exists}, and {@link #visible} to true.
  27319. *
  27320. * @method Phaser.Group#revive
  27321. */
  27322. Phaser.Group.prototype.revive = function () {
  27323. this.alive = true;
  27324. this.exists = true;
  27325. this.visible = true;
  27326. };
  27327. /**
  27328. * Revives all children having exists=false.
  27329. *
  27330. * @method Phaser.Group#reviveAll
  27331. */
  27332. Phaser.Group.prototype.reviveAll = function () {
  27333. this.callAllExists('revive', false);
  27334. };
  27335. /**
  27336. * Calls {@link #resetChild} on each child (or each existing child).
  27337. *
  27338. * @method Phaser.Group#resetAll
  27339. * @param {number} [x] - The x coordinate to reset each child to. The value is in relation to the group.x point.
  27340. * @param {number} [y] - The y coordinate to reset each child to. The value is in relation to the group.y point.
  27341. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - The image or texture used by the Sprite during rendering.
  27342. * @param {string|number} [frame] - The frame of a sprite sheet or texture atlas.
  27343. * @param {boolean} [checkExists=false] - Reset only existing children.
  27344. */
  27345. Phaser.Group.prototype.resetAll = function (x, y, key, frame, checkExists) {
  27346. this.forEach(this.resetChild, this, checkExists, x, y, key, frame);
  27347. };
  27348. /**
  27349. * Calls a function, specified by name, on all children in the group who exist (or do not exist).
  27350. *
  27351. * After the existsValue parameter you can add as many parameters as you like, which will all be passed to the child callback.
  27352. *
  27353. * @method Phaser.Group#callAllExists
  27354. * @param {string} callback - Name of the function on the children to call.
  27355. * @param {boolean} existsValue - Only children with exists=existsValue will be called.
  27356. * @param {...any} parameter - Additional parameters that will be passed to the callback.
  27357. */
  27358. Phaser.Group.prototype.callAllExists = function (callback, existsValue) {
  27359. var args;
  27360. if (arguments.length > 2)
  27361. {
  27362. args = [];
  27363. for (var i = 2; i < arguments.length; i++)
  27364. {
  27365. args.push(arguments[i]);
  27366. }
  27367. }
  27368. for (var i = 0; i < this.children.length; i++)
  27369. {
  27370. if (this.children[i].exists === existsValue && this.children[i][callback])
  27371. {
  27372. this.children[i][callback].apply(this.children[i], args);
  27373. }
  27374. }
  27375. };
  27376. /**
  27377. * Returns a reference to a function that exists on a child of the group based on the given callback array.
  27378. *
  27379. * @method Phaser.Group#callbackFromArray
  27380. * @param {object} child - The object to inspect.
  27381. * @param {array} callback - The array of function names.
  27382. * @param {integer} length - The size of the array (pre-calculated in callAll).
  27383. * @protected
  27384. */
  27385. Phaser.Group.prototype.callbackFromArray = function (child, callback, length) {
  27386. // Kinda looks like a Christmas tree
  27387. if (length === 1)
  27388. {
  27389. if (child[callback[0]])
  27390. {
  27391. return child[callback[0]];
  27392. }
  27393. }
  27394. else if (length === 2)
  27395. {
  27396. if (child[callback[0]][callback[1]])
  27397. {
  27398. return child[callback[0]][callback[1]];
  27399. }
  27400. }
  27401. else if (length === 3)
  27402. {
  27403. if (child[callback[0]][callback[1]][callback[2]])
  27404. {
  27405. return child[callback[0]][callback[1]][callback[2]];
  27406. }
  27407. }
  27408. else if (length === 4)
  27409. {
  27410. if (child[callback[0]][callback[1]][callback[2]][callback[3]])
  27411. {
  27412. return child[callback[0]][callback[1]][callback[2]][callback[3]];
  27413. }
  27414. }
  27415. else if (child[callback])
  27416. {
  27417. return child[callback];
  27418. }
  27419. return false;
  27420. };
  27421. /**
  27422. * Calls a function, specified by name, on all on children.
  27423. *
  27424. * The function is called for all children regardless if they are dead or alive (see callAllExists for different options).
  27425. * After the method parameter and context you can add as many extra parameters as you like, which will all be passed to the child.
  27426. *
  27427. * @method Phaser.Group#callAll
  27428. * @param {string} method - Name of the function on the child to call. Deep property lookup is supported.
  27429. * @param {string} [context=null] - A string containing the context under which the method will be executed. Set to null to default to the child.
  27430. * @param {...any} args - Additional parameters that will be passed to the method.
  27431. */
  27432. Phaser.Group.prototype.callAll = function (method, context) {
  27433. if (method === undefined)
  27434. {
  27435. return;
  27436. }
  27437. // Extract the method into an array
  27438. method = method.split('.');
  27439. var methodLength = method.length;
  27440. if (context === undefined || context === null || context === '')
  27441. {
  27442. context = null;
  27443. }
  27444. else
  27445. {
  27446. // Extract the context into an array
  27447. if (typeof context === 'string')
  27448. {
  27449. context = context.split('.');
  27450. var contextLength = context.length;
  27451. }
  27452. }
  27453. var args;
  27454. if (arguments.length > 2)
  27455. {
  27456. args = [];
  27457. for (var i = 2; i < arguments.length; i++)
  27458. {
  27459. args.push(arguments[i]);
  27460. }
  27461. }
  27462. var callback = null;
  27463. var callbackContext = null;
  27464. for (var i = 0; i < this.children.length; i++)
  27465. {
  27466. callback = this.callbackFromArray(this.children[i], method, methodLength);
  27467. if (context && callback)
  27468. {
  27469. callbackContext = this.callbackFromArray(this.children[i], context, contextLength);
  27470. if (callback)
  27471. {
  27472. callback.apply(callbackContext, args);
  27473. }
  27474. }
  27475. else if (callback)
  27476. {
  27477. callback.apply(this.children[i], args);
  27478. }
  27479. }
  27480. };
  27481. /**
  27482. * The core preUpdate - as called by World.
  27483. * @method Phaser.Group#preUpdate
  27484. * @protected
  27485. */
  27486. Phaser.Group.prototype.preUpdate = function () {
  27487. if (this.pendingDestroy)
  27488. {
  27489. this.destroy();
  27490. return false;
  27491. }
  27492. if (!this.exists || !this.parent.exists)
  27493. {
  27494. this.renderOrderID = -1;
  27495. return false;
  27496. }
  27497. // This chunk is identical to Phaser.Component.Core.prototype.preUpdateChildren, which is not yet defined.
  27498. // This can't loop in reverse, we need the renderOrderID to be in sequence
  27499. var i = 0;
  27500. while (i < this.children.length)
  27501. {
  27502. var child = this.children[i];
  27503. child.preUpdate();
  27504. if (this === child.parent)
  27505. {
  27506. i++;
  27507. }
  27508. }
  27509. return true;
  27510. };
  27511. /**
  27512. * The core update - as called by World.
  27513. *
  27514. * Children with `exists = false` are updated unless {@link #updateOnlyExistingChildren} is true.
  27515. *
  27516. * @method Phaser.Group#update
  27517. * @protected
  27518. */
  27519. Phaser.Group.prototype.update = function () {
  27520. // Goes in reverse, because it's highly likely the child will destroy itself in `update`
  27521. var i = this.children.length;
  27522. while (i--)
  27523. {
  27524. var len = this.children.length;
  27525. if (i >= len) { i = len - 1; }
  27526. var child = this.children[i];
  27527. if (!this.updateOnlyExistingChildren || child.exists) {
  27528. child.update();
  27529. }
  27530. }
  27531. };
  27532. /**
  27533. * The core postUpdate - as called by World.
  27534. * @method Phaser.Group#postUpdate
  27535. * @protected
  27536. */
  27537. Phaser.Group.prototype.postUpdate = function () {
  27538. // Fixed to Camera?
  27539. if (this.fixedToCamera)
  27540. {
  27541. this.x = (this.game.camera.view.x + this.cameraOffset.x) / this.game.camera.scale.x;
  27542. this.y = (this.game.camera.view.y + this.cameraOffset.y) / this.game.camera.scale.y;
  27543. }
  27544. for (var i = 0; i < this.children.length; i++)
  27545. {
  27546. this.children[i].postUpdate();
  27547. }
  27548. };
  27549. /**
  27550. * Find children matching a certain predicate.
  27551. *
  27552. * For example:
  27553. *
  27554. * var healthyList = Group.filter(function(child, index, children) {
  27555. * return child.health > 10 ? true : false;
  27556. * }, true);
  27557. * healthyList.callAll('attack');
  27558. *
  27559. * Note: Currently this will skip any children which are Groups themselves.
  27560. *
  27561. * @method Phaser.Group#filter
  27562. * @param {function} predicate - The function that each child will be evaluated against. Each child of the group will be passed to it as its first parameter, the index as the second, and the entire child array as the third
  27563. * @param {boolean} [checkExists=false] - If true, only existing can be selected; otherwise all children can be selected and will be passed to the predicate.
  27564. * @return {Phaser.ArraySet} Returns an array list containing all the children that the predicate returned true for
  27565. */
  27566. Phaser.Group.prototype.filter = function (predicate, checkExists) {
  27567. var index = -1;
  27568. var length = this.children.length;
  27569. var results = [];
  27570. while (++index < length)
  27571. {
  27572. var child = this.children[index];
  27573. if (!checkExists || (checkExists && child.exists))
  27574. {
  27575. if (predicate(child, index, this.children))
  27576. {
  27577. results.push(child);
  27578. }
  27579. }
  27580. }
  27581. return new Phaser.ArraySet(results);
  27582. };
  27583. /**
  27584. * Call a function on each child in this group.
  27585. *
  27586. * Additional arguments for the callback can be specified after the `checkExists` parameter. For example,
  27587. *
  27588. * Group.forEach(awardBonusGold, this, true, 100, 500)
  27589. *
  27590. * would invoke `awardBonusGold` function with the parameters `(child, 100, 500)`.
  27591. *
  27592. * Note: This check will skip any children which are Groups themselves.
  27593. *
  27594. * @method Phaser.Group#forEach
  27595. * @param {function} callback - The function that will be called for each applicable child. The child will be passed as the first argument.
  27596. * @param {object} callbackContext - The context in which the function should be called (usually 'this').
  27597. * @param {boolean} [checkExists=false] - If set only children matching for which `exists` is true will be passed to the callback, otherwise all children will be passed.
  27598. * @param {...any} [args=(none)] - Additional arguments to pass to the callback function, after the child item.
  27599. */
  27600. Phaser.Group.prototype.forEach = function (callback, callbackContext, checkExists) {
  27601. if (checkExists === undefined) { checkExists = false; }
  27602. if (arguments.length <= 3)
  27603. {
  27604. for (var i = 0; i < this.children.length; i++)
  27605. {
  27606. if (!checkExists || (checkExists && this.children[i].exists))
  27607. {
  27608. callback.call(callbackContext, this.children[i]);
  27609. }
  27610. }
  27611. }
  27612. else
  27613. {
  27614. // Assigning to arguments properties causes Extreme Deoptimization in Chrome, FF, and IE.
  27615. // Using an array and pushing each element (not a slice!) is _significantly_ faster.
  27616. var args = [null];
  27617. for (var i = 3; i < arguments.length; i++)
  27618. {
  27619. args.push(arguments[i]);
  27620. }
  27621. for (var i = 0; i < this.children.length; i++)
  27622. {
  27623. if (!checkExists || (checkExists && this.children[i].exists))
  27624. {
  27625. args[0] = this.children[i];
  27626. callback.apply(callbackContext, args);
  27627. }
  27628. }
  27629. }
  27630. };
  27631. /**
  27632. * Call a function on each existing child in this group.
  27633. *
  27634. * See {@link Phaser.Group#forEach forEach} for details.
  27635. *
  27636. * @method Phaser.Group#forEachExists
  27637. * @param {function} callback - The function that will be called for each applicable child. The child will be passed as the first argument.
  27638. * @param {object} callbackContext - The context in which the function should be called (usually 'this').
  27639. * @param {...any} [args=(none)] - Additional arguments to pass to the callback function, after the child item.
  27640. */
  27641. Phaser.Group.prototype.forEachExists = function (callback, callbackContext) {
  27642. var args;
  27643. if (arguments.length > 2)
  27644. {
  27645. args = [null];
  27646. for (var i = 2; i < arguments.length; i++)
  27647. {
  27648. args.push(arguments[i]);
  27649. }
  27650. }
  27651. this.iterate('exists', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
  27652. };
  27653. /**
  27654. * Call a function on each alive child in this group.
  27655. *
  27656. * See {@link Phaser.Group#forEach forEach} for details.
  27657. *
  27658. * @method Phaser.Group#forEachAlive
  27659. * @param {function} callback - The function that will be called for each applicable child. The child will be passed as the first argument.
  27660. * @param {object} callbackContext - The context in which the function should be called (usually 'this').
  27661. * @param {...any} [args=(none)] - Additional arguments to pass to the callback function, after the child item.
  27662. */
  27663. Phaser.Group.prototype.forEachAlive = function (callback, callbackContext) {
  27664. var args;
  27665. if (arguments.length > 2)
  27666. {
  27667. args = [null];
  27668. for (var i = 2; i < arguments.length; i++)
  27669. {
  27670. args.push(arguments[i]);
  27671. }
  27672. }
  27673. this.iterate('alive', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
  27674. };
  27675. /**
  27676. * Call a function on each dead child in this group.
  27677. *
  27678. * See {@link Phaser.Group#forEach forEach} for details.
  27679. *
  27680. * @method Phaser.Group#forEachDead
  27681. * @param {function} callback - The function that will be called for each applicable child. The child will be passed as the first argument.
  27682. * @param {object} callbackContext - The context in which the function should be called (usually 'this').
  27683. * @param {...any} [args=(none)] - Additional arguments to pass to the callback function, after the child item.
  27684. */
  27685. Phaser.Group.prototype.forEachDead = function (callback, callbackContext) {
  27686. var args;
  27687. if (arguments.length > 2)
  27688. {
  27689. args = [null];
  27690. for (var i = 2; i < arguments.length; i++)
  27691. {
  27692. args.push(arguments[i]);
  27693. }
  27694. }
  27695. this.iterate('alive', false, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args);
  27696. };
  27697. /**
  27698. * Sort the children in the group according to a particular key and ordering.
  27699. *
  27700. * Call this function to sort the group according to a particular key value and order.
  27701. *
  27702. * For example to depth sort Sprites for Zelda-style game you might call `group.sort('y', Phaser.Group.SORT_ASCENDING)` at the bottom of your `State.update()`.
  27703. *
  27704. * Internally this uses a standard JavaScript Array sort, so everything that applies there also applies here, including
  27705. * alphabetical sorting, mixing strings and numbers, and Unicode sorting. See MDN for more details.
  27706. *
  27707. * @method Phaser.Group#sort
  27708. * @param {string} [key='z'] - The name of the property to sort on. Defaults to the objects z-depth value.
  27709. * @param {integer} [order=Phaser.Group.SORT_ASCENDING] - Order ascending ({@link Phaser.Group.SORT_ASCENDING SORT_ASCENDING}) or descending ({@link Phaser.Group.SORT_DESCENDING SORT_DESCENDING}).
  27710. */
  27711. Phaser.Group.prototype.sort = function (key, order) {
  27712. if (this.children.length < 2)
  27713. {
  27714. // Nothing to swap
  27715. return;
  27716. }
  27717. if (key === undefined) { key = 'z'; }
  27718. if (order === undefined) { order = Phaser.Group.SORT_ASCENDING; }
  27719. this._sortProperty = key;
  27720. if (order === Phaser.Group.SORT_ASCENDING)
  27721. {
  27722. this.children.sort(this.ascendingSortHandler.bind(this));
  27723. }
  27724. else
  27725. {
  27726. this.children.sort(this.descendingSortHandler.bind(this));
  27727. }
  27728. this.updateZ();
  27729. };
  27730. /**
  27731. * Sort the children in the group according to custom sort function.
  27732. *
  27733. * The `sortHandler` is provided the two parameters: the two children involved in the comparison (a and b).
  27734. * It should return -1 if `a > b`, 1 if `a < b` or 0 if `a === b`.
  27735. *
  27736. * @method Phaser.Group#customSort
  27737. * @param {function} sortHandler - The custom sort function.
  27738. * @param {object} [context=undefined] - The context in which the sortHandler is called.
  27739. */
  27740. Phaser.Group.prototype.customSort = function (sortHandler, context) {
  27741. if (this.children.length < 2)
  27742. {
  27743. // Nothing to swap
  27744. return;
  27745. }
  27746. this.children.sort(sortHandler.bind(context));
  27747. this.updateZ();
  27748. };
  27749. /**
  27750. * An internal helper function for the sort process.
  27751. *
  27752. * @method Phaser.Group#ascendingSortHandler
  27753. * @protected
  27754. * @param {object} a - The first object being sorted.
  27755. * @param {object} b - The second object being sorted.
  27756. */
  27757. Phaser.Group.prototype.ascendingSortHandler = function (a, b) {
  27758. if (a[this._sortProperty] < b[this._sortProperty])
  27759. {
  27760. return -1;
  27761. }
  27762. else if (a[this._sortProperty] > b[this._sortProperty])
  27763. {
  27764. return 1;
  27765. }
  27766. else
  27767. {
  27768. if (a.z < b.z)
  27769. {
  27770. return -1;
  27771. }
  27772. else
  27773. {
  27774. return 1;
  27775. }
  27776. }
  27777. };
  27778. /**
  27779. * An internal helper function for the sort process.
  27780. *
  27781. * @method Phaser.Group#descendingSortHandler
  27782. * @protected
  27783. * @param {object} a - The first object being sorted.
  27784. * @param {object} b - The second object being sorted.
  27785. */
  27786. Phaser.Group.prototype.descendingSortHandler = function (a, b) {
  27787. if (a[this._sortProperty] < b[this._sortProperty])
  27788. {
  27789. return 1;
  27790. }
  27791. else if (a[this._sortProperty] > b[this._sortProperty])
  27792. {
  27793. return -1;
  27794. }
  27795. else
  27796. {
  27797. return 0;
  27798. }
  27799. };
  27800. /**
  27801. * Iterates over the children of the group performing one of several actions for matched children.
  27802. *
  27803. * A child is considered a match when it has a property, named `key`, whose value is equal to `value`
  27804. * according to a strict equality comparison.
  27805. *
  27806. * The result depends on the `returnType`:
  27807. *
  27808. * - {@link Phaser.Group.RETURN_TOTAL RETURN_TOTAL}:
  27809. * The callback, if any, is applied to all matching children. The number of matched children is returned.
  27810. * - {@link Phaser.Group.RETURN_NONE RETURN_NONE}:
  27811. * The callback, if any, is applied to all matching children. No value is returned.
  27812. * - {@link Phaser.Group.RETURN_CHILD RETURN_CHILD}:
  27813. * The callback, if any, is applied to the *first* matching child and the *first* matched child is returned.
  27814. * If there is no matching child then null is returned.
  27815. *
  27816. * If `args` is specified it must be an array. The matched child will be assigned to the first
  27817. * element and the entire array will be applied to the callback function.
  27818. *
  27819. * @method Phaser.Group#iterate
  27820. * @param {string} key - The child property to check, i.e. 'exists', 'alive', 'health'
  27821. * @param {any} value - A child matches if `child[key] === value` is true.
  27822. * @param {integer} returnType - How to iterate the children and what to return.
  27823. * @param {function} [callback=null] - Optional function that will be called on each matching child. The matched child is supplied as the first argument.
  27824. * @param {object} [callbackContext] - The context in which the function should be called (usually 'this').
  27825. * @param {any[]} [args=(none)] - The arguments supplied to to the callback; the first array index (argument) will be replaced with the matched child.
  27826. * @return {any} Returns either an integer (for RETURN_TOTAL), the first matched child (for RETURN_CHILD), or null.
  27827. */
  27828. Phaser.Group.prototype.iterate = function (key, value, returnType, callback, callbackContext, args) {
  27829. if (this.children.length === 0)
  27830. {
  27831. if (returnType === Phaser.Group.RETURN_TOTAL)
  27832. {
  27833. return 0;
  27834. }
  27835. else if (returnType === Phaser.Group.RETURN_ALL)
  27836. {
  27837. return [];
  27838. }
  27839. }
  27840. var total = 0;
  27841. if (returnType === Phaser.Group.RETURN_ALL)
  27842. {
  27843. var output = [];
  27844. }
  27845. for (var i = 0; i < this.children.length; i++)
  27846. {
  27847. if (this.children[i][key] === value)
  27848. {
  27849. total++;
  27850. if (callback)
  27851. {
  27852. if (args)
  27853. {
  27854. args[0] = this.children[i];
  27855. callback.apply(callbackContext, args);
  27856. }
  27857. else
  27858. {
  27859. callback.call(callbackContext, this.children[i]);
  27860. }
  27861. }
  27862. if (returnType === Phaser.Group.RETURN_CHILD)
  27863. {
  27864. return this.children[i];
  27865. }
  27866. else if (returnType === Phaser.Group.RETURN_ALL)
  27867. {
  27868. output.push(this.children[i]);
  27869. }
  27870. }
  27871. }
  27872. if (returnType === Phaser.Group.RETURN_TOTAL)
  27873. {
  27874. return total;
  27875. }
  27876. else if (returnType === Phaser.Group.RETURN_ALL)
  27877. {
  27878. return output;
  27879. }
  27880. else
  27881. {
  27882. // RETURN_CHILD or RETURN_NONE
  27883. return null;
  27884. }
  27885. };
  27886. /**
  27887. * Get the first display object with the given property name and value.
  27888. *
  27889. * @method Phaser.Group#getFirst
  27890. * @param {string} key - The child property to check.
  27891. * @param {string} value - A child matches if `child[key] === value` is true.
  27892. * @return {DisplayObject} The first child matching the query, or `null` if none were found.
  27893. */
  27894. Phaser.Group.prototype.getFirst = function (key, value) {
  27895. return this.iterate(key, value, Phaser.Group.RETURN_CHILD);
  27896. };
  27897. /**
  27898. * Get the first display object that exists, or doesn't exist.
  27899. *
  27900. * You can use the optional argument `createIfNull` to create a new Game Object if none matching your exists argument were found in this Group.
  27901. *
  27902. * It works by calling `Group.create` passing it the parameters given to this method, and returning the new child.
  27903. *
  27904. * If a child *was* found , `createIfNull` is `false` and you provided the additional arguments then the child
  27905. * will be reset and/or have a new texture loaded on it. This is handled by `Group.resetChild`.
  27906. *
  27907. * @method Phaser.Group#getFirstExists
  27908. * @param {boolean} [exists=true] - If true, find the first existing child; otherwise find the first non-existing child.
  27909. * @param {boolean} [createIfNull=false] - If `true` and no alive children are found a new one is created.
  27910. * @param {number} [x] - The x coordinate to reset the child to. The value is in relation to the group.x point.
  27911. * @param {number} [y] - The y coordinate to reset the child to. The value is in relation to the group.y point.
  27912. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache Image entry, or an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  27913. * @param {string|number} [frame] - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  27914. * @return {DisplayObject} The first child, or `null` if none found and `createIfNull` was false.
  27915. */
  27916. Phaser.Group.prototype.getFirstExists = function (exists, createIfNull, x, y, key, frame) {
  27917. if (createIfNull === undefined) { createIfNull = false; }
  27918. if (typeof exists !== 'boolean')
  27919. {
  27920. exists = true;
  27921. }
  27922. var child = this.getFirst('exists', exists);
  27923. return (child === null && createIfNull) ? this.create(x, y, key, frame) : this.resetChild(child, x, y, key, frame);
  27924. };
  27925. /**
  27926. * Get the first child that is alive (`child.alive === true`).
  27927. *
  27928. * This is handy for choosing a squad leader, etc.
  27929. *
  27930. * You can use the optional argument `createIfNull` to create a new Game Object if no alive ones were found in this Group.
  27931. *
  27932. * It works by calling `Group.create` passing it the parameters given to this method, and returning the new child.
  27933. *
  27934. * If a child *was* found , `createIfNull` is `false` and you provided the additional arguments then the child
  27935. * will be reset and/or have a new texture loaded on it. This is handled by `Group.resetChild`.
  27936. *
  27937. * @method Phaser.Group#getFirstAlive
  27938. * @param {boolean} [createIfNull=false] - If `true` and no alive children are found a new one is created.
  27939. * @param {number} [x] - The x coordinate to reset the child to. The value is in relation to the group.x point.
  27940. * @param {number} [y] - The y coordinate to reset the child to. The value is in relation to the group.y point.
  27941. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache Image entry, or an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  27942. * @param {string|number} [frame] - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  27943. * @return {DisplayObject} The alive dead child, or `null` if none found and `createIfNull` was false.
  27944. */
  27945. Phaser.Group.prototype.getFirstAlive = function (createIfNull, x, y, key, frame) {
  27946. if (createIfNull === undefined) { createIfNull = false; }
  27947. var child = this.getFirst('alive', true);
  27948. return (child === null && createIfNull) ? this.create(x, y, key, frame) : this.resetChild(child, x, y, key, frame);
  27949. };
  27950. /**
  27951. * Get the first child that is dead (`child.alive === false`).
  27952. *
  27953. * This is handy for checking if everything has been wiped out and adding to the pool as needed.
  27954. *
  27955. * You can use the optional argument `createIfNull` to create a new Game Object if no dead ones were found in this Group.
  27956. *
  27957. * It works by calling `Group.create` passing it the parameters given to this method, and returning the new child.
  27958. *
  27959. * If a child *was* found , `createIfNull` is `false` and you provided the additional arguments then the child
  27960. * will be reset and/or have a new texture loaded on it. This is handled by `Group.resetChild`.
  27961. *
  27962. * @method Phaser.Group#getFirstDead
  27963. * @param {boolean} [createIfNull=false] - If `true` and no dead children are found a new one is created.
  27964. * @param {number} [x] - The x coordinate to reset the child to. The value is in relation to the group.x point.
  27965. * @param {number} [y] - The y coordinate to reset the child to. The value is in relation to the group.y point.
  27966. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache Image entry, or an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  27967. * @param {string|number} [frame] - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  27968. * @return {DisplayObject} The first dead child, or `null` if none found and `createIfNull` was false.
  27969. */
  27970. Phaser.Group.prototype.getFirstDead = function (createIfNull, x, y, key, frame) {
  27971. if (createIfNull === undefined) { createIfNull = false; }
  27972. var child = this.getFirst('alive', false);
  27973. return (child === null && createIfNull) ? this.create(x, y, key, frame) : this.resetChild(child, x, y, key, frame);
  27974. };
  27975. /**
  27976. * Takes a child and if the `x` and `y` arguments are given it calls `child.reset(x, y)` on it.
  27977. *
  27978. * If the `key` and optionally the `frame` arguments are given, it calls `child.loadTexture(key, frame)` on it.
  27979. *
  27980. * The two operations are separate. For example if you just wish to load a new texture then pass `null` as the x and y values.
  27981. *
  27982. * @method Phaser.Group#resetChild
  27983. * @param {DisplayObject} child - The child to reset and/or load the texture on.
  27984. * @param {number} [x] - The x coordinate to reset the child to. The value is in relation to the group.x point.
  27985. * @param {number} [y] - The y coordinate to reset the child to. The value is in relation to the group.y point.
  27986. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache Image entry, or an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  27987. * @param {string|number} [frame] - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  27988. * @return {DisplayObject} The child that was reset: usually a {@link Phaser.Sprite}.
  27989. */
  27990. Phaser.Group.prototype.resetChild = function (child, x, y, key, frame) {
  27991. if (child === null)
  27992. {
  27993. return null;
  27994. }
  27995. if (x === undefined) { x = null; }
  27996. if (y === undefined) { y = null; }
  27997. if (x !== null && y !== null)
  27998. {
  27999. child.reset(x, y);
  28000. }
  28001. if (key !== undefined)
  28002. {
  28003. child.loadTexture(key, frame);
  28004. }
  28005. return child;
  28006. };
  28007. /**
  28008. * Return the child at the top of this group.
  28009. *
  28010. * The top child is the child displayed (rendered) above every other child.
  28011. *
  28012. * @method Phaser.Group#getTop
  28013. * @return {any} The child at the top of the Group.
  28014. */
  28015. Phaser.Group.prototype.getTop = function () {
  28016. if (this.children.length > 0)
  28017. {
  28018. return this.children[this.children.length - 1];
  28019. }
  28020. };
  28021. /**
  28022. * Returns the child at the bottom of this group.
  28023. *
  28024. * The bottom child the child being displayed (rendered) below every other child.
  28025. *
  28026. * @method Phaser.Group#getBottom
  28027. * @return {any} The child at the bottom of the Group.
  28028. */
  28029. Phaser.Group.prototype.getBottom = function () {
  28030. if (this.children.length > 0)
  28031. {
  28032. return this.children[0];
  28033. }
  28034. };
  28035. /**
  28036. * Get the closest child to given Object, with optional callback to filter children.
  28037. *
  28038. * This can be a Sprite, Group, Image or any object with public x and y properties.
  28039. *
  28040. * 'close' is determined by the distance from the objects `x` and `y` properties compared to the childs `x` and `y` properties.
  28041. *
  28042. * You can use the optional `callback` argument to apply your own filter to the distance checks.
  28043. * If the child is closer then the previous child, it will be sent to `callback` as the first argument,
  28044. * with the distance as the second. The callback should return `true` if it passes your
  28045. * filtering criteria, otherwise it should return `false`.
  28046. *
  28047. * @method Phaser.Group#getClosestTo
  28048. * @param {any} object - The object used to determine the distance. This can be a Sprite, Group, Image or any object with public x and y properties.
  28049. * @param {function} [callback] - The function that each child will be evaluated against. Each child of the group will be passed to it as its first parameter, with the distance as the second. It should return `true` if the child passes the matching criteria.
  28050. * @param {object} [callbackContext] - The context in which the function should be called (usually 'this').
  28051. * @return {any} The child closest to given object, or `null` if no child was found.
  28052. */
  28053. Phaser.Group.prototype.getClosestTo = function (object, callback, callbackContext) {
  28054. var distance = Number.MAX_VALUE;
  28055. var tempDistance = 0;
  28056. var result = null;
  28057. for (var i = 0; i < this.children.length; i++)
  28058. {
  28059. var child = this.children[i];
  28060. if (child.exists)
  28061. {
  28062. tempDistance = Math.abs(Phaser.Point.distance(object, child));
  28063. if (tempDistance < distance && (!callback || callback.call(callbackContext, child, tempDistance)))
  28064. {
  28065. distance = tempDistance;
  28066. result = child;
  28067. }
  28068. }
  28069. }
  28070. return result;
  28071. };
  28072. /**
  28073. * Get the child furthest away from the given Object, with optional callback to filter children.
  28074. *
  28075. * This can be a Sprite, Group, Image or any object with public x and y properties.
  28076. *
  28077. * 'furthest away' is determined by the distance from the objects `x` and `y` properties compared to the childs `x` and `y` properties.
  28078. *
  28079. * You can use the optional `callback` argument to apply your own filter to the distance checks.
  28080. * If the child is closer then the previous child, it will be sent to `callback` as the first argument,
  28081. * with the distance as the second. The callback should return `true` if it passes your
  28082. * filtering criteria, otherwise it should return `false`.
  28083. *
  28084. * @method Phaser.Group#getFurthestFrom
  28085. * @param {any} object - The object used to determine the distance. This can be a Sprite, Group, Image or any object with public x and y properties.
  28086. * @param {function} [callback] - The function that each child will be evaluated against. Each child of the group will be passed to it as its first parameter, with the distance as the second. It should return `true` if the child passes the matching criteria.
  28087. * @param {object} [callbackContext] - The context in which the function should be called (usually 'this').
  28088. * @return {any} The child furthest from the given object, or `null` if no child was found.
  28089. */
  28090. Phaser.Group.prototype.getFurthestFrom = function (object, callback, callbackContext) {
  28091. var distance = 0;
  28092. var tempDistance = 0;
  28093. var result = null;
  28094. for (var i = 0; i < this.children.length; i++)
  28095. {
  28096. var child = this.children[i];
  28097. if (child.exists)
  28098. {
  28099. tempDistance = Math.abs(Phaser.Point.distance(object, child));
  28100. if (tempDistance > distance && (!callback || callback.call(callbackContext, child, tempDistance)))
  28101. {
  28102. distance = tempDistance;
  28103. result = child;
  28104. }
  28105. }
  28106. }
  28107. return result;
  28108. };
  28109. /**
  28110. * Get the number of children with the given property name and value.
  28111. *
  28112. * @method Phaser.Group#count
  28113. * @param {string} key - The child property to check.
  28114. * @param {string} value - A child matches if `child[key] === value` is true.
  28115. * @return {integer} The number of children matching the query.
  28116. */
  28117. Phaser.Group.prototype.count = function (key, value) {
  28118. return this.iterate(key, value, Phaser.Group.RETURN_TOTAL);
  28119. };
  28120. /**
  28121. * Get the number of living children in this group.
  28122. *
  28123. * @method Phaser.Group#countLiving
  28124. * @return {integer} The number of children flagged as alive.
  28125. */
  28126. Phaser.Group.prototype.countLiving = function () {
  28127. return this.count('alive', true);
  28128. };
  28129. /**
  28130. * Get the number of dead children in this group.
  28131. *
  28132. * @method Phaser.Group#countDead
  28133. * @return {integer} The number of children flagged as dead.
  28134. */
  28135. Phaser.Group.prototype.countDead = function () {
  28136. return this.count('alive', false);
  28137. };
  28138. /**
  28139. * Returns a random child from the group.
  28140. *
  28141. * @method Phaser.Group#getRandom
  28142. * @param {integer} [startIndex=0] - Offset from the front of the group (lowest child).
  28143. * @param {integer} [length=(to top)] - Restriction on the number of values you want to randomly select from.
  28144. * @return {any} A random child of this Group.
  28145. */
  28146. Phaser.Group.prototype.getRandom = function (startIndex, length) {
  28147. if (startIndex === undefined) { startIndex = 0; }
  28148. if (length === undefined) { length = this.children.length; }
  28149. if (length === 0)
  28150. {
  28151. return null;
  28152. }
  28153. return Phaser.ArrayUtils.getRandomItem(this.children, startIndex, length);
  28154. };
  28155. /**
  28156. * Returns a random child from the Group that has `exists` set to `true`.
  28157. *
  28158. * Optionally you can specify a start and end index. For example if this Group had 100 children,
  28159. * and you set `startIndex` to 0 and `endIndex` to 50, it would return a random child from only
  28160. * the first 50 children in the Group.
  28161. *
  28162. * @method Phaser.Group#getRandomExists
  28163. * @param {integer} [startIndex=0] - The first child index to start the search from.
  28164. * @param {integer} [endIndex] - The last child index to search up to.
  28165. * @return {any} A random child of this Group that exists.
  28166. */
  28167. Phaser.Group.prototype.getRandomExists = function (startIndex, endIndex) {
  28168. var list = this.getAll('exists', true, startIndex, endIndex);
  28169. return this.game.rnd.pick(list);
  28170. };
  28171. /**
  28172. * Returns all children in this Group.
  28173. *
  28174. * You can optionally specify a matching criteria using the `property` and `value` arguments.
  28175. *
  28176. * For example: `getAll('exists', true)` would return only children that have an `exists` property equal to `true`.
  28177. *
  28178. * Optionally you can specify a start and end index. For example if this Group had 100 children,
  28179. * and you set `startIndex` to 0 and `endIndex` to 50, it would return the first 50 children in the Group.
  28180. * If `property` and `value` are also specified, only children within the given index range are searched.
  28181. *
  28182. * @method Phaser.Group#getAll
  28183. * @param {string} [property] - An optional property to test against the value argument.
  28184. * @param {any} [value] - If property is set then Child.property must strictly equal this value to be included in the results.
  28185. * @param {integer} [startIndex=0] - The first child index to start the search from.
  28186. * @param {integer} [endIndex] - The last child index to search up until.
  28187. * @return {array} - An array containing all, some, or none of the Children of this Group.
  28188. */
  28189. Phaser.Group.prototype.getAll = function (property, value, startIndex, endIndex) {
  28190. if (startIndex === undefined) { startIndex = 0; }
  28191. if (endIndex === undefined) { endIndex = this.children.length; }
  28192. var output = [];
  28193. for (var i = startIndex; i < endIndex; i++)
  28194. {
  28195. var child = this.children[i];
  28196. if (property)
  28197. {
  28198. if (child[property] === value)
  28199. {
  28200. output.push(child);
  28201. }
  28202. }
  28203. else
  28204. {
  28205. output.push(child);
  28206. }
  28207. }
  28208. return output;
  28209. };
  28210. /**
  28211. * Removes the given child from this group.
  28212. *
  28213. * This will dispatch an `onRemovedFromGroup` event from the child (if it has one), and optionally destroy the child.
  28214. *
  28215. * If the group cursor was referring to the removed child it is updated to refer to the next child.
  28216. *
  28217. * @method Phaser.Group#remove
  28218. * @param {any} child - The child to remove.
  28219. * @param {boolean} [destroy=false] - If true `destroy` will be invoked on the removed child.
  28220. * @param {boolean} [silent=false] - If true the the child will not dispatch the `onRemovedFromGroup` event.
  28221. * @return {boolean} true if the child was removed from this group, otherwise false.
  28222. */
  28223. Phaser.Group.prototype.remove = function (child, destroy, silent) {
  28224. if (destroy === undefined) { destroy = false; }
  28225. if (silent === undefined) { silent = false; }
  28226. if (this.children.length === 0 || this.children.indexOf(child) === -1)
  28227. {
  28228. return false;
  28229. }
  28230. if (!silent && child.events && !child.destroyPhase)
  28231. {
  28232. child.events.onRemovedFromGroup$dispatch(child, this);
  28233. }
  28234. var removed = this.removeChild(child);
  28235. this.removeFromHash(child);
  28236. this.updateZ();
  28237. if (this.cursor === child)
  28238. {
  28239. this.next();
  28240. }
  28241. if (destroy && removed)
  28242. {
  28243. removed.destroy(true);
  28244. }
  28245. return true;
  28246. };
  28247. /**
  28248. * Moves all children from this Group to the Group given.
  28249. *
  28250. * @method Phaser.Group#moveAll
  28251. * @param {Phaser.Group} group - The new Group to which the children will be moved to.
  28252. * @param {boolean} [silent=false] - If true the children will not dispatch the `onAddedToGroup` event for the new Group.
  28253. * @return {Phaser.Group} The Group to which all the children were moved.
  28254. */
  28255. Phaser.Group.prototype.moveAll = function (group, silent) {
  28256. if (silent === undefined) { silent = false; }
  28257. if (this.children.length > 0 && group instanceof Phaser.Group)
  28258. {
  28259. do
  28260. {
  28261. group.add(this.children[0], silent);
  28262. }
  28263. while (this.children.length > 0);
  28264. this.hash = [];
  28265. this.cursor = null;
  28266. }
  28267. return group;
  28268. };
  28269. /**
  28270. * Removes all children from this Group, but does not remove the group from its parent.
  28271. *
  28272. * The children can be optionally destroyed as they are removed.
  28273. *
  28274. * You can also optionally also destroy the BaseTexture the Child is using. Be careful if you've
  28275. * more than one Game Object sharing the same BaseTexture.
  28276. *
  28277. * @method Phaser.Group#removeAll
  28278. * @param {boolean} [destroy=false] - If true `destroy` will be invoked on each removed child.
  28279. * @param {boolean} [silent=false] - If true the children will not dispatch their `onRemovedFromGroup` events.
  28280. * @param {boolean} [destroyTexture=false] - If true, and if the `destroy` argument is also true, the BaseTexture belonging to the Child is also destroyed. Note that if another Game Object is sharing the same BaseTexture it will invalidate it.
  28281. */
  28282. Phaser.Group.prototype.removeAll = function (destroy, silent, destroyTexture) {
  28283. if (destroy === undefined) { destroy = false; }
  28284. if (silent === undefined) { silent = false; }
  28285. if (destroyTexture === undefined) { destroyTexture = false; }
  28286. if (this.children.length === 0)
  28287. {
  28288. return;
  28289. }
  28290. do
  28291. {
  28292. if (!silent && this.children[0].events)
  28293. {
  28294. this.children[0].events.onRemovedFromGroup$dispatch(this.children[0], this);
  28295. }
  28296. var removed = this.removeChild(this.children[0]);
  28297. this.removeFromHash(removed);
  28298. if (destroy && removed)
  28299. {
  28300. removed.destroy(true, destroyTexture);
  28301. }
  28302. }
  28303. while (this.children.length > 0);
  28304. this.hash = [];
  28305. this.cursor = null;
  28306. };
  28307. /**
  28308. * Removes all children from this group whose index falls beteen the given startIndex and endIndex values.
  28309. *
  28310. * @method Phaser.Group#removeBetween
  28311. * @param {integer} startIndex - The index to start removing children from.
  28312. * @param {integer} [endIndex] - The index to stop removing children at. Must be higher than startIndex. If undefined this method will remove all children between startIndex and the end of the group.
  28313. * @param {boolean} [destroy=false] - If true `destroy` will be invoked on each removed child.
  28314. * @param {boolean} [silent=false] - If true the children will not dispatch their `onRemovedFromGroup` events.
  28315. */
  28316. Phaser.Group.prototype.removeBetween = function (startIndex, endIndex, destroy, silent) {
  28317. if (endIndex === undefined) { endIndex = this.children.length - 1; }
  28318. if (destroy === undefined) { destroy = false; }
  28319. if (silent === undefined) { silent = false; }
  28320. if (this.children.length === 0)
  28321. {
  28322. return;
  28323. }
  28324. if (startIndex > endIndex || startIndex < 0 || endIndex > this.children.length)
  28325. {
  28326. return false;
  28327. }
  28328. var i = endIndex;
  28329. while (i >= startIndex)
  28330. {
  28331. if (!silent && this.children[i].events)
  28332. {
  28333. this.children[i].events.onRemovedFromGroup$dispatch(this.children[i], this);
  28334. }
  28335. var removed = this.removeChild(this.children[i]);
  28336. this.removeFromHash(removed);
  28337. if (destroy && removed)
  28338. {
  28339. removed.destroy(true);
  28340. }
  28341. if (this.cursor === this.children[i])
  28342. {
  28343. this.cursor = null;
  28344. }
  28345. i--;
  28346. }
  28347. this.updateZ();
  28348. };
  28349. /**
  28350. * Places each child at a random position within the given Rectangle (or the {@link Phaser.World#bounds World bounds}).
  28351. *
  28352. * @method Phaser.Group#scatter
  28353. * @param {Phaser.Rectangle} [rect=this.game.world.bounds] - A Rectangle. If omitted {@link Phaser.World#bounds} is used.
  28354. * @param {boolean} [checkExists=false] - Place only children with exists=true.
  28355. */
  28356. Phaser.Group.prototype.scatter = function (rect, checkExists) {
  28357. if (rect == null) { rect = this.game.world.bounds; }
  28358. this.forEach(function (child) {
  28359. child.position.set(rect.randomX, rect.randomY);
  28360. }, null, checkExists);
  28361. };
  28362. /**
  28363. * Orders this Group's children randomly.
  28364. *
  28365. * This can be more efficient than calling {@link #getRandom} repeatedly.
  28366. *
  28367. * @method Phaser.Group#shuffle
  28368. */
  28369. Phaser.Group.prototype.shuffle = function () {
  28370. Phaser.ArrayUtils.shuffle(this.children);
  28371. this.updateZ();
  28372. };
  28373. /**
  28374. * Destroys this group.
  28375. *
  28376. * Removes all children, then removes this group from its parent and nulls references.
  28377. *
  28378. * @method Phaser.Group#destroy
  28379. * @param {boolean} [destroyChildren=true] - If true `destroy` will be invoked on each removed child.
  28380. * @param {boolean} [soft=false] - A 'soft destroy' (set to true) doesn't remove this group from its parent or null the game reference. Set to false and it does.
  28381. */
  28382. Phaser.Group.prototype.destroy = function (destroyChildren, soft) {
  28383. if (this.game === null || this.ignoreDestroy) { return; }
  28384. if (destroyChildren === undefined) { destroyChildren = true; }
  28385. if (soft === undefined) { soft = false; }
  28386. this.onDestroy.dispatch(this, destroyChildren, soft);
  28387. this.removeAll(destroyChildren);
  28388. this.cursor = null;
  28389. this.filters = null;
  28390. this.pendingDestroy = false;
  28391. if (!soft)
  28392. {
  28393. if (this.parent)
  28394. {
  28395. this.parent.removeChild(this);
  28396. }
  28397. this.game = null;
  28398. this.exists = false;
  28399. }
  28400. };
  28401. /**
  28402. * Total number of existing children in the group.
  28403. *
  28404. * @name Phaser.Group#total
  28405. * @property {integer} total
  28406. * @readonly
  28407. */
  28408. Object.defineProperty(Phaser.Group.prototype, "total", {
  28409. get: function () {
  28410. return this.iterate('exists', true, Phaser.Group.RETURN_TOTAL);
  28411. }
  28412. });
  28413. /**
  28414. * Total number of children in this group, regardless of exists/alive status.
  28415. *
  28416. * @name Phaser.Group#length
  28417. * @property {integer} length
  28418. * @readonly
  28419. */
  28420. Object.defineProperty(Phaser.Group.prototype, "length", {
  28421. get: function () {
  28422. return this.children.length;
  28423. }
  28424. });
  28425. /**
  28426. * The angle of rotation of the group container, in degrees.
  28427. *
  28428. * This adjusts the group itself by modifying its local rotation transform.
  28429. *
  28430. * This has no impact on the rotation/angle properties of the children, but it will update their worldTransform
  28431. * and on-screen orientation and position.
  28432. *
  28433. * @name Phaser.Group#angle
  28434. * @property {number} angle
  28435. */
  28436. Object.defineProperty(Phaser.Group.prototype, "angle", {
  28437. get: function() {
  28438. return Phaser.Math.radToDeg(this.rotation);
  28439. },
  28440. set: function(value) {
  28441. this.rotation = Phaser.Math.degToRad(value);
  28442. }
  28443. });
  28444. /**
  28445. * The center x coordinate of this Group.
  28446. *
  28447. * It is derived by calling `getBounds`, calculating the Groups dimensions based on its
  28448. * visible children.
  28449. *
  28450. * @name Phaser.Group#centerX
  28451. * @property {number} centerX
  28452. */
  28453. Object.defineProperty(Phaser.Group.prototype, "centerX", {
  28454. get: function () {
  28455. return this.getBounds(this.parent).centerX;
  28456. },
  28457. set: function (value) {
  28458. var r = this.getBounds(this.parent);
  28459. var offset = this.x - r.x;
  28460. this.x = (value + offset) - r.halfWidth;
  28461. }
  28462. });
  28463. /**
  28464. * The center y coordinate of this Group.
  28465. *
  28466. * It is derived by calling `getBounds`, calculating the Groups dimensions based on its
  28467. * visible children.
  28468. *
  28469. * @name Phaser.Group#centerY
  28470. * @property {number} centerY
  28471. */
  28472. Object.defineProperty(Phaser.Group.prototype, "centerY", {
  28473. get: function () {
  28474. return this.getBounds(this.parent).centerY;
  28475. },
  28476. set: function (value) {
  28477. var r = this.getBounds(this.parent);
  28478. var offset = this.y - r.y;
  28479. this.y = (value + offset) - r.halfHeight;
  28480. }
  28481. });
  28482. /**
  28483. * The left coordinate of this Group.
  28484. *
  28485. * It is derived by calling `getBounds`, calculating the Groups dimensions based on its
  28486. * visible children.
  28487. *
  28488. * @name Phaser.Group#left
  28489. * @property {number} left
  28490. */
  28491. Object.defineProperty(Phaser.Group.prototype, "left", {
  28492. get: function () {
  28493. return this.getBounds(this.parent).left;
  28494. },
  28495. set: function (value) {
  28496. var r = this.getBounds(this.parent);
  28497. var offset = this.x - r.x;
  28498. this.x = value + offset;
  28499. }
  28500. });
  28501. /**
  28502. * The right coordinate of this Group.
  28503. *
  28504. * It is derived by calling `getBounds`, calculating the Groups dimensions based on its
  28505. * visible children.
  28506. *
  28507. * @name Phaser.Group#right
  28508. * @property {number} right
  28509. */
  28510. Object.defineProperty(Phaser.Group.prototype, "right", {
  28511. get: function () {
  28512. return this.getBounds(this.parent).right;
  28513. },
  28514. set: function (value) {
  28515. var r = this.getBounds(this.parent);
  28516. var offset = this.x - r.x;
  28517. this.x = (value + offset) - r.width;
  28518. }
  28519. });
  28520. /**
  28521. * The top coordinate of this Group.
  28522. *
  28523. * It is derived by calling `getBounds`, calculating the Groups dimensions based on its
  28524. * visible children.
  28525. *
  28526. * @name Phaser.Group#top
  28527. * @property {number} top
  28528. */
  28529. Object.defineProperty(Phaser.Group.prototype, "top", {
  28530. get: function () {
  28531. return this.getBounds(this.parent).top;
  28532. },
  28533. set: function (value) {
  28534. var r = this.getBounds(this.parent);
  28535. var offset = this.y - r.y;
  28536. this.y = (value + offset);
  28537. }
  28538. });
  28539. /**
  28540. * The bottom coordinate of this Group.
  28541. *
  28542. * It is derived by calling `getBounds`, calculating the Groups dimensions based on its
  28543. * visible children.
  28544. *
  28545. * @name Phaser.Group#bottom
  28546. * @property {number} bottom
  28547. */
  28548. Object.defineProperty(Phaser.Group.prototype, "bottom", {
  28549. get: function () {
  28550. return this.getBounds(this.parent).bottom;
  28551. },
  28552. set: function (value) {
  28553. var r = this.getBounds(this.parent);
  28554. var offset = this.y - r.y;
  28555. this.y = (value + offset) - r.height;
  28556. }
  28557. });
  28558. /**
  28559. * Aligns this Group within another Game Object, or Rectangle, known as the
  28560. * 'container', to one of 9 possible positions.
  28561. *
  28562. * The container must be a Game Object, or Phaser.Rectangle object. This can include properties
  28563. * such as `World.bounds` or `Camera.view`, for aligning Groups within the world
  28564. * and camera bounds. Or it can include other Sprites, Images, Text objects, BitmapText,
  28565. * TileSprites or Buttons.
  28566. *
  28567. * Please note that aligning a Group to another Game Object does **not** make it a child of
  28568. * the container. It simply modifies its position coordinates so it aligns with it.
  28569. *
  28570. * The position constants you can use are:
  28571. *
  28572. * `Phaser.TOP_LEFT`, `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`,
  28573. * `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`,
  28574. * `Phaser.BOTTOM_CENTER` and `Phaser.BOTTOM_RIGHT`.
  28575. *
  28576. * Groups are placed in such a way that their _bounds_ align with the
  28577. * container, taking into consideration rotation and scale of its children.
  28578. * This allows you to neatly align Groups, irrespective of their position value.
  28579. *
  28580. * The optional `offsetX` and `offsetY` arguments allow you to apply extra spacing to the final
  28581. * aligned position of the Group. For example:
  28582. *
  28583. * `group.alignIn(background, Phaser.BOTTOM_RIGHT, -20, -20)`
  28584. *
  28585. * Would align the `group` to the bottom-right, but moved 20 pixels in from the corner.
  28586. * Think of the offsets as applying an adjustment to the containers bounds before the alignment takes place.
  28587. * So providing a negative offset will 'shrink' the container bounds by that amount, and providing a positive
  28588. * one expands it.
  28589. *
  28590. * @method Phaser.Group#alignIn
  28591. * @param {Phaser.Rectangle|Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Button|Phaser.Graphics|Phaser.TileSprite} container - The Game Object or Rectangle with which to align this Group to. Can also include properties such as `World.bounds` or `Camera.view`.
  28592. * @param {integer} [position] - The position constant. One of `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`, `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`.
  28593. * @param {integer} [offsetX=0] - A horizontal adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  28594. * @param {integer} [offsetY=0] - A vertical adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  28595. * @return {Phaser.Group} This Group.
  28596. */
  28597. // This function is set at the bottom of src/gameobjects/components/Bounds.js
  28598. /**
  28599. * Aligns this Group to the side of another Game Object, or Rectangle, known as the
  28600. * 'parent', in one of 11 possible positions.
  28601. *
  28602. * The parent must be a Game Object, or Phaser.Rectangle object. This can include properties
  28603. * such as `World.bounds` or `Camera.view`, for aligning Groups within the world
  28604. * and camera bounds. Or it can include other Sprites, Images, Text objects, BitmapText,
  28605. * TileSprites or Buttons.
  28606. *
  28607. * Please note that aligning a Group to another Game Object does **not** make it a child of
  28608. * the parent. It simply modifies its position coordinates so it aligns with it.
  28609. *
  28610. * The position constants you can use are:
  28611. *
  28612. * `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_TOP`,
  28613. * `Phaser.LEFT_CENTER`, `Phaser.LEFT_BOTTOM`, `Phaser.RIGHT_TOP`, `Phaser.RIGHT_CENTER`,
  28614. * `Phaser.RIGHT_BOTTOM`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER`
  28615. * and `Phaser.BOTTOM_RIGHT`.
  28616. *
  28617. * Groups are placed in such a way that their _bounds_ align with the
  28618. * parent, taking into consideration rotation and scale of the children.
  28619. * This allows you to neatly align Groups, irrespective of their position value.
  28620. *
  28621. * The optional `offsetX` and `offsetY` arguments allow you to apply extra spacing to the final
  28622. * aligned position of the Group. For example:
  28623. *
  28624. * `group.alignTo(background, Phaser.BOTTOM_RIGHT, -20, -20)`
  28625. *
  28626. * Would align the `group` to the bottom-right, but moved 20 pixels in from the corner.
  28627. * Think of the offsets as applying an adjustment to the parents bounds before the alignment takes place.
  28628. * So providing a negative offset will 'shrink' the parent bounds by that amount, and providing a positive
  28629. * one expands it.
  28630. *
  28631. * @method Phaser.Group#alignTo
  28632. * @param {Phaser.Rectangle|Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Button|Phaser.Graphics|Phaser.TileSprite} parent - The Game Object or Rectangle with which to align this Group to. Can also include properties such as `World.bounds` or `Camera.view`.
  28633. * @param {integer} [position] - The position constant. One of `Phaser.TOP_LEFT`, `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_TOP`, `Phaser.LEFT_CENTER`, `Phaser.LEFT_BOTTOM`, `Phaser.RIGHT_TOP`, `Phaser.RIGHT_CENTER`, `Phaser.RIGHT_BOTTOM`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`.
  28634. * @param {integer} [offsetX=0] - A horizontal adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  28635. * @param {integer} [offsetY=0] - A vertical adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  28636. * @return {Phaser.Group} This Group.
  28637. */
  28638. // This function is set at the bottom of src/gameobjects/components/Bounds.js
  28639. /**
  28640. * A display object is any object that can be rendered in the Phaser/pixi.js scene graph:
  28641. *
  28642. * - {@link PIXI.DisplayObject}
  28643. * - {@link PIXI.DisplayObjectContainer}
  28644. * - {@link Phaser.BitmapText}
  28645. * - {@link Phaser.Creature}
  28646. * - {@link Phaser.Graphics}
  28647. * - {@link Phaser.Group}
  28648. * - {@link Phaser.FlexLayer}
  28649. * - {@link Phaser.Particles.Arcade.Emitter}
  28650. * - {@link Phaser.Physics.P2.BodyDebug}
  28651. * - {@link Phaser.SpriteBatch}
  28652. * - {@link Phaser.World}
  28653. * - {@link Phaser.Rope}
  28654. * - {@link Phaser.Stage}
  28655. * - {@link PIXI.Sprite}
  28656. * - {@link Phaser.Image}
  28657. * - {@link Phaser.Button}
  28658. * - {@link Phaser.Sprite}
  28659. * - {@link Phaser.Bullet}
  28660. * - {@link Phaser.Particle}
  28661. * - {@link Phaser.Text}
  28662. * - {@link Phaser.TilemapLayer}
  28663. * - {@link Phaser.TileSprite}
  28664. *
  28665. * @typedef {object} DisplayObject
  28666. */
  28667. // Documentation stub for linking.
  28668. /**
  28669. * The x coordinate of the group container.
  28670. *
  28671. * You can adjust the group container itself by modifying its coordinates.
  28672. * This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position.
  28673. * @name Phaser.Group#x
  28674. * @property {number} x
  28675. */
  28676. /**
  28677. * The y coordinate of the group container.
  28678. *
  28679. * You can adjust the group container itself by modifying its coordinates.
  28680. * This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position.
  28681. * @name Phaser.Group#y
  28682. * @property {number} y
  28683. */
  28684. /**
  28685. * The angle of rotation of the group container, in radians.
  28686. *
  28687. * This will adjust the group container itself by modifying its rotation.
  28688. * This will have no impact on the rotation value of its children, but it will update their worldTransform and on-screen position.
  28689. * @name Phaser.Group#rotation
  28690. * @property {number} rotation
  28691. */
  28692. /**
  28693. * The visible state of the group. Non-visible Groups and all of their children are not rendered.
  28694. *
  28695. * @name Phaser.Group#visible
  28696. * @property {boolean} visible
  28697. */
  28698. /**
  28699. * The alpha value of the group container.
  28700. *
  28701. * @name Phaser.Group#alpha
  28702. * @property {number} alpha
  28703. */
  28704. /**
  28705. * @author Richard Davey <rich@photonstorm.com>
  28706. * @copyright 2016 Photon Storm Ltd.
  28707. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  28708. */
  28709. /**
  28710. * "This world is but a canvas to our imagination." - Henry David Thoreau
  28711. *
  28712. * A game has only one world. The world is an abstract place in which all game objects live. It is not bound
  28713. * by stage limits and can be any size. You look into the world via cameras. All game objects live within
  28714. * the world at world-based coordinates. By default a world is created the same size as your Stage.
  28715. *
  28716. * @class Phaser.World
  28717. * @extends Phaser.Group
  28718. * @constructor
  28719. * @param {Phaser.Game} game - Reference to the current game instance.
  28720. */
  28721. Phaser.World = function (game) {
  28722. Phaser.Group.call(this, game, null, '__world', false);
  28723. /**
  28724. * The World has no fixed size, but it does have a bounds outside of which objects are no longer considered as being "in world" and you should use this to clean-up the display list and purge dead objects.
  28725. * By default we set the Bounds to be from 0,0 to Game.width,Game.height. I.e. it will match the size given to the game constructor with 0,0 representing the top-left of the display.
  28726. * However 0,0 is actually the center of the world, and if you rotate or scale the world all of that will happen from 0,0.
  28727. * So if you want to make a game in which the world itself will rotate you should adjust the bounds so that 0,0 is the center point, i.e. set them to -1000,-1000,2000,2000 for a 2000x2000 sized world centered around 0,0.
  28728. * @property {Phaser.Rectangle} bounds - Bound of this world that objects can not escape from.
  28729. */
  28730. this.bounds = new Phaser.Rectangle(0, 0, game.width, game.height);
  28731. /**
  28732. * @property {Phaser.Camera} camera - Camera instance.
  28733. */
  28734. this.camera = null;
  28735. /**
  28736. * @property {boolean} _definedSize - True if the World has been given a specifically defined size (i.e. from a Tilemap or direct in code) or false if it's just matched to the Game dimensions.
  28737. * @readonly
  28738. */
  28739. this._definedSize = false;
  28740. /**
  28741. * @property {number} width - The defined width of the World. Sometimes the bounds needs to grow larger than this (if you resize the game) but this retains the original requested dimension.
  28742. */
  28743. this._width = game.width;
  28744. /**
  28745. * @property {number} height - The defined height of the World. Sometimes the bounds needs to grow larger than this (if you resize the game) but this retains the original requested dimension.
  28746. */
  28747. this._height = game.height;
  28748. this.game.state.onStateChange.add(this.stateChange, this);
  28749. };
  28750. Phaser.World.prototype = Object.create(Phaser.Group.prototype);
  28751. Phaser.World.prototype.constructor = Phaser.World;
  28752. /**
  28753. * Initialises the game world.
  28754. *
  28755. * @method Phaser.World#boot
  28756. * @protected
  28757. */
  28758. Phaser.World.prototype.boot = function () {
  28759. this.camera = new Phaser.Camera(this.game, 0, 0, 0, this.game.width, this.game.height);
  28760. this.game.stage.addChild(this);
  28761. this.camera.boot();
  28762. };
  28763. /**
  28764. * Called whenever the State changes or resets.
  28765. *
  28766. * It resets the world.x and world.y coordinates back to zero,
  28767. * then resets the Camera.
  28768. *
  28769. * @method Phaser.World#stateChange
  28770. * @protected
  28771. */
  28772. Phaser.World.prototype.stateChange = function () {
  28773. this.x = 0;
  28774. this.y = 0;
  28775. this.camera.reset();
  28776. };
  28777. /**
  28778. * Updates the size of this world and sets World.x/y to the given values
  28779. * The Camera bounds and Physics bounds (if set) are also updated to match the new World bounds.
  28780. *
  28781. * @method Phaser.World#setBounds
  28782. * @param {number} x - Top left most corner of the world.
  28783. * @param {number} y - Top left most corner of the world.
  28784. * @param {number} width - New width of the game world in pixels.
  28785. * @param {number} height - New height of the game world in pixels.
  28786. */
  28787. Phaser.World.prototype.setBounds = function (x, y, width, height) {
  28788. this._definedSize = true;
  28789. this._width = width;
  28790. this._height = height;
  28791. this.bounds.setTo(x, y, width, height);
  28792. this.x = x;
  28793. this.y = y;
  28794. if (this.camera.bounds)
  28795. {
  28796. // The Camera can never be smaller than the game size
  28797. this.camera.bounds.setTo(x, y, Math.max(width, this.game.width), Math.max(height, this.game.height));
  28798. }
  28799. this.game.physics.setBoundsToWorld();
  28800. };
  28801. /**
  28802. * Updates the size of this world. Note that this doesn't modify the world x/y coordinates, just the width and height.
  28803. *
  28804. * @method Phaser.World#resize
  28805. * @param {number} width - New width of the game world in pixels.
  28806. * @param {number} height - New height of the game world in pixels.
  28807. */
  28808. Phaser.World.prototype.resize = function (width, height) {
  28809. // Don't ever scale the World bounds lower than the original requested dimensions if it's a defined world size
  28810. if (this._definedSize)
  28811. {
  28812. if (width < this._width)
  28813. {
  28814. width = this._width;
  28815. }
  28816. if (height < this._height)
  28817. {
  28818. height = this._height;
  28819. }
  28820. }
  28821. this.bounds.width = width;
  28822. this.bounds.height = height;
  28823. this.game.camera.setBoundsToWorld();
  28824. this.game.physics.setBoundsToWorld();
  28825. };
  28826. /**
  28827. * Destroyer of worlds.
  28828. *
  28829. * @method Phaser.World#shutdown
  28830. */
  28831. Phaser.World.prototype.shutdown = function () {
  28832. // World is a Group, so run a soft destruction on this and all children.
  28833. this.destroy(true, true);
  28834. };
  28835. /**
  28836. * This will take the given game object and check if its x/y coordinates fall outside of the world bounds.
  28837. * If they do it will reposition the object to the opposite side of the world, creating a wrap-around effect.
  28838. * If sprite has a P2 body then the body (sprite.body) should be passed as first parameter to the function.
  28839. *
  28840. * Please understand there are limitations to this method. For example if you have scaled the World
  28841. * then objects won't always be re-positioned correctly, and you'll need to employ your own wrapping function.
  28842. *
  28843. * @method Phaser.World#wrap
  28844. * @param {Phaser.Sprite|Phaser.Image|Phaser.TileSprite|Phaser.Text} sprite - The object you wish to wrap around the world bounds.
  28845. * @param {number} [padding=0] - Extra padding added equally to the sprite.x and y coordinates before checking if within the world bounds. Ignored if useBounds is true.
  28846. * @param {boolean} [useBounds=false] - If useBounds is false wrap checks the object.x/y coordinates. If true it does a more accurate bounds check, which is more expensive.
  28847. * @param {boolean} [horizontal=true] - If horizontal is false, wrap will not wrap the object.x coordinates horizontally.
  28848. * @param {boolean} [vertical=true] - If vertical is false, wrap will not wrap the object.y coordinates vertically.
  28849. */
  28850. Phaser.World.prototype.wrap = function (sprite, padding, useBounds, horizontal, vertical) {
  28851. if (padding === undefined) { padding = 0; }
  28852. if (useBounds === undefined) { useBounds = false; }
  28853. if (horizontal === undefined) { horizontal = true; }
  28854. if (vertical === undefined) { vertical = true; }
  28855. if (!useBounds)
  28856. {
  28857. if (horizontal && sprite.x + padding < this.bounds.x)
  28858. {
  28859. sprite.x = this.bounds.right + padding;
  28860. }
  28861. else if (horizontal && sprite.x - padding > this.bounds.right)
  28862. {
  28863. sprite.x = this.bounds.left - padding;
  28864. }
  28865. if (vertical && sprite.y + padding < this.bounds.top)
  28866. {
  28867. sprite.y = this.bounds.bottom + padding;
  28868. }
  28869. else if (vertical && sprite.y - padding > this.bounds.bottom)
  28870. {
  28871. sprite.y = this.bounds.top - padding;
  28872. }
  28873. }
  28874. else
  28875. {
  28876. sprite.getBounds();
  28877. if (horizontal)
  28878. {
  28879. if ((sprite.x + sprite._currentBounds.width) < this.bounds.x)
  28880. {
  28881. sprite.x = this.bounds.right;
  28882. }
  28883. else if (sprite.x > this.bounds.right)
  28884. {
  28885. sprite.x = this.bounds.left;
  28886. }
  28887. }
  28888. if (vertical)
  28889. {
  28890. if ((sprite.y + sprite._currentBounds.height) < this.bounds.top)
  28891. {
  28892. sprite.y = this.bounds.bottom;
  28893. }
  28894. else if (sprite.y > this.bounds.bottom)
  28895. {
  28896. sprite.y = this.bounds.top;
  28897. }
  28898. }
  28899. }
  28900. };
  28901. /**
  28902. * @name Phaser.World#width
  28903. * @property {number} width - Gets or sets the current width of the game world. The world can never be smaller than the game (canvas) dimensions.
  28904. */
  28905. Object.defineProperty(Phaser.World.prototype, "width", {
  28906. get: function () {
  28907. return this.bounds.width;
  28908. },
  28909. set: function (value) {
  28910. if (value < this.game.width)
  28911. {
  28912. value = this.game.width;
  28913. }
  28914. this.bounds.width = value;
  28915. this._width = value;
  28916. this._definedSize = true;
  28917. }
  28918. });
  28919. /**
  28920. * @name Phaser.World#height
  28921. * @property {number} height - Gets or sets the current height of the game world. The world can never be smaller than the game (canvas) dimensions.
  28922. */
  28923. Object.defineProperty(Phaser.World.prototype, "height", {
  28924. get: function () {
  28925. return this.bounds.height;
  28926. },
  28927. set: function (value) {
  28928. if (value < this.game.height)
  28929. {
  28930. value = this.game.height;
  28931. }
  28932. this.bounds.height = value;
  28933. this._height = value;
  28934. this._definedSize = true;
  28935. }
  28936. });
  28937. /**
  28938. * @name Phaser.World#centerX
  28939. * @property {number} centerX - Gets the X position corresponding to the center point of the world.
  28940. * @readonly
  28941. */
  28942. Object.defineProperty(Phaser.World.prototype, "centerX", {
  28943. get: function () {
  28944. return this.bounds.halfWidth + this.bounds.x;
  28945. }
  28946. });
  28947. /**
  28948. * @name Phaser.World#centerY
  28949. * @property {number} centerY - Gets the Y position corresponding to the center point of the world.
  28950. * @readonly
  28951. */
  28952. Object.defineProperty(Phaser.World.prototype, "centerY", {
  28953. get: function () {
  28954. return this.bounds.halfHeight + this.bounds.y;
  28955. }
  28956. });
  28957. /**
  28958. * @name Phaser.World#randomX
  28959. * @property {number} randomX - Gets a random integer which is lesser than or equal to the current width of the game world.
  28960. * @readonly
  28961. */
  28962. Object.defineProperty(Phaser.World.prototype, "randomX", {
  28963. get: function () {
  28964. if (this.bounds.x < 0)
  28965. {
  28966. return this.game.rnd.between(this.bounds.x, (this.bounds.width - Math.abs(this.bounds.x)));
  28967. }
  28968. else
  28969. {
  28970. return this.game.rnd.between(this.bounds.x, this.bounds.width);
  28971. }
  28972. }
  28973. });
  28974. /**
  28975. * @name Phaser.World#randomY
  28976. * @property {number} randomY - Gets a random integer which is lesser than or equal to the current height of the game world.
  28977. * @readonly
  28978. */
  28979. Object.defineProperty(Phaser.World.prototype, "randomY", {
  28980. get: function () {
  28981. if (this.bounds.y < 0)
  28982. {
  28983. return this.game.rnd.between(this.bounds.y, (this.bounds.height - Math.abs(this.bounds.y)));
  28984. }
  28985. else
  28986. {
  28987. return this.game.rnd.between(this.bounds.y, this.bounds.height);
  28988. }
  28989. }
  28990. });
  28991. /**
  28992. * @author Richard Davey <rich@photonstorm.com>
  28993. * @copyright 2016 Photon Storm Ltd.
  28994. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  28995. */
  28996. /**
  28997. * The Phaser.Game object is the main controller for the entire Phaser game. It is responsible
  28998. * for handling the boot process, parsing the configuration values, creating the renderer,
  28999. * and setting-up all of the Phaser systems, such as physics, sound and input.
  29000. * Once that is complete it will start the default State, and then begin the main game loop.
  29001. *
  29002. * You can access lots of the Phaser systems via the properties on the `game` object. For
  29003. * example `game.renderer` is the Renderer, `game.sound` is the Sound Manager, and so on.
  29004. *
  29005. * Anywhere you can access the `game` property, you can access all of these core systems.
  29006. * For example a Sprite has a `game` property, allowing you to talk to the various parts
  29007. * of Phaser directly, without having to look after your own references.
  29008. *
  29009. * In it's most simplest form, a Phaser game can be created by providing the arguments
  29010. * to the constructor:
  29011. *
  29012. * ```javascript
  29013. * var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create });
  29014. * ```
  29015. *
  29016. * In the example above it is passing in a State object directly. You can also use the State
  29017. * Manager to do this:
  29018. *
  29019. * ```javascript
  29020. * var game = new Phaser.Game(800, 600, Phaser.AUTO);
  29021. * game.state.add('Boot', BasicGame.Boot);
  29022. * game.state.add('Preloader', BasicGame.Preloader);
  29023. * game.state.add('MainMenu', BasicGame.MainMenu);
  29024. * game.state.add('Game', BasicGame.Game);
  29025. * game.state.start('Boot');
  29026. * ```
  29027. *
  29028. * In the example above, 4 States are added to the State Manager, and Phaser is told to
  29029. * start running the `Boot` state when it has finished initializing. There are example
  29030. * project templates you can use in the Phaser GitHub repo, inside the `resources` folder.
  29031. *
  29032. * Instead of specifying arguments you can also pass {@link GameConfig a single object} instead:
  29033. *
  29034. * ```javascript
  29035. * var config = {
  29036. * width: 800,
  29037. * height: 600,
  29038. * renderer: Phaser.AUTO,
  29039. * antialias: true,
  29040. * multiTexture: true,
  29041. * state: {
  29042. * preload: preload,
  29043. * create: create,
  29044. * update: update
  29045. * }
  29046. * }
  29047. *
  29048. * var game = new Phaser.Game(config);
  29049. * ```
  29050. *
  29051. * @class Phaser.Game
  29052. * @constructor
  29053. * @param {number|string|GameConfig} [width=800] - The width of your game in game pixels. If given as a string the value must be between 0 and 100 and will be used as the percentage width of the parent container, or the browser window if no parent is given.
  29054. * @param {number|string} [height=600] - The height of your game in game pixels. If given as a string the value must be between 0 and 100 and will be used as the percentage height of the parent container, or the browser window if no parent is given.
  29055. * @param {number} [renderer=Phaser.AUTO] - Which renderer to use: Phaser.AUTO will auto-detect, Phaser.WEBGL, Phaser.WEBGL_MULTI, Phaser.CANVAS or Phaser.HEADLESS (no rendering at all).
  29056. * @param {string|HTMLElement} [parent=''] - The DOM element into which this games canvas will be injected. Either a DOM ID (string) or the element itself.
  29057. * @param {object} [state=null] - The default state object. A object consisting of Phaser.State functions (preload, create, update, render) or null.
  29058. * @param {boolean} [transparent=false] - Use a transparent canvas background or not.
  29059. * @param {boolean} [antialias=true] - Draw all image textures anti-aliased or not. The default is for smooth textures, but disable if your game features pixel art.
  29060. * @param {object} [physicsConfig=null] - A physics configuration object to pass to the Physics world on creation.
  29061. */
  29062. Phaser.Game = function (width, height, renderer, parent, state, transparent, antialias, physicsConfig) {
  29063. /**
  29064. * @property {number} id - Phaser Game ID
  29065. * @readonly
  29066. */
  29067. this.id = Phaser.GAMES.push(this) - 1;
  29068. /**
  29069. * @property {object} config - The Phaser.Game configuration object.
  29070. */
  29071. this.config = null;
  29072. /**
  29073. * @property {object} physicsConfig - The Phaser.Physics.World configuration object.
  29074. */
  29075. this.physicsConfig = physicsConfig;
  29076. /**
  29077. * @property {string|HTMLElement} parent - The Game's DOM parent (or name thereof), if any, as set when the game was created. The actual parent can be found in `game.canvas.parentNode`. Setting this has no effect after {@link Phaser.ScaleManager} is booted.
  29078. * @readonly
  29079. * @default
  29080. */
  29081. this.parent = '';
  29082. /**
  29083. * The current Game Width in pixels.
  29084. *
  29085. * _Do not modify this property directly:_ use {@link Phaser.ScaleManager#setGameSize} - e.g. `game.scale.setGameSize(width, height)` - instead.
  29086. *
  29087. * @property {integer} width
  29088. * @readonly
  29089. * @default
  29090. */
  29091. this.width = 800;
  29092. /**
  29093. * The current Game Height in pixels.
  29094. *
  29095. * _Do not modify this property directly:_ use {@link Phaser.ScaleManager#setGameSize} - e.g. `game.scale.setGameSize(width, height)` - instead.
  29096. *
  29097. * @property {integer} height
  29098. * @readonly
  29099. * @default
  29100. */
  29101. this.height = 600;
  29102. /**
  29103. * The resolution of your game, as a ratio of canvas pixels to game pixels. This value is read only, but can be changed at start time it via a game configuration object.
  29104. *
  29105. * @property {integer} resolution
  29106. * @readonly
  29107. * @default
  29108. */
  29109. this.resolution = 1;
  29110. /**
  29111. * @property {integer} _width - Private internal var.
  29112. * @private
  29113. */
  29114. this._width = 800;
  29115. /**
  29116. * @property {integer} _height - Private internal var.
  29117. * @private
  29118. */
  29119. this._height = 600;
  29120. /**
  29121. * @property {boolean} transparent - Use a transparent canvas background or not.
  29122. * @default
  29123. */
  29124. this.transparent = false;
  29125. /**
  29126. * @property {boolean} antialias - Anti-alias graphics (as set when the Game is created). By default scaled and rotated images are smoothed in Canvas and WebGL; set `antialias` to false to disable this globally. After the game boots, use `game.stage.smoothed` instead.
  29127. * @readonly
  29128. * @default
  29129. */
  29130. this.antialias = true;
  29131. /**
  29132. * Has support for Multiple bound Textures in WebGL been enabled? This is a read-only property.
  29133. * To set it you need to either specify `Phaser.WEBGL_MULTI` as the renderer type, or use the Game
  29134. * Configuration object with the property `multiTexture` set to true. It has to be enabled before
  29135. * Pixi boots, and cannot be changed after the game is running. Once enabled, take advantage of it
  29136. * via the `game.renderer.setTexturePriority` method.
  29137. *
  29138. * @property {boolean} multiTexture
  29139. * @readonly
  29140. * @default
  29141. */
  29142. this.multiTexture = false;
  29143. /**
  29144. * @property {boolean} preserveDrawingBuffer - The value of the preserveDrawingBuffer flag affects whether or not the contents of the stencil buffer is retained after rendering.
  29145. * @default
  29146. */
  29147. this.preserveDrawingBuffer = false;
  29148. /**
  29149. * Clear the Canvas each frame before rendering the display list.
  29150. * You can set this to `false` to gain some performance if your game always contains a background that completely fills the display.
  29151. * This must be `true` to show any {@link Phaser.Stage#backgroundColor} set on the Stage.
  29152. * @property {boolean} clearBeforeRender
  29153. * @default
  29154. */
  29155. this.clearBeforeRender = true;
  29156. /**
  29157. * @property {PIXI.CanvasRenderer|PIXI.WebGLRenderer} renderer - The Pixi Renderer.
  29158. * @protected
  29159. */
  29160. this.renderer = null;
  29161. /**
  29162. * @property {number} renderType - The Renderer this game will use. Either Phaser.AUTO, Phaser.CANVAS, Phaser.WEBGL, Phaser.WEBGL_MULTI or Phaser.HEADLESS. After the game boots, renderType reflects the renderer in use: AUTO changes to CANVAS or WEBGL and WEBGL_MULTI changes to WEBGL. HEADLESS skips `render` hooks but not `preRender` or `postRender`; set {@link lockRender} to skip those as well.
  29163. * @readonly
  29164. */
  29165. this.renderType = Phaser.AUTO;
  29166. /**
  29167. * @property {Phaser.StateManager} state - The StateManager.
  29168. */
  29169. this.state = null;
  29170. /**
  29171. * @property {boolean} isBooted - Whether the game engine is booted, aka available.
  29172. * @readonly
  29173. */
  29174. this.isBooted = false;
  29175. /**
  29176. * @property {boolean} isRunning - Is game running or paused?
  29177. * @readonly
  29178. */
  29179. this.isRunning = false;
  29180. /**
  29181. * @property {Phaser.RequestAnimationFrame} raf - Automatically handles the core game loop via requestAnimationFrame or setTimeout
  29182. * @protected
  29183. */
  29184. this.raf = null;
  29185. /**
  29186. * @property {Phaser.GameObjectFactory} add - Reference to the Phaser.GameObjectFactory.
  29187. */
  29188. this.add = null;
  29189. /**
  29190. * @property {Phaser.GameObjectCreator} make - Reference to the GameObject Creator.
  29191. */
  29192. this.make = null;
  29193. /**
  29194. * @property {Phaser.Cache} cache - Reference to the assets cache.
  29195. */
  29196. this.cache = null;
  29197. /**
  29198. * @property {Phaser.Input} input - Reference to the input manager
  29199. */
  29200. this.input = null;
  29201. /**
  29202. * @property {Phaser.Loader} load - Reference to the assets loader.
  29203. */
  29204. this.load = null;
  29205. /**
  29206. * @property {Phaser.Math} math - Reference to the math helper.
  29207. */
  29208. this.math = null;
  29209. /**
  29210. * @property {Phaser.Net} net - Reference to the network class.
  29211. */
  29212. this.net = null;
  29213. /**
  29214. * @property {Phaser.ScaleManager} scale - The game scale manager.
  29215. */
  29216. this.scale = null;
  29217. /**
  29218. * @property {Phaser.SoundManager} sound - Reference to the sound manager.
  29219. */
  29220. this.sound = null;
  29221. /**
  29222. * @property {Phaser.Stage} stage - Reference to the stage.
  29223. */
  29224. this.stage = null;
  29225. /**
  29226. * @property {Phaser.Time} time - Reference to the core game clock.
  29227. */
  29228. this.time = null;
  29229. /**
  29230. * @property {Phaser.TweenManager} tweens - Reference to the tween manager.
  29231. */
  29232. this.tweens = null;
  29233. /**
  29234. * @property {Phaser.World} world - Reference to the world.
  29235. */
  29236. this.world = null;
  29237. /**
  29238. * @property {Phaser.Physics} physics - Reference to the physics manager.
  29239. */
  29240. this.physics = null;
  29241. /**
  29242. * @property {Phaser.PluginManager} plugins - Reference to the plugin manager.
  29243. */
  29244. this.plugins = null;
  29245. /**
  29246. * @property {Phaser.RandomDataGenerator} rnd - Instance of repeatable random data generator helper.
  29247. */
  29248. this.rnd = null;
  29249. /**
  29250. * @property {Phaser.Device} device - Contains device information and capabilities.
  29251. */
  29252. this.device = Phaser.Device;
  29253. /**
  29254. * @property {Phaser.Camera} camera - A handy reference to world.camera.
  29255. */
  29256. this.camera = null;
  29257. /**
  29258. * @property {HTMLCanvasElement} canvas - A handy reference to renderer.view, the canvas that the game is being rendered in to.
  29259. */
  29260. this.canvas = null;
  29261. /**
  29262. * @property {CanvasRenderingContext2D} context - A handy reference to renderer.context (only set for CANVAS games, not WebGL)
  29263. */
  29264. this.context = null;
  29265. /**
  29266. * @property {Phaser.Utils.Debug} debug - A set of useful debug utilities.
  29267. */
  29268. this.debug = null;
  29269. /**
  29270. * @property {Phaser.Particles} particles - The Particle Manager.
  29271. */
  29272. this.particles = null;
  29273. /**
  29274. * @property {Phaser.Create} create - The Asset Generator.
  29275. */
  29276. this.create = null;
  29277. /**
  29278. * If `false` Phaser will automatically render the display list every update. If `true` the render loop will be skipped.
  29279. * You can toggle this value at run-time to gain exact control over when Phaser renders. This can be useful in certain types of game or application.
  29280. * Please note that if you don't render the display list then none of the game object transforms will be updated, so use this value carefully.
  29281. * @property {boolean} lockRender
  29282. * @default
  29283. */
  29284. this.lockRender = false;
  29285. /**
  29286. * @property {boolean} stepping - Enable core loop stepping with Game.enableStep().
  29287. * @default
  29288. * @readonly
  29289. */
  29290. this.stepping = false;
  29291. /**
  29292. * @property {boolean} pendingStep - An internal property used by enableStep, but also useful to query from your own game objects.
  29293. * @default
  29294. * @readonly
  29295. */
  29296. this.pendingStep = false;
  29297. /**
  29298. * @property {number} stepCount - When stepping is enabled this contains the current step cycle.
  29299. * @default
  29300. * @readonly
  29301. */
  29302. this.stepCount = 0;
  29303. /**
  29304. * @property {Phaser.Signal} onPause - This event is fired when the game pauses.
  29305. */
  29306. this.onPause = null;
  29307. /**
  29308. * @property {Phaser.Signal} onResume - This event is fired when the game resumes from a paused state.
  29309. */
  29310. this.onResume = null;
  29311. /**
  29312. * @property {Phaser.Signal} onBlur - This event is fired when the game no longer has focus (typically on page hide).
  29313. */
  29314. this.onBlur = null;
  29315. /**
  29316. * @property {Phaser.Signal} onFocus - This event is fired when the game has focus (typically on page show).
  29317. */
  29318. this.onFocus = null;
  29319. /**
  29320. * @property {boolean} _paused - Is game paused?
  29321. * @private
  29322. */
  29323. this._paused = false;
  29324. /**
  29325. * @property {boolean} _codePaused - Was the game paused via code or a visibility change?
  29326. * @private
  29327. */
  29328. this._codePaused = false;
  29329. /**
  29330. * The ID of the current/last logic update applied this render frame, starting from 0.
  29331. * The first update is `currentUpdateID === 0` and the last update is `currentUpdateID === updatesThisFrame.`
  29332. * @property {integer} currentUpdateID
  29333. * @protected
  29334. */
  29335. this.currentUpdateID = 0;
  29336. /**
  29337. * Number of logic updates expected to occur this render frame; will be 1 unless there are catch-ups required (and allowed).
  29338. * @property {integer} updatesThisFrame
  29339. * @protected
  29340. */
  29341. this.updatesThisFrame = 1;
  29342. /**
  29343. * @property {number} _deltaTime - Accumulate elapsed time until a logic update is due.
  29344. * @private
  29345. */
  29346. this._deltaTime = 0;
  29347. /**
  29348. * @property {number} _lastCount - Remember how many 'catch-up' iterations were used on the logicUpdate last frame.
  29349. * @private
  29350. */
  29351. this._lastCount = 0;
  29352. /**
  29353. * @property {number} _spiraling - If the 'catch-up' iterations are spiraling out of control, this counter is incremented.
  29354. * @private
  29355. */
  29356. this._spiraling = 0;
  29357. /**
  29358. * @property {boolean} _kickstart - Force a logic update + render by default (always set on Boot and State swap)
  29359. * @private
  29360. */
  29361. this._kickstart = true;
  29362. /**
  29363. * If the game is struggling to maintain the desired FPS, this signal will be dispatched.
  29364. * The desired/chosen FPS should probably be closer to the {@link Phaser.Time#suggestedFps} value.
  29365. * @property {Phaser.Signal} fpsProblemNotifier
  29366. * @public
  29367. */
  29368. this.fpsProblemNotifier = new Phaser.Signal();
  29369. /**
  29370. * @property {boolean} forceSingleUpdate - Should the game loop force a logic update, regardless of the delta timer? You can toggle it on the fly.
  29371. */
  29372. this.forceSingleUpdate = true;
  29373. /**
  29374. * @property {number} _nextNotification - The soonest game.time.time value that the next fpsProblemNotifier can be dispatched.
  29375. * @private
  29376. */
  29377. this._nextFpsNotification = 0;
  29378. // Parse the configuration object (if any)
  29379. if (arguments.length === 1 && typeof arguments[0] === 'object')
  29380. {
  29381. this.parseConfig(arguments[0]);
  29382. }
  29383. else
  29384. {
  29385. this.config = { enableDebug: true };
  29386. if (typeof width !== 'undefined')
  29387. {
  29388. this._width = width;
  29389. }
  29390. if (typeof height !== 'undefined')
  29391. {
  29392. this._height = height;
  29393. }
  29394. if (typeof renderer !== 'undefined')
  29395. {
  29396. this.renderType = renderer;
  29397. }
  29398. if (typeof parent !== 'undefined')
  29399. {
  29400. this.parent = parent;
  29401. }
  29402. if (typeof transparent !== 'undefined')
  29403. {
  29404. this.transparent = transparent;
  29405. }
  29406. if (typeof antialias !== 'undefined')
  29407. {
  29408. this.antialias = antialias;
  29409. }
  29410. this.rnd = new Phaser.RandomDataGenerator([(Date.now() * Math.random()).toString()]);
  29411. this.state = new Phaser.StateManager(this, state);
  29412. }
  29413. this.device.whenReady(this.boot, this);
  29414. return this;
  29415. };
  29416. /**
  29417. * A configuration object for {@link Phaser.Game}.
  29418. *
  29419. * @typedef {object} GameConfig
  29420. * @property {number|string} [GameConfig.antialias=true]
  29421. * @property {string} [GameConfig.backgroundColor=0] - Sets {@link Phaser.Stage#backgroundColor}.
  29422. * @property {boolean} [GameConfig.disableVisibilityChange=false] - Sets {@link Phaser.Stage#disableVisibilityChange}
  29423. * @property {number|string} [GameConfig.height=600]
  29424. * @property {boolean} [GameConfig.enableDebug=true] - Enable {@link Phaser.Utils.Debug}. You can gain a little performance by disabling this in production.
  29425. * @property {number} [GameConfig.fullScreenScaleMode] - The scaling method used by the ScaleManager when in fullscreen.
  29426. * @property {DOMElement} [GameConfig.fullScreenTarget] - The DOM element on which the Fullscreen API enter request will be invoked.
  29427. * @property {boolean} [GameConfig.multiTexture=false] - Enable support for multiple bound Textures in WebGL. Same as `{renderer: Phaser.WEBGL_MULTI}`.
  29428. * @property {string|HTMLElement} [GameConfig.parent='']
  29429. * @property {object} [GameConfig.physicsConfig=null]
  29430. * @property {boolean} [GameConfig.preserveDrawingBuffer=false] - Whether or not the contents of the stencil buffer is retained after rendering.
  29431. * @property {number} [GameConfig.renderer=Phaser.AUTO]
  29432. * @property {number} [GameConfig.resolution=1] - The resolution of your game, as a ratio of canvas pixels to game pixels.
  29433. * @property {number} [GameConfig.scaleMode] - The scaling method used by the ScaleManager when not in fullscreen.
  29434. * @property {number} [GameConfig.seed] - Seed for {@link Phaser.RandomDataGenerator}.
  29435. * @property {object} [GameConfig.state=null]
  29436. * @property {boolean} [GameConfig.transparent=false]
  29437. * @property {number|string} [GameConfig.width=800]
  29438. */
  29439. // Documentation stub for linking.
  29440. Phaser.Game.prototype = {
  29441. /**
  29442. * Parses a Game configuration object.
  29443. *
  29444. * @method Phaser.Game#parseConfig
  29445. * @protected
  29446. */
  29447. parseConfig: function (config) {
  29448. this.config = config;
  29449. if (config['enableDebug'] === undefined)
  29450. {
  29451. this.config.enableDebug = true;
  29452. }
  29453. if (config['width'])
  29454. {
  29455. this._width = config['width'];
  29456. }
  29457. if (config['height'])
  29458. {
  29459. this._height = config['height'];
  29460. }
  29461. if (config['renderer'])
  29462. {
  29463. this.renderType = config['renderer'];
  29464. }
  29465. if (config['parent'])
  29466. {
  29467. this.parent = config['parent'];
  29468. }
  29469. if (config['transparent'] !== undefined)
  29470. {
  29471. this.transparent = config['transparent'];
  29472. }
  29473. if (config['antialias'] !== undefined)
  29474. {
  29475. this.antialias = config['antialias'];
  29476. }
  29477. if (config['multiTexture'] !== undefined)
  29478. {
  29479. this.multiTexture = config['multiTexture'];
  29480. }
  29481. if (config['resolution'])
  29482. {
  29483. this.resolution = config['resolution'];
  29484. }
  29485. if (config['preserveDrawingBuffer'] !== undefined)
  29486. {
  29487. this.preserveDrawingBuffer = config['preserveDrawingBuffer'];
  29488. }
  29489. if (config['physicsConfig'])
  29490. {
  29491. this.physicsConfig = config['physicsConfig'];
  29492. }
  29493. var seed = [(Date.now() * Math.random()).toString()];
  29494. if (config['seed'])
  29495. {
  29496. seed = config['seed'];
  29497. }
  29498. this.rnd = new Phaser.RandomDataGenerator(seed);
  29499. var state = null;
  29500. if (config['state'])
  29501. {
  29502. state = config['state'];
  29503. }
  29504. this.state = new Phaser.StateManager(this, state);
  29505. },
  29506. /**
  29507. * Initialize engine sub modules and start the game.
  29508. *
  29509. * @method Phaser.Game#boot
  29510. * @protected
  29511. */
  29512. boot: function () {
  29513. if (this.isBooted)
  29514. {
  29515. return;
  29516. }
  29517. this.onPause = new Phaser.Signal();
  29518. this.onResume = new Phaser.Signal();
  29519. this.onBlur = new Phaser.Signal();
  29520. this.onFocus = new Phaser.Signal();
  29521. this.isBooted = true;
  29522. PIXI.game = this;
  29523. this.math = Phaser.Math;
  29524. this.scale = new Phaser.ScaleManager(this, this._width, this._height);
  29525. this.stage = new Phaser.Stage(this);
  29526. this.setUpRenderer();
  29527. this.world = new Phaser.World(this);
  29528. this.add = new Phaser.GameObjectFactory(this);
  29529. this.make = new Phaser.GameObjectCreator(this);
  29530. this.cache = new Phaser.Cache(this);
  29531. this.load = new Phaser.Loader(this);
  29532. this.time = new Phaser.Time(this);
  29533. this.tweens = new Phaser.TweenManager(this);
  29534. this.input = new Phaser.Input(this);
  29535. this.sound = new Phaser.SoundManager(this);
  29536. this.physics = new Phaser.Physics(this, this.physicsConfig);
  29537. this.particles = new Phaser.Particles(this);
  29538. this.create = new Phaser.Create(this);
  29539. this.plugins = new Phaser.PluginManager(this);
  29540. this.net = new Phaser.Net(this);
  29541. this.time.boot();
  29542. this.stage.boot();
  29543. this.world.boot();
  29544. this.scale.boot();
  29545. this.input.boot();
  29546. this.sound.boot();
  29547. this.state.boot();
  29548. if (this.config['enableDebug'])
  29549. {
  29550. this.debug = new Phaser.Utils.Debug(this);
  29551. this.debug.boot();
  29552. }
  29553. else
  29554. {
  29555. this.debug = { preUpdate: function () {}, update: function () {}, reset: function () {}, isDisabled: true };
  29556. }
  29557. this.showDebugHeader();
  29558. this.isRunning = true;
  29559. if (this.config && this.config['forceSetTimeOut'])
  29560. {
  29561. this.raf = new Phaser.RequestAnimationFrame(this, this.config['forceSetTimeOut']);
  29562. }
  29563. else
  29564. {
  29565. this.raf = new Phaser.RequestAnimationFrame(this, false);
  29566. }
  29567. this._kickstart = true;
  29568. if (window['focus'])
  29569. {
  29570. if (!window['PhaserGlobal'] || (window['PhaserGlobal'] && !window['PhaserGlobal'].stopFocus))
  29571. {
  29572. window.focus();
  29573. }
  29574. }
  29575. if (this.cache.isReady)
  29576. {
  29577. this.raf.start();
  29578. }
  29579. else
  29580. {
  29581. this.cache.onReady.addOnce(function () {
  29582. this.raf.start();
  29583. }, this);
  29584. }
  29585. },
  29586. /**
  29587. * Displays a Phaser version debug header in the console.
  29588. *
  29589. * @method Phaser.Game#showDebugHeader
  29590. * @protected
  29591. */
  29592. showDebugHeader: function () {
  29593. if (window['PhaserGlobal'] && window['PhaserGlobal'].hideBanner)
  29594. {
  29595. return;
  29596. }
  29597. var v = Phaser.VERSION;
  29598. var r = 'Canvas';
  29599. var a = 'HTML Audio';
  29600. var c = 1;
  29601. if (this.renderType === Phaser.WEBGL)
  29602. {
  29603. r = 'WebGL';
  29604. c++;
  29605. }
  29606. else if (this.renderType === Phaser.HEADLESS)
  29607. {
  29608. r = 'Headless';
  29609. }
  29610. if (this.device.webAudio)
  29611. {
  29612. a = 'WebAudio';
  29613. c++;
  29614. }
  29615. if (!this.device.ie) // https://developer.mozilla.org/en-US/docs/Web/API/Console/log#Browser_compatibility
  29616. {
  29617. var args = [
  29618. '%c %c %c Phaser CE v' + v + ' | Pixi.js | ' + r + ' | ' + a + ' %c %c ' + '%c http://phaser.io %c\u2665%c\u2665%c\u2665',
  29619. 'background: #fb8cb3',
  29620. 'background: #d44a52',
  29621. 'color: #ffffff; background: #871905;',
  29622. 'background: #d44a52',
  29623. 'background: #fb8cb3',
  29624. 'background: #ffffff'
  29625. ];
  29626. for (var i = 0; i < 3; i++)
  29627. {
  29628. if (i < c)
  29629. {
  29630. args.push('color: #ff2424; background: #fff');
  29631. }
  29632. else
  29633. {
  29634. args.push('color: #959595; background: #fff');
  29635. }
  29636. }
  29637. console.log.apply(console, args);
  29638. }
  29639. else if (window['console'])
  29640. {
  29641. console.log('Phaser v' + v + ' | Pixi.js | ' + r + ' | ' + a + ' | http://phaser.io');
  29642. }
  29643. },
  29644. /**
  29645. * Checks if the device is capable of using the requested renderer and sets it up or an alternative if not.
  29646. *
  29647. * @method Phaser.Game#setUpRenderer
  29648. * @protected
  29649. */
  29650. setUpRenderer: function () {
  29651. if (this.config['canvas'])
  29652. {
  29653. this.canvas = this.config['canvas'];
  29654. }
  29655. else
  29656. {
  29657. this.canvas = Phaser.Canvas.create(this, this.width, this.height, this.config['canvasID'], true);
  29658. }
  29659. if (this.config['canvasStyle'])
  29660. {
  29661. this.canvas.style = this.config['canvasStyle'];
  29662. }
  29663. else
  29664. {
  29665. this.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%';
  29666. }
  29667. if (this.renderType === Phaser.HEADLESS || this.renderType === Phaser.CANVAS || (this.renderType === Phaser.AUTO && !this.device.webGL))
  29668. {
  29669. if (this.device.canvas)
  29670. {
  29671. this.renderer = new PIXI.CanvasRenderer(this);
  29672. this.context = this.renderer.context;
  29673. if (this.renderType === Phaser.AUTO) {
  29674. this.renderType = Phaser.CANVAS;
  29675. }
  29676. }
  29677. else
  29678. {
  29679. throw new Error('Phaser.Game - Cannot create Canvas or WebGL context, aborting.');
  29680. }
  29681. }
  29682. else
  29683. {
  29684. // They requested WebGL and their browser supports it
  29685. if (this.multiTexture || this.renderType === Phaser.WEBGL_MULTI)
  29686. {
  29687. PIXI.enableMultiTexture();
  29688. this.multiTexture = true;
  29689. }
  29690. this.renderType = Phaser.WEBGL;
  29691. this.renderer = new PIXI.WebGLRenderer(this);
  29692. this.context = null;
  29693. this.canvas.addEventListener('webglcontextlost', this.contextLost.bind(this), false);
  29694. this.canvas.addEventListener('webglcontextrestored', this.contextRestored.bind(this), false);
  29695. }
  29696. if (this.device.cocoonJS)
  29697. {
  29698. this.canvas.screencanvas = (this.renderType === Phaser.CANVAS) ? true : false;
  29699. }
  29700. if (this.renderType !== Phaser.HEADLESS)
  29701. {
  29702. this.stage.smoothed = this.antialias;
  29703. Phaser.Canvas.addToDOM(this.canvas, this.parent, false);
  29704. Phaser.Canvas.setTouchAction(this.canvas);
  29705. }
  29706. },
  29707. /**
  29708. * Handles WebGL context loss.
  29709. *
  29710. * @method Phaser.Game#contextLost
  29711. * @private
  29712. * @param {Event} event - The webglcontextlost event.
  29713. */
  29714. contextLost: function (event) {
  29715. event.preventDefault();
  29716. this.renderer.contextLost = true;
  29717. },
  29718. /**
  29719. * Handles WebGL context restoration.
  29720. *
  29721. * @method Phaser.Game#contextRestored
  29722. * @private
  29723. */
  29724. contextRestored: function () {
  29725. this.renderer.initContext();
  29726. this.cache.clearGLTextures();
  29727. this.renderer.contextLost = false;
  29728. },
  29729. /**
  29730. * The core game loop.
  29731. *
  29732. * @method Phaser.Game#update
  29733. * @protected
  29734. * @param {number} time - The current time as provided by RequestAnimationFrame.
  29735. */
  29736. update: function (time) {
  29737. this.time.update(time);
  29738. if (this._kickstart)
  29739. {
  29740. this.updateLogic(this.time.desiredFpsMult);
  29741. // call the game render update exactly once every frame
  29742. this.updateRender(this.time.slowMotion * this.time.desiredFps);
  29743. this._kickstart = false;
  29744. return;
  29745. }
  29746. // if the logic time is spiraling upwards, skip a frame entirely
  29747. if (this._spiraling > 1 && !this.forceSingleUpdate)
  29748. {
  29749. // cause an event to warn the program that this CPU can't keep up with the current desiredFps rate
  29750. if (this.time.time > this._nextFpsNotification)
  29751. {
  29752. // only permit one fps notification per 10 seconds
  29753. this._nextFpsNotification = this.time.time + 10000;
  29754. // dispatch the notification signal
  29755. this.fpsProblemNotifier.dispatch();
  29756. }
  29757. // reset the _deltaTime accumulator which will cause all pending dropped frames to be permanently skipped
  29758. this._deltaTime = 0;
  29759. this._spiraling = 0;
  29760. // call the game render update exactly once every frame
  29761. this.updateRender(this.time.slowMotion * this.time.desiredFps);
  29762. }
  29763. else
  29764. {
  29765. // step size taking into account the slow motion speed
  29766. var slowStep = this.time.slowMotion * 1000.0 / this.time.desiredFps;
  29767. // accumulate time until the slowStep threshold is met or exceeded... up to a limit of 3 catch-up frames at slowStep intervals
  29768. this._deltaTime += Math.max(Math.min(slowStep * 3, this.time.elapsed), 0);
  29769. // call the game update logic multiple times if necessary to "catch up" with dropped frames
  29770. // unless forceSingleUpdate is true
  29771. var count = 0;
  29772. this.updatesThisFrame = Math.floor(this._deltaTime / slowStep);
  29773. if (this.forceSingleUpdate)
  29774. {
  29775. this.updatesThisFrame = Math.min(1, this.updatesThisFrame);
  29776. }
  29777. while (this._deltaTime >= slowStep)
  29778. {
  29779. this._deltaTime -= slowStep;
  29780. this.currentUpdateID = count;
  29781. this.updateLogic(this.time.desiredFpsMult);
  29782. count++;
  29783. if (this.forceSingleUpdate && count === 1)
  29784. {
  29785. break;
  29786. }
  29787. else
  29788. {
  29789. this.time.refresh();
  29790. }
  29791. }
  29792. // detect spiraling (if the catch-up loop isn't fast enough, the number of iterations will increase constantly)
  29793. if (count > this._lastCount)
  29794. {
  29795. this._spiraling++;
  29796. }
  29797. else if (count < this._lastCount)
  29798. {
  29799. // looks like it caught up successfully, reset the spiral alert counter
  29800. this._spiraling = 0;
  29801. }
  29802. this._lastCount = count;
  29803. // call the game render update exactly once every frame unless we're playing catch-up from a spiral condition
  29804. this.updateRender(this._deltaTime / slowStep);
  29805. }
  29806. },
  29807. /**
  29808. * Updates all logic subsystems in Phaser. Called automatically by Game.update.
  29809. *
  29810. * @method Phaser.Game#updateLogic
  29811. * @protected
  29812. * @param {number} timeStep - The current timeStep value as determined by Game.update.
  29813. */
  29814. updateLogic: function (timeStep) {
  29815. if (!this._paused && !this.pendingStep)
  29816. {
  29817. if (this.stepping)
  29818. {
  29819. this.pendingStep = true;
  29820. }
  29821. this.scale.preUpdate();
  29822. this.debug.preUpdate();
  29823. this.camera.preUpdate();
  29824. this.physics.preUpdate();
  29825. this.state.preUpdate(timeStep);
  29826. this.plugins.preUpdate(timeStep);
  29827. this.stage.preUpdate();
  29828. this.state.update();
  29829. this.stage.update();
  29830. this.tweens.update();
  29831. this.sound.update();
  29832. this.input.update();
  29833. this.physics.update();
  29834. this.plugins.update();
  29835. this.stage.postUpdate();
  29836. this.plugins.postUpdate();
  29837. }
  29838. else
  29839. {
  29840. // Scaling and device orientation changes are still reflected when paused.
  29841. this.scale.pauseUpdate();
  29842. this.state.pauseUpdate(timeStep);
  29843. this.debug.preUpdate();
  29844. }
  29845. this.stage.updateTransform();
  29846. },
  29847. /**
  29848. * Runs the Render cycle.
  29849. * It starts by calling State.preRender. In here you can do any last minute adjustments of display objects as required.
  29850. * It then calls the renderer, which renders the entire display list, starting from the Stage object and working down.
  29851. * It then calls plugin.render on any loaded plugins, in the order in which they were enabled.
  29852. * After this State.render is called. Any rendering that happens here will take place on-top of the display list.
  29853. * Finally plugin.postRender is called on any loaded plugins, in the order in which they were enabled.
  29854. * This method is called automatically by Game.update, you don't need to call it directly.
  29855. * Should you wish to have fine-grained control over when Phaser renders then use the `Game.lockRender` boolean.
  29856. * Phaser will only render when this boolean is `false`.
  29857. *
  29858. * @method Phaser.Game#updateRender
  29859. * @protected
  29860. * @param {number} elapsedTime - The time elapsed since the last update.
  29861. */
  29862. updateRender: function (elapsedTime) {
  29863. if (this.lockRender)
  29864. {
  29865. return;
  29866. }
  29867. this.state.preRender(elapsedTime);
  29868. if (this.renderType !== Phaser.HEADLESS)
  29869. {
  29870. this.renderer.render(this.stage);
  29871. this.plugins.render(elapsedTime);
  29872. this.state.render(elapsedTime);
  29873. }
  29874. this.plugins.postRender(elapsedTime);
  29875. },
  29876. /**
  29877. * Enable core game loop stepping. When enabled you must call game.step() directly (perhaps via a DOM button?)
  29878. * Calling step will advance the game loop by one frame. This is extremely useful for hard to track down errors!
  29879. *
  29880. * @method Phaser.Game#enableStep
  29881. */
  29882. enableStep: function () {
  29883. this.stepping = true;
  29884. this.pendingStep = false;
  29885. this.stepCount = 0;
  29886. },
  29887. /**
  29888. * Disables core game loop stepping.
  29889. *
  29890. * @method Phaser.Game#disableStep
  29891. */
  29892. disableStep: function () {
  29893. this.stepping = false;
  29894. this.pendingStep = false;
  29895. },
  29896. /**
  29897. * When stepping is enabled you must call this function directly (perhaps via a DOM button?) to advance the game loop by one frame.
  29898. * This is extremely useful to hard to track down errors! Use the internal stepCount property to monitor progress.
  29899. *
  29900. * @method Phaser.Game#step
  29901. */
  29902. step: function () {
  29903. this.pendingStep = false;
  29904. this.stepCount++;
  29905. },
  29906. /**
  29907. * Nukes the entire game from orbit.
  29908. *
  29909. * Calls destroy on Game.state, Game.sound, Game.scale, Game.stage, Game.input, Game.physics and Game.plugins.
  29910. *
  29911. * Then sets all of those local handlers to null, destroys the renderer, removes the canvas from the DOM
  29912. * and resets the PIXI default renderer.
  29913. *
  29914. * @method Phaser.Game#destroy
  29915. */
  29916. destroy: function () {
  29917. this.raf.stop();
  29918. if (this.debug.destroy)
  29919. {
  29920. this.debug.destroy();
  29921. }
  29922. this.state.destroy();
  29923. this.sound.destroy();
  29924. this.scale.destroy();
  29925. this.stage.destroy();
  29926. this.input.destroy();
  29927. this.physics.destroy();
  29928. this.plugins.destroy();
  29929. this.debug = null;
  29930. this.state = null;
  29931. this.sound = null;
  29932. this.scale = null;
  29933. this.stage = null;
  29934. this.input = null;
  29935. this.physics = null;
  29936. this.plugins = null;
  29937. this.cache = null;
  29938. this.load = null;
  29939. this.time = null;
  29940. this.world = null;
  29941. this.isBooted = false;
  29942. this.renderer.destroy(false);
  29943. Phaser.Canvas.removeFromDOM(this.canvas);
  29944. PIXI.defaultRenderer = null;
  29945. Phaser.GAMES[this.id] = null;
  29946. },
  29947. /**
  29948. * Called by the Stage visibility handler.
  29949. *
  29950. * @method Phaser.Game#gamePaused
  29951. * @param {object} event - The DOM event that caused the game to pause, if any.
  29952. * @protected
  29953. */
  29954. gamePaused: function (event) {
  29955. // If the game is already paused it was done via game code, so don't re-pause it
  29956. if (!this._paused)
  29957. {
  29958. this._paused = true;
  29959. this.time.gamePaused();
  29960. if (this.sound.muteOnPause)
  29961. {
  29962. this.sound.setMute();
  29963. }
  29964. this.onPause.dispatch(event);
  29965. // Avoids Cordova iOS crash event: https://github.com/photonstorm/phaser/issues/1800
  29966. if (this.device.cordova && this.device.iOS)
  29967. {
  29968. this.lockRender = true;
  29969. }
  29970. }
  29971. },
  29972. /**
  29973. * Called by the Stage visibility handler.
  29974. *
  29975. * @method Phaser.Game#gameResumed
  29976. * @param {object} event - The DOM event that caused the game to pause, if any.
  29977. * @protected
  29978. */
  29979. gameResumed: function (event) {
  29980. // Game is paused, but wasn't paused via code, so resume it
  29981. if (this._paused && !this._codePaused)
  29982. {
  29983. this._paused = false;
  29984. this.time.gameResumed();
  29985. this.input.reset();
  29986. if (this.sound.muteOnPause)
  29987. {
  29988. this.sound.unsetMute();
  29989. }
  29990. this.onResume.dispatch(event);
  29991. // Avoids Cordova iOS crash event: https://github.com/photonstorm/phaser/issues/1800
  29992. if (this.device.cordova && this.device.iOS)
  29993. {
  29994. this.lockRender = false;
  29995. }
  29996. }
  29997. },
  29998. /**
  29999. * Called by the Stage visibility handler.
  30000. *
  30001. * @method Phaser.Game#focusLoss
  30002. * @param {object} event - The DOM event that caused the game to pause, if any.
  30003. * @protected
  30004. */
  30005. focusLoss: function (event) {
  30006. this.onBlur.dispatch(event);
  30007. if (!this.stage.disableVisibilityChange)
  30008. {
  30009. this.gamePaused(event);
  30010. }
  30011. },
  30012. /**
  30013. * Called by the Stage visibility handler.
  30014. *
  30015. * @method Phaser.Game#focusGain
  30016. * @param {object} event - The DOM event that caused the game to pause, if any.
  30017. * @protected
  30018. */
  30019. focusGain: function (event) {
  30020. this.onFocus.dispatch(event);
  30021. if (!this.stage.disableVisibilityChange)
  30022. {
  30023. this.gameResumed(event);
  30024. }
  30025. }
  30026. };
  30027. Phaser.Game.prototype.constructor = Phaser.Game;
  30028. /**
  30029. * The paused state of the Game. A paused game doesn't update any of its subsystems.
  30030. * When a game is paused the onPause event is dispatched. When it is resumed the onResume event is dispatched.
  30031. * @name Phaser.Game#paused
  30032. * @property {boolean} paused - Gets and sets the paused state of the Game.
  30033. */
  30034. Object.defineProperty(Phaser.Game.prototype, "paused", {
  30035. get: function () {
  30036. return this._paused;
  30037. },
  30038. set: function (value) {
  30039. if (value === true)
  30040. {
  30041. if (this._paused === false)
  30042. {
  30043. this._paused = true;
  30044. this.sound.setMute();
  30045. this.time.gamePaused();
  30046. this.onPause.dispatch(this);
  30047. }
  30048. this._codePaused = true;
  30049. }
  30050. else
  30051. {
  30052. if (this._paused)
  30053. {
  30054. this._paused = false;
  30055. this.input.reset();
  30056. this.sound.unsetMute();
  30057. this.time.gameResumed();
  30058. this.onResume.dispatch(this);
  30059. }
  30060. this._codePaused = false;
  30061. }
  30062. }
  30063. });
  30064. /**
  30065. *
  30066. * "Deleted code is debugged code." - Jeff Sickel
  30067. *
  30068. * ヽ(〃^▽^〃)ノ
  30069. *
  30070. */
  30071. /**
  30072. * @author Richard Davey <rich@photonstorm.com>
  30073. * @copyright 2016 Photon Storm Ltd.
  30074. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  30075. */
  30076. /**
  30077. * Phaser.Input is the Input Manager for all types of Input across Phaser, including mouse, keyboard, touch and MSPointer.
  30078. * The Input manager is updated automatically by the core game loop.
  30079. *
  30080. * @class Phaser.Input
  30081. * @constructor
  30082. * @param {Phaser.Game} game - Current game instance.
  30083. */
  30084. Phaser.Input = function (game) {
  30085. /**
  30086. * @property {Phaser.Game} game - A reference to the currently running game.
  30087. */
  30088. this.game = game;
  30089. /**
  30090. * @property {HTMLCanvasElement} hitCanvas - The canvas to which single pixels are drawn in order to perform pixel-perfect hit detection.
  30091. * @default
  30092. */
  30093. this.hitCanvas = null;
  30094. /**
  30095. * @property {CanvasRenderingContext2D} hitContext - The context of the pixel perfect hit canvas.
  30096. * @default
  30097. */
  30098. this.hitContext = null;
  30099. /**
  30100. * An array of callbacks that will be fired every time the activePointer receives a move event from the DOM.
  30101. * To add a callback to this array please use `Input.addMoveCallback`.
  30102. * @property {array} moveCallbacks
  30103. * @protected
  30104. */
  30105. this.moveCallbacks = [];
  30106. /**
  30107. * @property {function} customCandidateHandler - See Input.setInteractiveCandidateHandler.
  30108. * @private
  30109. */
  30110. this.customCandidateHandler = null;
  30111. /**
  30112. * @property {object} customCandidateHandlerContext - See Input.setInteractiveCandidateHandler.
  30113. * @private
  30114. */
  30115. this.customCandidateHandlerContext = null;
  30116. /**
  30117. * @property {number} pollRate - How often should the input pointers be checked for updates? A value of 0 means every single frame (60fps); a value of 1 means every other frame (30fps) and so on.
  30118. * @default
  30119. */
  30120. this.pollRate = 0;
  30121. /**
  30122. * When enabled, input (eg. Keyboard, Mouse, Touch) will be processed - as long as the individual sources are enabled themselves.
  30123. *
  30124. * When not enabled, _all_ input sources are ignored. To disable just one type of input; for example, the Mouse, use `input.mouse.enabled = false`.
  30125. * @property {boolean} enabled
  30126. * @default
  30127. */
  30128. this.enabled = true;
  30129. /**
  30130. * @property {number} multiInputOverride - Controls the expected behavior when using a mouse and touch together on a multi-input device.
  30131. * @default
  30132. */
  30133. this.multiInputOverride = Phaser.Input.MOUSE_TOUCH_COMBINE;
  30134. /**
  30135. * @property {Phaser.Point} position - A point object representing the current position of the Pointer.
  30136. * @default
  30137. */
  30138. this.position = null;
  30139. /**
  30140. * @property {Phaser.Point} speed - A point object representing the speed of the Pointer. Only really useful in single Pointer games; otherwise see the Pointer objects directly.
  30141. */
  30142. this.speed = null;
  30143. /**
  30144. * A Circle object centered on the x/y screen coordinates of the Input.
  30145. * Default size of 44px (Apples recommended "finger tip" size) but can be changed to anything.
  30146. * @property {Phaser.Circle} circle
  30147. */
  30148. this.circle = null;
  30149. /**
  30150. * @property {Phaser.Point} scale - The scale by which all input coordinates are multiplied; calculated by the ScaleManager. In an un-scaled game the values will be x = 1 and y = 1.
  30151. */
  30152. this.scale = null;
  30153. /**
  30154. * @property {integer} maxPointers - The maximum number of Pointers allowed to be active at any one time. A value of -1 is only limited by the total number of pointers. For lots of games it's useful to set this to 1.
  30155. * @default -1 (Limited by total pointers.)
  30156. */
  30157. this.maxPointers = -1;
  30158. /**
  30159. * @property {number} tapRate - The number of milliseconds that the Pointer has to be pressed down and then released to be considered a tap or click.
  30160. * @default
  30161. */
  30162. this.tapRate = 200;
  30163. /**
  30164. * @property {number} doubleTapRate - The number of milliseconds between taps of the same Pointer for it to be considered a double tap / click.
  30165. * @default
  30166. */
  30167. this.doubleTapRate = 300;
  30168. /**
  30169. * @property {number} holdRate - The number of milliseconds that the Pointer has to be pressed down for it to fire a onHold event.
  30170. * @default
  30171. */
  30172. this.holdRate = 2000;
  30173. /**
  30174. * @property {number} justPressedRate - The number of milliseconds below which the Pointer is considered justPressed.
  30175. * @default
  30176. */
  30177. this.justPressedRate = 200;
  30178. /**
  30179. * @property {number} justReleasedRate - The number of milliseconds below which the Pointer is considered justReleased .
  30180. * @default
  30181. */
  30182. this.justReleasedRate = 200;
  30183. /**
  30184. * Sets if the Pointer objects should record a history of x/y coordinates they have passed through.
  30185. * The history is cleared each time the Pointer is pressed down.
  30186. * The history is updated at the rate specified in Input.pollRate
  30187. * @property {boolean} recordPointerHistory
  30188. * @default
  30189. */
  30190. this.recordPointerHistory = false;
  30191. /**
  30192. * @property {number} recordRate - The rate in milliseconds at which the Pointer objects should update their tracking history.
  30193. * @default
  30194. */
  30195. this.recordRate = 100;
  30196. /**
  30197. * The total number of entries that can be recorded into the Pointer objects tracking history.
  30198. * If the Pointer is tracking one event every 100ms; then a trackLimit of 100 would store the last 10 seconds worth of history.
  30199. * @property {number} recordLimit
  30200. * @default
  30201. */
  30202. this.recordLimit = 100;
  30203. /**
  30204. * An array of callbacks that will be fired every time a native touch start or touch end event (pointerdown or pointerup when using Pointer events) is received from the browser.
  30205. * This is used internally to handle audio and video unlocking on mobile devices.
  30206. * To add a callback to this array please use `Input.addTouchLockCallback`.
  30207. * @property {array} touchLockCallbacks
  30208. * @protected
  30209. */
  30210. this.touchLockCallbacks = [];
  30211. /**
  30212. * @property {Phaser.Pointer} pointer1 - A Pointer object.
  30213. */
  30214. this.pointer1 = null;
  30215. /**
  30216. * @property {Phaser.Pointer} pointer2 - A Pointer object.
  30217. */
  30218. this.pointer2 = null;
  30219. /**
  30220. * @property {Phaser.Pointer} pointer3 - A Pointer object.
  30221. */
  30222. this.pointer3 = null;
  30223. /**
  30224. * @property {Phaser.Pointer} pointer4 - A Pointer object.
  30225. */
  30226. this.pointer4 = null;
  30227. /**
  30228. * @property {Phaser.Pointer} pointer5 - A Pointer object.
  30229. */
  30230. this.pointer5 = null;
  30231. /**
  30232. * @property {Phaser.Pointer} pointer6 - A Pointer object.
  30233. */
  30234. this.pointer6 = null;
  30235. /**
  30236. * @property {Phaser.Pointer} pointer7 - A Pointer object.
  30237. */
  30238. this.pointer7 = null;
  30239. /**
  30240. * @property {Phaser.Pointer} pointer8 - A Pointer object.
  30241. */
  30242. this.pointer8 = null;
  30243. /**
  30244. * @property {Phaser.Pointer} pointer9 - A Pointer object.
  30245. */
  30246. this.pointer9 = null;
  30247. /**
  30248. * @property {Phaser.Pointer} pointer10 - A Pointer object.
  30249. */
  30250. this.pointer10 = null;
  30251. /**
  30252. * An array of non-mouse pointers that have been added to the game.
  30253. * The properties `pointer1..N` are aliases for `pointers[0..N-1]`.
  30254. * @property {Phaser.Pointer[]} pointers
  30255. * @public
  30256. * @readonly
  30257. */
  30258. this.pointers = [];
  30259. /**
  30260. * The most recently active Pointer object.
  30261. *
  30262. * When you've limited max pointers to 1 this will accurately be either the first finger touched or mouse.
  30263. *
  30264. * @property {Phaser.Pointer} activePointer
  30265. */
  30266. this.activePointer = null;
  30267. /**
  30268. * The mouse has its own unique Phaser.Pointer object which you can use if making a desktop specific game.
  30269. *
  30270. * @property {Pointer} mousePointer
  30271. */
  30272. this.mousePointer = null;
  30273. /**
  30274. * The Mouse Input manager.
  30275. *
  30276. * You should not usually access this manager directly, but instead use Input.mousePointer or Input.activePointer
  30277. * which normalizes all the input values for you, regardless of browser.
  30278. *
  30279. * @property {Phaser.Mouse} mouse
  30280. */
  30281. this.mouse = null;
  30282. /**
  30283. * The Keyboard Input manager.
  30284. *
  30285. * @property {Phaser.Keyboard} keyboard
  30286. */
  30287. this.keyboard = null;
  30288. /**
  30289. * The Touch Input manager.
  30290. *
  30291. * You should not usually access this manager directly, but instead use Input.activePointer
  30292. * which normalizes all the input values for you, regardless of browser.
  30293. *
  30294. * @property {Phaser.Touch} touch
  30295. */
  30296. this.touch = null;
  30297. /**
  30298. * The MSPointer Input manager.
  30299. *
  30300. * You should not usually access this manager directly, but instead use Input.activePointer
  30301. * which normalizes all the input values for you, regardless of browser.
  30302. *
  30303. * @property {Phaser.MSPointer} mspointer
  30304. */
  30305. this.mspointer = null;
  30306. /**
  30307. * The Gamepad Input manager.
  30308. *
  30309. * @property {Phaser.Gamepad} gamepad
  30310. */
  30311. this.gamepad = null;
  30312. /**
  30313. * If the Input Manager has been reset locked then all calls made to InputManager.reset,
  30314. * such as from a State change, are ignored.
  30315. * @property {boolean} resetLocked
  30316. * @default
  30317. */
  30318. this.resetLocked = false;
  30319. /**
  30320. * A Signal that is dispatched each time a {@link Phaser.Pointer pointer} is pressed down.
  30321. * It is sent two arguments:
  30322. *
  30323. * - {Phaser.Pointer} The pointer that caused the event.
  30324. * - {Event} The original DOM event.
  30325. *
  30326. * @property {Phaser.Signal} onDown
  30327. */
  30328. this.onDown = null;
  30329. /**
  30330. * A Signal that is dispatched each time a {@link Phaser.Pointer pointer} is released.
  30331. * It is sent two arguments:
  30332. *
  30333. * - {Phaser.Pointer} The pointer that caused the event.
  30334. * - {Event} The original DOM event.
  30335. *
  30336. * @property {Phaser.Signal} onUp
  30337. */
  30338. this.onUp = null;
  30339. /**
  30340. * A Signal that is dispatched each time a {@link Phaser.Pointer pointer} is tapped.
  30341. * It is sent two arguments:
  30342. *
  30343. * - {Phaser.Pointer} The pointer that caused the event.
  30344. * - {boolean} True if this was a double tap.
  30345. *
  30346. * @property {Phaser.Signal} onTap
  30347. */
  30348. this.onTap = null;
  30349. /**
  30350. * A Signal that is dispatched each time a {@link Phaser.Pointer pointer} is held down.
  30351. * It is sent one argument:
  30352. *
  30353. * - {Phaser.Pointer} The pointer that caused the event.
  30354. *
  30355. * @property {Phaser.Signal} onHold
  30356. */
  30357. this.onHold = null;
  30358. /**
  30359. * You can tell all Pointers to ignore any Game Object with a `priorityID` lower than this value.
  30360. * This is useful when stacking UI layers. Set to zero to disable.
  30361. * @property {number} minPriorityID
  30362. * @default
  30363. */
  30364. this.minPriorityID = 0;
  30365. /**
  30366. * A list of interactive objects. The InputHandler components add and remove themselves from this list.
  30367. * @property {Phaser.ArraySet} interactiveItems
  30368. */
  30369. this.interactiveItems = new Phaser.ArraySet();
  30370. /**
  30371. * @property {Phaser.Point} _localPoint - Internal cache var.
  30372. * @private
  30373. */
  30374. this._localPoint = new Phaser.Point();
  30375. /**
  30376. * @property {number} _pollCounter - Internal var holding the current poll counter.
  30377. * @private
  30378. */
  30379. this._pollCounter = 0;
  30380. /**
  30381. * @property {Phaser.Point} _oldPosition - A point object representing the previous position of the Pointer.
  30382. * @private
  30383. */
  30384. this._oldPosition = null;
  30385. /**
  30386. * @property {number} _x - x coordinate of the most recent Pointer event
  30387. * @private
  30388. */
  30389. this._x = 0;
  30390. /**
  30391. * @property {number} _y - Y coordinate of the most recent Pointer event
  30392. * @private
  30393. */
  30394. this._y = 0;
  30395. };
  30396. /**
  30397. * @constant
  30398. * @type {number}
  30399. */
  30400. Phaser.Input.MOUSE_OVERRIDES_TOUCH = 0;
  30401. /**
  30402. * @constant
  30403. * @type {number}
  30404. */
  30405. Phaser.Input.TOUCH_OVERRIDES_MOUSE = 1;
  30406. /**
  30407. * @constant
  30408. * @type {number}
  30409. */
  30410. Phaser.Input.MOUSE_TOUCH_COMBINE = 2;
  30411. /**
  30412. * The maximum number of pointers that can be added. This excludes the mouse pointer.
  30413. * @constant
  30414. * @type {integer}
  30415. */
  30416. Phaser.Input.MAX_POINTERS = 10;
  30417. Phaser.Input.prototype = {
  30418. /**
  30419. * Starts the Input Manager running.
  30420. *
  30421. * @method Phaser.Input#boot
  30422. * @protected
  30423. */
  30424. boot: function () {
  30425. this.mousePointer = new Phaser.Pointer(this.game, 0, Phaser.PointerMode.CURSOR);
  30426. this.addPointer();
  30427. this.addPointer();
  30428. this.mouse = new Phaser.Mouse(this.game);
  30429. this.touch = new Phaser.Touch(this.game);
  30430. this.mspointer = new Phaser.MSPointer(this.game);
  30431. if (Phaser.Keyboard)
  30432. {
  30433. this.keyboard = new Phaser.Keyboard(this.game);
  30434. }
  30435. if (Phaser.Gamepad)
  30436. {
  30437. this.gamepad = new Phaser.Gamepad(this.game);
  30438. }
  30439. this.onDown = new Phaser.Signal();
  30440. this.onUp = new Phaser.Signal();
  30441. this.onTap = new Phaser.Signal();
  30442. this.onHold = new Phaser.Signal();
  30443. this.scale = new Phaser.Point(1, 1);
  30444. this.speed = new Phaser.Point();
  30445. this.position = new Phaser.Point();
  30446. this._oldPosition = new Phaser.Point();
  30447. this.circle = new Phaser.Circle(0, 0, 44);
  30448. this.activePointer = this.mousePointer;
  30449. this.hitCanvas = Phaser.CanvasPool.create(this, 1, 1);
  30450. this.hitContext = this.hitCanvas.getContext('2d');
  30451. this.mouse.start();
  30452. if (!this.game.device.mspointer)
  30453. {
  30454. // Chrome >= 55 fires both PointerEvent and TouchEvent.
  30455. // Pick only one.
  30456. this.touch.start();
  30457. }
  30458. this.mspointer.start();
  30459. this.mousePointer.active = true;
  30460. if (this.keyboard)
  30461. {
  30462. this.keyboard.start();
  30463. }
  30464. var _this = this;
  30465. this._onClickTrampoline = function (event) {
  30466. _this.onClickTrampoline(event);
  30467. };
  30468. this.game.canvas.addEventListener('click', this._onClickTrampoline, false);
  30469. },
  30470. /**
  30471. * Stops all of the Input Managers from running.
  30472. *
  30473. * @method Phaser.Input#destroy
  30474. */
  30475. destroy: function () {
  30476. this.mouse.stop();
  30477. this.touch.stop();
  30478. this.mspointer.stop();
  30479. if (this.keyboard)
  30480. {
  30481. this.keyboard.stop();
  30482. }
  30483. if (this.gamepad)
  30484. {
  30485. this.gamepad.stop();
  30486. }
  30487. this.moveCallbacks = [];
  30488. Phaser.CanvasPool.remove(this);
  30489. this.game.canvas.removeEventListener('click', this._onClickTrampoline);
  30490. },
  30491. /**
  30492. * Adds a callback that is fired every time `Pointer.processInteractiveObjects` is called.
  30493. * The purpose of `processInteractiveObjects` is to work out which Game Object the Pointer is going to
  30494. * interact with. It works by polling all of the valid game objects, and then slowly discounting those
  30495. * that don't meet the criteria (i.e. they aren't under the Pointer, are disabled, invisible, etc).
  30496. *
  30497. * Eventually a short-list of 'candidates' is created. These are all of the Game Objects which are valid
  30498. * for input and overlap with the Pointer. If you need fine-grained control over which of the items is
  30499. * selected then you can use this callback to do so.
  30500. *
  30501. * The callback will be sent 3 parameters:
  30502. *
  30503. * 1) A reference to the Phaser.Pointer object that is processing the Items.
  30504. * 2) An array containing all potential interactive candidates. This is an array of `InputHandler` objects, not Sprites.
  30505. * 3) The current 'favorite' candidate, based on its priorityID and position in the display list.
  30506. *
  30507. * Your callback MUST return one of the candidates sent to it.
  30508. *
  30509. * @method Phaser.Input#setInteractiveCandidateHandler
  30510. * @param {function} callback - The callback that will be called each time `Pointer.processInteractiveObjects` is called. Set to `null` to disable.
  30511. * @param {object} context - The context in which the callback will be called.
  30512. */
  30513. setInteractiveCandidateHandler: function (callback, context) {
  30514. this.customCandidateHandler = callback;
  30515. this.customCandidateHandlerContext = context;
  30516. },
  30517. /**
  30518. * Adds a callback that is fired every time the activePointer receives a DOM move event such as a mousemove or touchmove.
  30519. *
  30520. * The callback will be sent 4 parameters:
  30521. *
  30522. * A reference to the Phaser.Pointer object that moved,
  30523. * The x position of the pointer,
  30524. * The y position,
  30525. * A boolean indicating if the movement was the result of a 'click' event (such as a mouse click or touch down).
  30526. *
  30527. * It will be called every time the activePointer moves, which in a multi-touch game can be a lot of times, so this is best
  30528. * to only use if you've limited input to a single pointer (i.e. mouse or touch).
  30529. *
  30530. * The callback is added to the Phaser.Input.moveCallbacks array and should be removed with Phaser.Input.deleteMoveCallback.
  30531. *
  30532. * @method Phaser.Input#addMoveCallback
  30533. * @param {function} callback - The callback that will be called each time the activePointer receives a DOM move event.
  30534. * @param {object} context - The context in which the callback will be called.
  30535. */
  30536. addMoveCallback: function (callback, context) {
  30537. this.moveCallbacks.push({ callback: callback, context: context });
  30538. },
  30539. /**
  30540. * Adds a callback that is fired when a browser touchstart/pointerdown or touchend/pointerup event is received.
  30541. *
  30542. * This is used internally to handle audio and video unlocking on mobile devices.
  30543. *
  30544. * If the callback returns 'true' then the callback is automatically deleted once invoked.
  30545. *
  30546. * The callback is added to the {@link #touchLockCallbacks} array and should be removed with {@link #removeTouchLockCallback}.
  30547. *
  30548. * @method Phaser.Input#addTouchLockCallback
  30549. * @param {function} callback - The callback that will be called when a touchstart event is received.
  30550. * @param {object} context - The context in which the callback will be called.
  30551. * @param {boolean} [onEnd=false] - Will the callback fire on a touchstart/pointerdown (default) or touchend/pointerup event?
  30552. */
  30553. addTouchLockCallback: function (callback, context, onEnd) {
  30554. if (onEnd === undefined) { onEnd = false; }
  30555. this.touchLockCallbacks.push({ callback: callback, context: context, onEnd: onEnd });
  30556. },
  30557. /**
  30558. * Removes the callback at the defined index from the {@link #touchLockCallbacks} array
  30559. *
  30560. * @method Phaser.Input#removeTouchLockCallback
  30561. * @param {function} callback - The callback to be removed.
  30562. * @param {object} context - The context in which the callback exists.
  30563. * @return {boolean} True if the callback was deleted, otherwise false.
  30564. */
  30565. removeTouchLockCallback: function (callback, context) {
  30566. var i = this.touchLockCallbacks.length;
  30567. while (i--)
  30568. {
  30569. if (this.touchLockCallbacks[i].callback === callback && this.touchLockCallbacks[i].context === context)
  30570. {
  30571. this.touchLockCallbacks.splice(i, 1);
  30572. return true;
  30573. }
  30574. }
  30575. return false;
  30576. },
  30577. /**
  30578. * Execute any {@link #touchLockCallbacks} of the given type.
  30579. *
  30580. * @method Phaser.Input#executeTouchLockCallbacks
  30581. * @private
  30582. * @param {boolean} onEnd - Execute the touchend/pointerup callbacks (true) or the touchstart/pointerdown callbacks (false). Required!
  30583. * @param {Event} event - The native event from the browser.
  30584. */
  30585. executeTouchLockCallbacks: function (onEnd, event) {
  30586. var i = this.touchLockCallbacks.length;
  30587. while (i--)
  30588. {
  30589. var cb = this.touchLockCallbacks[i];
  30590. if (cb.onEnd === onEnd && cb.callback.call(cb.context, this, event))
  30591. {
  30592. this.touchLockCallbacks.splice(i, 1);
  30593. }
  30594. }
  30595. },
  30596. /**
  30597. * Removes the callback from the Phaser.Input.moveCallbacks array.
  30598. *
  30599. * @method Phaser.Input#deleteMoveCallback
  30600. * @param {function} callback - The callback to be removed.
  30601. * @param {object} context - The context in which the callback exists.
  30602. */
  30603. deleteMoveCallback: function (callback, context) {
  30604. var i = this.moveCallbacks.length;
  30605. while (i--)
  30606. {
  30607. if (this.moveCallbacks[i].callback === callback && this.moveCallbacks[i].context === context)
  30608. {
  30609. this.moveCallbacks.splice(i, 1);
  30610. return;
  30611. }
  30612. }
  30613. },
  30614. /**
  30615. * Add a new Pointer object to the Input Manager.
  30616. * By default Input creates 3 pointer objects: `mousePointer` (not include in part of general pointer pool), `pointer1` and `pointer2`.
  30617. * This method adds an additional pointer, up to a maximum of Phaser.Input.MAX_POINTERS (default of 10).
  30618. *
  30619. * @method Phaser.Input#addPointer
  30620. * @return {Phaser.Pointer|null} The new Pointer object that was created; null if a new pointer could not be added.
  30621. */
  30622. addPointer: function () {
  30623. if (this.pointers.length >= Phaser.Input.MAX_POINTERS)
  30624. {
  30625. console.warn("Phaser.Input.addPointer: Maximum limit of " + Phaser.Input.MAX_POINTERS + " pointers reached.");
  30626. return null;
  30627. }
  30628. var id = this.pointers.length + 1;
  30629. var pointer = new Phaser.Pointer(this.game, id, Phaser.PointerMode.TOUCH);
  30630. this.pointers.push(pointer);
  30631. this['pointer' + id] = pointer;
  30632. return pointer;
  30633. },
  30634. /**
  30635. * Updates the Input Manager. Called by the core Game loop.
  30636. *
  30637. * @method Phaser.Input#update
  30638. * @protected
  30639. */
  30640. update: function () {
  30641. if (this.keyboard)
  30642. {
  30643. this.keyboard.update();
  30644. }
  30645. if (this.pollRate > 0 && this._pollCounter < this.pollRate)
  30646. {
  30647. this._pollCounter++;
  30648. return;
  30649. }
  30650. this.speed.x = this.position.x - this._oldPosition.x;
  30651. this.speed.y = this.position.y - this._oldPosition.y;
  30652. this._oldPosition.copyFrom(this.position);
  30653. this.mousePointer.update();
  30654. if (this.gamepad && this.gamepad.active)
  30655. {
  30656. this.gamepad.update();
  30657. }
  30658. for (var i = 0; i < this.pointers.length; i++)
  30659. {
  30660. this.pointers[i].update();
  30661. }
  30662. this._pollCounter = 0;
  30663. },
  30664. /**
  30665. * Reset all of the Pointers and Input states.
  30666. *
  30667. * The optional `hard` parameter will reset any events or callbacks that may be bound.
  30668. * Input.reset is called automatically during a State change or if a game loses focus / visibility.
  30669. * To control control the reset manually set {@link Phaser.InputManager.resetLocked} to `true`.
  30670. *
  30671. * @method Phaser.Input#reset
  30672. * @public
  30673. * @param {boolean} [hard=false] - A soft reset won't reset any events or callbacks that are bound. A hard reset will.
  30674. */
  30675. reset: function (hard) {
  30676. if (!this.game.isBooted || this.resetLocked)
  30677. {
  30678. return;
  30679. }
  30680. if (hard === undefined) { hard = false; }
  30681. this.mousePointer.reset();
  30682. if (this.keyboard)
  30683. {
  30684. this.keyboard.reset(hard);
  30685. }
  30686. if (this.gamepad)
  30687. {
  30688. this.gamepad.reset();
  30689. }
  30690. for (var i = 0; i < this.pointers.length; i++)
  30691. {
  30692. this.pointers[i].reset();
  30693. }
  30694. if (this.game.canvas.style.cursor !== 'none')
  30695. {
  30696. this.game.canvas.style.cursor = '';
  30697. }
  30698. if (hard)
  30699. {
  30700. this.onDown.dispose();
  30701. this.onUp.dispose();
  30702. this.onTap.dispose();
  30703. this.onHold.dispose();
  30704. this.onDown = new Phaser.Signal();
  30705. this.onUp = new Phaser.Signal();
  30706. this.onTap = new Phaser.Signal();
  30707. this.onHold = new Phaser.Signal();
  30708. this.moveCallbacks = [];
  30709. }
  30710. this._pollCounter = 0;
  30711. },
  30712. /**
  30713. * Resets the speed and old position properties.
  30714. *
  30715. * @method Phaser.Input#resetSpeed
  30716. * @param {number} x - Sets the oldPosition.x value.
  30717. * @param {number} y - Sets the oldPosition.y value.
  30718. */
  30719. resetSpeed: function (x, y) {
  30720. this._oldPosition.setTo(x, y);
  30721. this.speed.setTo(0, 0);
  30722. },
  30723. /**
  30724. * Find the first free Pointer object and start it, passing in the event data.
  30725. * This is called automatically by Phaser.Touch and Phaser.MSPointer.
  30726. *
  30727. * @method Phaser.Input#startPointer
  30728. * @protected
  30729. * @param {any} event - The event data from the Touch event.
  30730. * @return {Phaser.Pointer} The Pointer object that was started or null if no Pointer object is available.
  30731. */
  30732. startPointer: function (event) {
  30733. if (this.maxPointers >= 0 && this.countActivePointers(this.maxPointers) >= this.maxPointers)
  30734. {
  30735. return null;
  30736. }
  30737. if (!this.pointer1.active)
  30738. {
  30739. return this.pointer1.start(event);
  30740. }
  30741. if (!this.pointer2.active)
  30742. {
  30743. return this.pointer2.start(event);
  30744. }
  30745. for (var i = 2; i < this.pointers.length; i++)
  30746. {
  30747. var pointer = this.pointers[i];
  30748. if (!pointer.active)
  30749. {
  30750. return pointer.start(event);
  30751. }
  30752. }
  30753. return null;
  30754. },
  30755. /**
  30756. * Updates the matching Pointer object, passing in the event data.
  30757. * This is called automatically and should not normally need to be invoked.
  30758. *
  30759. * @method Phaser.Input#updatePointer
  30760. * @protected
  30761. * @param {any} event - The event data from the Touch event.
  30762. * @return {Phaser.Pointer} The Pointer object that was updated; null if no pointer was updated.
  30763. */
  30764. updatePointer: function (event) {
  30765. if (this.pointer1.active && this.pointer1.identifier === event.identifier)
  30766. {
  30767. return this.pointer1.move(event);
  30768. }
  30769. if (this.pointer2.active && this.pointer2.identifier === event.identifier)
  30770. {
  30771. return this.pointer2.move(event);
  30772. }
  30773. for (var i = 2; i < this.pointers.length; i++)
  30774. {
  30775. var pointer = this.pointers[i];
  30776. if (pointer.active && pointer.identifier === event.identifier)
  30777. {
  30778. return pointer.move(event);
  30779. }
  30780. }
  30781. return null;
  30782. },
  30783. /**
  30784. * Stops the matching Pointer object, passing in the event data.
  30785. *
  30786. * @method Phaser.Input#stopPointer
  30787. * @protected
  30788. * @param {any} event - The event data from the Touch event.
  30789. * @return {Phaser.Pointer} The Pointer object that was stopped or null if no Pointer object is available.
  30790. */
  30791. stopPointer: function (event) {
  30792. if (this.pointer1.active && this.pointer1.identifier === event.identifier)
  30793. {
  30794. return this.pointer1.stop(event);
  30795. }
  30796. if (this.pointer2.active && this.pointer2.identifier === event.identifier)
  30797. {
  30798. return this.pointer2.stop(event);
  30799. }
  30800. for (var i = 2; i < this.pointers.length; i++)
  30801. {
  30802. var pointer = this.pointers[i];
  30803. if (pointer.active && pointer.identifier === event.identifier)
  30804. {
  30805. return pointer.stop(event);
  30806. }
  30807. }
  30808. return null;
  30809. },
  30810. /**
  30811. * Returns the total number of active pointers, not exceeding the specified limit
  30812. *
  30813. * @name Phaser.Input#countActivePointers
  30814. * @private
  30815. * @property {integer} [limit=(max pointers)] - Stop counting after this.
  30816. * @return {integer} The number of active pointers, or limit - whichever is less.
  30817. */
  30818. countActivePointers: function (limit) {
  30819. if (limit === undefined) { limit = this.pointers.length; }
  30820. var count = limit;
  30821. for (var i = 0; i < this.pointers.length && count > 0; i++)
  30822. {
  30823. var pointer = this.pointers[i];
  30824. if (pointer.active)
  30825. {
  30826. count--;
  30827. }
  30828. }
  30829. return (limit - count);
  30830. },
  30831. /**
  30832. * Get the first Pointer with the given active state.
  30833. *
  30834. * @method Phaser.Input#getPointer
  30835. * @param {boolean} [isActive=false] - The state the Pointer should be in - active or inactive?
  30836. * @return {Phaser.Pointer} A Pointer object or null if no Pointer object matches the requested state.
  30837. */
  30838. getPointer: function (isActive) {
  30839. if (isActive === undefined) { isActive = false; }
  30840. for (var i = 0; i < this.pointers.length; i++)
  30841. {
  30842. var pointer = this.pointers[i];
  30843. if (pointer.active === isActive)
  30844. {
  30845. return pointer;
  30846. }
  30847. }
  30848. return null;
  30849. },
  30850. /**
  30851. * Get the Pointer object whos `identifier` property matches the given identifier value.
  30852. *
  30853. * The identifier property is not set until the Pointer has been used at least once, as its populated by the DOM event.
  30854. * Also it can change every time you press the pointer down, and is not fixed once set.
  30855. * Note: Not all browsers set the identifier property and it's not part of the W3C spec, so you may need getPointerFromId instead.
  30856. *
  30857. * @method Phaser.Input#getPointerFromIdentifier
  30858. * @param {number} identifier - The Pointer.identifier value to search for.
  30859. * @return {Phaser.Pointer} A Pointer object or null if no Pointer object matches the requested identifier.
  30860. */
  30861. getPointerFromIdentifier: function (identifier) {
  30862. for (var i = 0; i < this.pointers.length; i++)
  30863. {
  30864. var pointer = this.pointers[i];
  30865. if (pointer.identifier === identifier)
  30866. {
  30867. return pointer;
  30868. }
  30869. }
  30870. return null;
  30871. },
  30872. /**
  30873. * Get the Pointer object whos `pointerId` property matches the given value.
  30874. *
  30875. * The pointerId property is not set until the Pointer has been used at least once, as its populated by the DOM event.
  30876. * Also it can change every time you press the pointer down if the browser recycles it.
  30877. *
  30878. * @method Phaser.Input#getPointerFromId
  30879. * @param {number} pointerId - The `pointerId` (not 'id') value to search for.
  30880. * @return {Phaser.Pointer} A Pointer object or null if no Pointer object matches the requested identifier.
  30881. */
  30882. getPointerFromId: function (pointerId) {
  30883. for (var i = 0; i < this.pointers.length; i++)
  30884. {
  30885. var pointer = this.pointers[i];
  30886. if (pointer.pointerId === pointerId)
  30887. {
  30888. return pointer;
  30889. }
  30890. }
  30891. return null;
  30892. },
  30893. /**
  30894. * This will return the local coordinates of the specified displayObject based on the given Pointer.
  30895. *
  30896. * @method Phaser.Input#getLocalPosition
  30897. * @param {Phaser.Sprite|Phaser.Image} displayObject - The DisplayObject to get the local coordinates for.
  30898. * @param {Phaser.Pointer} pointer - The Pointer to use in the check against the displayObject.
  30899. * @return {Phaser.Point} A point containing the coordinates of the Pointer position relative to the DisplayObject.
  30900. */
  30901. getLocalPosition: function (displayObject, pointer, output) {
  30902. if (output === undefined) { output = new Phaser.Point(); }
  30903. var wt = displayObject.worldTransform;
  30904. var id = 1 / (wt.a * wt.d + wt.c * -wt.b);
  30905. return output.setTo(
  30906. wt.d * id * pointer.x + -wt.c * id * pointer.y + (wt.ty * wt.c - wt.tx * wt.d) * id,
  30907. wt.a * id * pointer.y + -wt.b * id * pointer.x + (-wt.ty * wt.a + wt.tx * wt.b) * id
  30908. );
  30909. },
  30910. /**
  30911. * Tests if the pointer hits the given object.
  30912. *
  30913. * @method Phaser.Input#hitTest
  30914. * @param {DisplayObject} displayObject - The displayObject to test for a hit.
  30915. * @param {Phaser.Pointer} pointer - The pointer to use for the test.
  30916. * @param {Phaser.Point} localPoint - The local translated point.
  30917. */
  30918. hitTest: function (displayObject, pointer, localPoint) {
  30919. if (!displayObject.worldVisible)
  30920. {
  30921. return false;
  30922. }
  30923. this.getLocalPosition(displayObject, pointer, this._localPoint);
  30924. localPoint.copyFrom(this._localPoint);
  30925. if (displayObject.hitArea && displayObject.hitArea.contains)
  30926. {
  30927. return (displayObject.hitArea.contains(this._localPoint.x, this._localPoint.y));
  30928. }
  30929. else if (Phaser.Creature && displayObject instanceof Phaser.Creature) {
  30930. var width = Math.abs(displayObject.width);
  30931. var height = Math.abs(displayObject.height);
  30932. var x1 = displayObject.x - (width * displayObject.anchorX);
  30933. if (this.game.camera.x + pointer.x >= x1 && this.game.camera.x + pointer.x < x1 + width)
  30934. {
  30935. var y1 = displayObject.y - (height * displayObject.anchorY);
  30936. if (this.game.camera.y + pointer.y >= y1 && this.game.camera.y + pointer.y < y1 + height)
  30937. {
  30938. return true;
  30939. }
  30940. }
  30941. }
  30942. else if (displayObject instanceof Phaser.TileSprite)
  30943. {
  30944. var width = displayObject.width;
  30945. var height = displayObject.height;
  30946. var x1 = -width * displayObject.anchor.x;
  30947. if (this._localPoint.x >= x1 && this._localPoint.x < x1 + width)
  30948. {
  30949. var y1 = -height * displayObject.anchor.y;
  30950. if (this._localPoint.y >= y1 && this._localPoint.y < y1 + height)
  30951. {
  30952. return true;
  30953. }
  30954. }
  30955. }
  30956. else if (displayObject instanceof PIXI.Sprite)
  30957. {
  30958. var width = displayObject.texture.frame.width / displayObject.texture.baseTexture.resolution;
  30959. var height = displayObject.texture.frame.height / displayObject.texture.baseTexture.resolution;
  30960. var x1 = -width * displayObject.anchor.x;
  30961. if (this._localPoint.x >= x1 && this._localPoint.x < x1 + width)
  30962. {
  30963. var y1 = -height * displayObject.anchor.y;
  30964. if (this._localPoint.y >= y1 && this._localPoint.y < y1 + height)
  30965. {
  30966. return true;
  30967. }
  30968. }
  30969. }
  30970. else if (displayObject instanceof Phaser.Graphics)
  30971. {
  30972. for (var i = 0; i < displayObject.graphicsData.length; i++)
  30973. {
  30974. var data = displayObject.graphicsData[i];
  30975. if (!data.fill)
  30976. {
  30977. continue;
  30978. }
  30979. // Only deal with fills..
  30980. if (data.shape && data.shape.contains(this._localPoint.x, this._localPoint.y))
  30981. {
  30982. return true;
  30983. }
  30984. }
  30985. }
  30986. // Didn't hit the parent, does it have any children?
  30987. for (var i = 0; i < displayObject.children.length; i++)
  30988. {
  30989. if (this.hitTest(displayObject.children[i], pointer, localPoint))
  30990. {
  30991. return true;
  30992. }
  30993. }
  30994. return false;
  30995. },
  30996. /**
  30997. * Used for click trampolines. See {@link Phaser.Pointer.addClickTrampoline}.
  30998. *
  30999. * @method Phaser.Input#onClickTrampoline
  31000. * @private
  31001. */
  31002. onClickTrampoline: function () {
  31003. // It might not always be the active pointer, but this does work on
  31004. // Desktop browsers (read: IE) with Mouse or MSPointer input.
  31005. this.activePointer.processClickTrampolines();
  31006. }
  31007. };
  31008. Phaser.Input.prototype.constructor = Phaser.Input;
  31009. /**
  31010. * The X coordinate of the most recently active pointer.
  31011. * This value takes game scaling into account automatically. See Pointer.screenX/clientX for source values.
  31012. * @name Phaser.Input#x
  31013. * @property {number} x
  31014. */
  31015. Object.defineProperty(Phaser.Input.prototype, "x", {
  31016. get: function () {
  31017. return this._x;
  31018. },
  31019. set: function (value) {
  31020. this._x = Math.floor(value);
  31021. }
  31022. });
  31023. /**
  31024. * The Y coordinate of the most recently active pointer.
  31025. * This value takes game scaling into account automatically. See Pointer.screenY/clientY for source values.
  31026. * @name Phaser.Input#y
  31027. * @property {number} y
  31028. */
  31029. Object.defineProperty(Phaser.Input.prototype, "y", {
  31030. get: function () {
  31031. return this._y;
  31032. },
  31033. set: function (value) {
  31034. this._y = Math.floor(value);
  31035. }
  31036. });
  31037. /**
  31038. * True if the Input is currently poll rate locked.
  31039. * @name Phaser.Input#pollLocked
  31040. * @property {boolean} pollLocked
  31041. * @readonly
  31042. */
  31043. Object.defineProperty(Phaser.Input.prototype, "pollLocked", {
  31044. get: function () {
  31045. return (this.pollRate > 0 && this._pollCounter < this.pollRate);
  31046. }
  31047. });
  31048. /**
  31049. * The total number of inactive Pointers.
  31050. * @name Phaser.Input#totalInactivePointers
  31051. * @property {number} totalInactivePointers
  31052. * @readonly
  31053. */
  31054. Object.defineProperty(Phaser.Input.prototype, "totalInactivePointers", {
  31055. get: function () {
  31056. return this.pointers.length - this.countActivePointers();
  31057. }
  31058. });
  31059. /**
  31060. * The total number of active Pointers, not counting the mouse pointer.
  31061. * @name Phaser.Input#totalActivePointers
  31062. * @property {integers} totalActivePointers
  31063. * @readonly
  31064. */
  31065. Object.defineProperty(Phaser.Input.prototype, "totalActivePointers", {
  31066. get: function () {
  31067. return this.countActivePointers();
  31068. }
  31069. });
  31070. /**
  31071. * The world X coordinate of the most recently active pointer.
  31072. * @name Phaser.Input#worldX
  31073. * @property {number} worldX - The world X coordinate of the most recently active pointer.
  31074. * @readonly
  31075. */
  31076. Object.defineProperty(Phaser.Input.prototype, "worldX", {
  31077. get: function () {
  31078. return this.game.camera.view.x + this.x;
  31079. }
  31080. });
  31081. /**
  31082. * The world Y coordinate of the most recently active pointer.
  31083. * @name Phaser.Input#worldY
  31084. * @property {number} worldY - The world Y coordinate of the most recently active pointer.
  31085. * @readonly
  31086. */
  31087. Object.defineProperty(Phaser.Input.prototype, "worldY", {
  31088. get: function () {
  31089. return this.game.camera.view.y + this.y;
  31090. }
  31091. });
  31092. /**
  31093. * @author Richard Davey <rich@photonstorm.com>
  31094. * @copyright 2016 Photon Storm Ltd.
  31095. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  31096. */
  31097. /**
  31098. * The Mouse class is responsible for handling all aspects of mouse interaction with the browser.
  31099. *
  31100. * It captures and processes mouse events that happen on the game canvas object.
  31101. * It also adds a single `mouseup` listener to `window` which is used to capture the mouse being released
  31102. * when not over the game.
  31103. *
  31104. * You should not normally access this class directly, but instead use a Phaser.Pointer object
  31105. * which normalises all game input for you, including accurate button handling.
  31106. *
  31107. * @class Phaser.Mouse
  31108. * @constructor
  31109. * @param {Phaser.Game} game - A reference to the currently running game.
  31110. */
  31111. Phaser.Mouse = function (game) {
  31112. /**
  31113. * @property {Phaser.Game} game - A reference to the currently running game.
  31114. */
  31115. this.game = game;
  31116. /**
  31117. * @property {Phaser.Input} input - A reference to the Phaser Input Manager.
  31118. * @protected
  31119. */
  31120. this.input = game.input;
  31121. /**
  31122. * @property {object} callbackContext - The context under which callbacks are called.
  31123. */
  31124. this.callbackContext = this.game;
  31125. /**
  31126. * @property {function} mouseDownCallback - A callback that can be fired when the mouse is pressed down.
  31127. */
  31128. this.mouseDownCallback = null;
  31129. /**
  31130. * @property {function} mouseUpCallback - A callback that can be fired when the mouse is released from a pressed down state.
  31131. */
  31132. this.mouseUpCallback = null;
  31133. /**
  31134. * @property {function} mouseOutCallback - A callback that can be fired when the mouse is no longer over the game canvas.
  31135. */
  31136. this.mouseOutCallback = null;
  31137. /**
  31138. * @property {function} mouseOverCallback - A callback that can be fired when the mouse enters the game canvas (usually after a mouseout).
  31139. */
  31140. this.mouseOverCallback = null;
  31141. /**
  31142. * @property {function} mouseWheelCallback - A callback that can be fired when the mousewheel is used.
  31143. */
  31144. this.mouseWheelCallback = null;
  31145. /**
  31146. * @property {boolean} capture - If true the DOM mouse events will have event.preventDefault applied to them, if false they will propagate fully.
  31147. */
  31148. this.capture = false;
  31149. /**
  31150. * This property was removed in Phaser 2.4 and should no longer be used.
  31151. * Instead please see the Pointer button properties such as `Pointer.leftButton`, `Pointer.rightButton` and so on.
  31152. * Or Pointer.button holds the DOM event button value if you require that.
  31153. * @property {number} button
  31154. * @default
  31155. */
  31156. this.button = -1;
  31157. /**
  31158. * The direction of the _last_ mousewheel usage 1 for up -1 for down.
  31159. * @property {number} wheelDelta
  31160. */
  31161. this.wheelDelta = 0;
  31162. /**
  31163. * Mouse input will only be processed if enabled.
  31164. * @property {boolean} enabled
  31165. * @default
  31166. */
  31167. this.enabled = true;
  31168. /**
  31169. * @property {boolean} locked - If the mouse has been Pointer Locked successfully this will be set to true.
  31170. * @default
  31171. */
  31172. this.locked = false;
  31173. /**
  31174. * @property {boolean} stopOnGameOut - If true Pointer.stop will be called if the mouse leaves the game canvas.
  31175. * @default
  31176. */
  31177. this.stopOnGameOut = false;
  31178. /**
  31179. * @property {Phaser.Signal} pointerLock - This event is dispatched when the browser enters or leaves pointer lock state.
  31180. * @default
  31181. */
  31182. this.pointerLock = new Phaser.Signal();
  31183. /**
  31184. * The browser mouse DOM event. Will be null if no mouse event has ever been received.
  31185. * Access this property only inside a Mouse event handler and do not keep references to it.
  31186. * @property {MouseEvent|null} event
  31187. * @default
  31188. */
  31189. this.event = null;
  31190. /**
  31191. * @property {function} _onMouseDown - Internal event handler reference.
  31192. * @private
  31193. */
  31194. this._onMouseDown = null;
  31195. /**
  31196. * @property {function} _onMouseMove - Internal event handler reference.
  31197. * @private
  31198. */
  31199. this._onMouseMove = null;
  31200. /**
  31201. * @property {function} _onMouseUp - Internal event handler reference.
  31202. * @private
  31203. */
  31204. this._onMouseUp = null;
  31205. /**
  31206. * @property {function} _onMouseOut - Internal event handler reference.
  31207. * @private
  31208. */
  31209. this._onMouseOut = null;
  31210. /**
  31211. * @property {function} _onMouseOver - Internal event handler reference.
  31212. * @private
  31213. */
  31214. this._onMouseOver = null;
  31215. /**
  31216. * @property {function} _onMouseWheel - Internal event handler reference.
  31217. * @private
  31218. */
  31219. this._onMouseWheel = null;
  31220. /**
  31221. * Wheel proxy event object, if required. Shared for all wheel events for this mouse.
  31222. * @property {Phaser.Mouse~WheelEventProxy} _wheelEvent
  31223. * @private
  31224. */
  31225. this._wheelEvent = null;
  31226. };
  31227. /**
  31228. * @constant
  31229. * @type {number}
  31230. */
  31231. Phaser.Mouse.NO_BUTTON = -1;
  31232. /**
  31233. * @constant
  31234. * @type {number}
  31235. */
  31236. Phaser.Mouse.LEFT_BUTTON = 0;
  31237. /**
  31238. * @constant
  31239. * @type {number}
  31240. */
  31241. Phaser.Mouse.MIDDLE_BUTTON = 1;
  31242. /**
  31243. * @constant
  31244. * @type {number}
  31245. */
  31246. Phaser.Mouse.RIGHT_BUTTON = 2;
  31247. /**
  31248. * @constant
  31249. * @type {number}
  31250. */
  31251. Phaser.Mouse.BACK_BUTTON = 3;
  31252. /**
  31253. * @constant
  31254. * @type {number}
  31255. */
  31256. Phaser.Mouse.FORWARD_BUTTON = 4;
  31257. /**
  31258. * @constant
  31259. * @type {number}
  31260. */
  31261. Phaser.Mouse.WHEEL_UP = 1;
  31262. /**
  31263. * @constant
  31264. * @type {number}
  31265. */
  31266. Phaser.Mouse.WHEEL_DOWN = -1;
  31267. Phaser.Mouse.prototype = {
  31268. /**
  31269. * Starts the event listeners running.
  31270. * @method Phaser.Mouse#start
  31271. */
  31272. start: function () {
  31273. if (this.game.device.android && this.game.device.chrome === false)
  31274. {
  31275. // Android stock browser fires mouse events even if you preventDefault on the touchStart, so ...
  31276. return;
  31277. }
  31278. if (this._onMouseDown !== null)
  31279. {
  31280. // Avoid setting multiple listeners
  31281. return;
  31282. }
  31283. var _this = this;
  31284. this._onMouseDown = function (event) {
  31285. return _this.onMouseDown(event);
  31286. };
  31287. this._onMouseMove = function (event) {
  31288. return _this.onMouseMove(event);
  31289. };
  31290. this._onMouseUp = function (event) {
  31291. return _this.onMouseUp(event);
  31292. };
  31293. this._onMouseUpGlobal = function (event) {
  31294. return _this.onMouseUpGlobal(event);
  31295. };
  31296. this._onMouseOutGlobal = function (event) {
  31297. return _this.onMouseOutGlobal(event);
  31298. };
  31299. this._onMouseOut = function (event) {
  31300. return _this.onMouseOut(event);
  31301. };
  31302. this._onMouseOver = function (event) {
  31303. return _this.onMouseOver(event);
  31304. };
  31305. this._onMouseWheel = function (event) {
  31306. return _this.onMouseWheel(event);
  31307. };
  31308. var canvas = this.game.canvas;
  31309. canvas.addEventListener('mousedown', this._onMouseDown, true);
  31310. canvas.addEventListener('mousemove', this._onMouseMove, true);
  31311. canvas.addEventListener('mouseup', this._onMouseUp, true);
  31312. if (!this.game.device.cocoonJS)
  31313. {
  31314. window.addEventListener('mouseup', this._onMouseUpGlobal, true);
  31315. window.addEventListener('mouseout', this._onMouseOutGlobal, true);
  31316. canvas.addEventListener('mouseover', this._onMouseOver, true);
  31317. canvas.addEventListener('mouseout', this._onMouseOut, true);
  31318. }
  31319. var wheelEvent = this.game.device.wheelEvent;
  31320. if (wheelEvent)
  31321. {
  31322. canvas.addEventListener(wheelEvent, this._onMouseWheel, true);
  31323. if (wheelEvent === 'mousewheel')
  31324. {
  31325. this._wheelEvent = new WheelEventProxy(-1/40, 1);
  31326. }
  31327. else if (wheelEvent === 'DOMMouseScroll')
  31328. {
  31329. this._wheelEvent = new WheelEventProxy(1, 1);
  31330. }
  31331. }
  31332. },
  31333. /**
  31334. * The internal method that handles the mouse down event from the browser.
  31335. * @method Phaser.Mouse#onMouseDown
  31336. * @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
  31337. */
  31338. onMouseDown: function (event) {
  31339. this.event = event;
  31340. if (this.capture)
  31341. {
  31342. event.preventDefault();
  31343. }
  31344. if (this.mouseDownCallback)
  31345. {
  31346. this.mouseDownCallback.call(this.callbackContext, event);
  31347. }
  31348. if (!this.input.enabled || !this.enabled)
  31349. {
  31350. return;
  31351. }
  31352. event['identifier'] = 0;
  31353. this.input.mousePointer.start(event);
  31354. },
  31355. /**
  31356. * The internal method that handles the mouse move event from the browser.
  31357. * @method Phaser.Mouse#onMouseMove
  31358. * @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
  31359. */
  31360. onMouseMove: function (event) {
  31361. this.event = event;
  31362. if (this.capture)
  31363. {
  31364. event.preventDefault();
  31365. }
  31366. if (this.mouseMoveCallback)
  31367. {
  31368. this.mouseMoveCallback.call(this.callbackContext, event);
  31369. }
  31370. if (!this.input.enabled || !this.enabled)
  31371. {
  31372. return;
  31373. }
  31374. event['identifier'] = 0;
  31375. this.input.mousePointer.move(event);
  31376. },
  31377. /**
  31378. * The internal method that handles the mouse up event from the browser.
  31379. * @method Phaser.Mouse#onMouseUp
  31380. * @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
  31381. */
  31382. onMouseUp: function (event) {
  31383. this.event = event;
  31384. if (this.capture)
  31385. {
  31386. event.preventDefault();
  31387. }
  31388. if (this.mouseUpCallback)
  31389. {
  31390. this.mouseUpCallback.call(this.callbackContext, event);
  31391. }
  31392. if (!this.input.enabled || !this.enabled)
  31393. {
  31394. return;
  31395. }
  31396. event['identifier'] = 0;
  31397. this.input.mousePointer.stop(event);
  31398. },
  31399. /**
  31400. * The internal method that handles the mouse up event from the window.
  31401. *
  31402. * @method Phaser.Mouse#onMouseUpGlobal
  31403. * @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
  31404. */
  31405. onMouseUpGlobal: function (event) {
  31406. if (!this.input.mousePointer.withinGame)
  31407. {
  31408. if (this.mouseUpCallback)
  31409. {
  31410. this.mouseUpCallback.call(this.callbackContext, event);
  31411. }
  31412. event['identifier'] = 0;
  31413. this.input.mousePointer.stop(event);
  31414. }
  31415. },
  31416. /**
  31417. * The internal method that handles the mouse out event from the window.
  31418. *
  31419. * @method Phaser.Mouse#onMouseOutGlobal
  31420. * @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
  31421. */
  31422. onMouseOutGlobal: function (event) {
  31423. this.event = event;
  31424. if (this.capture)
  31425. {
  31426. event.preventDefault();
  31427. }
  31428. this.input.mousePointer.withinGame = false;
  31429. if (!this.input.enabled || !this.enabled)
  31430. {
  31431. return;
  31432. }
  31433. // If we get a mouseout event from the window then basically
  31434. // something serious has gone down, usually along the lines of
  31435. // the browser opening a context-menu or similar.
  31436. // On OS X Chrome especially this is bad news, as it blocks
  31437. // us then getting a mouseup event, so we need to force that through.
  31438. //
  31439. // No matter what, we must cancel the left and right buttons
  31440. this.input.mousePointer.stop(event);
  31441. // Clear the button states (again?)
  31442. this.input.mousePointer.resetButtons();
  31443. },
  31444. /**
  31445. * The internal method that handles the mouse out event from the browser.
  31446. *
  31447. * @method Phaser.Mouse#onMouseOut
  31448. * @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
  31449. */
  31450. onMouseOut: function (event) {
  31451. this.event = event;
  31452. if (this.capture)
  31453. {
  31454. event.preventDefault();
  31455. }
  31456. this.input.mousePointer.withinGame = false;
  31457. if (this.mouseOutCallback)
  31458. {
  31459. this.mouseOutCallback.call(this.callbackContext, event);
  31460. }
  31461. if (!this.input.enabled || !this.enabled)
  31462. {
  31463. return;
  31464. }
  31465. if (this.stopOnGameOut)
  31466. {
  31467. event['identifier'] = 0;
  31468. this.input.mousePointer.stop(event);
  31469. }
  31470. },
  31471. /**
  31472. * The internal method that handles the mouse over event from the browser.
  31473. *
  31474. * @method Phaser.Mouse#onMouseOver
  31475. * @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
  31476. */
  31477. onMouseOver: function (event) {
  31478. this.event = event;
  31479. if (this.capture)
  31480. {
  31481. event.preventDefault();
  31482. }
  31483. this.input.mousePointer.withinGame = true;
  31484. if (this.mouseOverCallback)
  31485. {
  31486. this.mouseOverCallback.call(this.callbackContext, event);
  31487. }
  31488. },
  31489. /**
  31490. * The internal method that handles the mouse wheel event from the browser.
  31491. *
  31492. * @method Phaser.Mouse#onMouseWheel
  31493. * @param {MouseEvent} event - The native event from the browser.
  31494. */
  31495. onMouseWheel: function (event) {
  31496. if (this._wheelEvent) {
  31497. event = this._wheelEvent.bindEvent(event);
  31498. }
  31499. this.event = event;
  31500. if (this.capture)
  31501. {
  31502. event.preventDefault();
  31503. }
  31504. // reverse detail for firefox
  31505. this.wheelDelta = Phaser.Math.clamp(-event.deltaY, -1, 1);
  31506. if (this.mouseWheelCallback)
  31507. {
  31508. this.mouseWheelCallback.call(this.callbackContext, event);
  31509. }
  31510. },
  31511. /**
  31512. * If the browser supports it you can request that the pointer be locked to the browser window.
  31513. * This is classically known as 'FPS controls', where the pointer can't leave the browser until the user presses an exit key.
  31514. * If the browser successfully enters a locked state the event Phaser.Mouse.pointerLock will be dispatched and the first parameter will be 'true'.
  31515. * @method Phaser.Mouse#requestPointerLock
  31516. */
  31517. requestPointerLock: function () {
  31518. if (this.game.device.pointerLock)
  31519. {
  31520. var element = this.game.canvas;
  31521. element.requestPointerLock = element.requestPointerLock || element.mozRequestPointerLock || element.webkitRequestPointerLock;
  31522. element.requestPointerLock();
  31523. var _this = this;
  31524. this._pointerLockChange = function (event) {
  31525. return _this.pointerLockChange(event);
  31526. };
  31527. document.addEventListener('pointerlockchange', this._pointerLockChange, true);
  31528. document.addEventListener('mozpointerlockchange', this._pointerLockChange, true);
  31529. document.addEventListener('webkitpointerlockchange', this._pointerLockChange, true);
  31530. }
  31531. },
  31532. /**
  31533. * Internal pointerLockChange handler.
  31534. *
  31535. * @method Phaser.Mouse#pointerLockChange
  31536. * @param {Event} event - The native event from the browser. This gets stored in Mouse.event.
  31537. */
  31538. pointerLockChange: function (event) {
  31539. var element = this.game.canvas;
  31540. if (document.pointerLockElement === element || document.mozPointerLockElement === element || document.webkitPointerLockElement === element)
  31541. {
  31542. // Pointer was successfully locked
  31543. this.locked = true;
  31544. this.pointerLock.dispatch(true, event);
  31545. }
  31546. else
  31547. {
  31548. // Pointer was unlocked
  31549. this.locked = false;
  31550. this.pointerLock.dispatch(false, event);
  31551. }
  31552. },
  31553. /**
  31554. * Internal release pointer lock handler.
  31555. * @method Phaser.Mouse#releasePointerLock
  31556. */
  31557. releasePointerLock: function () {
  31558. document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock || document.webkitExitPointerLock;
  31559. document.exitPointerLock();
  31560. document.removeEventListener('pointerlockchange', this._pointerLockChange, true);
  31561. document.removeEventListener('mozpointerlockchange', this._pointerLockChange, true);
  31562. document.removeEventListener('webkitpointerlockchange', this._pointerLockChange, true);
  31563. },
  31564. /**
  31565. * Stop the event listeners.
  31566. * @method Phaser.Mouse#stop
  31567. */
  31568. stop: function () {
  31569. var canvas = this.game.canvas;
  31570. canvas.removeEventListener('mousedown', this._onMouseDown, true);
  31571. canvas.removeEventListener('mousemove', this._onMouseMove, true);
  31572. canvas.removeEventListener('mouseup', this._onMouseUp, true);
  31573. canvas.removeEventListener('mouseover', this._onMouseOver, true);
  31574. canvas.removeEventListener('mouseout', this._onMouseOut, true);
  31575. var wheelEvent = this.game.device.wheelEvent;
  31576. if (wheelEvent)
  31577. {
  31578. canvas.removeEventListener(wheelEvent, this._onMouseWheel, true);
  31579. }
  31580. window.removeEventListener('mouseup', this._onMouseUpGlobal, true);
  31581. window.removeEventListener('mouseout', this._onMouseOutGlobal, true);
  31582. document.removeEventListener('pointerlockchange', this._pointerLockChange, true);
  31583. document.removeEventListener('mozpointerlockchange', this._pointerLockChange, true);
  31584. document.removeEventListener('webkitpointerlockchange', this._pointerLockChange, true);
  31585. }
  31586. };
  31587. Phaser.Mouse.prototype.constructor = Phaser.Mouse;
  31588. /* jshint latedef:nofunc */
  31589. /**
  31590. * A purely internal event support class to proxy 'wheelscroll' and 'DOMMouseWheel'
  31591. * events to 'wheel'-like events.
  31592. *
  31593. * See https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel for choosing a scale and delta mode.
  31594. *
  31595. * @method Phaser.Mouse#WheelEventProxy
  31596. * @private
  31597. * @param {number} scaleFactor - Scale factor as applied to wheelDelta/wheelDeltaX or details.
  31598. * @param {integer} deltaMode - The reported delta mode.
  31599. */
  31600. function WheelEventProxy (scaleFactor, deltaMode) {
  31601. /**
  31602. * @property {number} _scaleFactor - Scale factor as applied to wheelDelta/wheelDeltaX or details.
  31603. * @private
  31604. */
  31605. this._scaleFactor = scaleFactor;
  31606. /**
  31607. * @property {number} _deltaMode - The reported delta mode.
  31608. * @private
  31609. */
  31610. this._deltaMode = deltaMode;
  31611. /**
  31612. * @property {any} originalEvent - The original event _currently_ being proxied; the getters will follow suit.
  31613. * @private
  31614. */
  31615. this.originalEvent = null;
  31616. }
  31617. WheelEventProxy.prototype = {};
  31618. WheelEventProxy.prototype.constructor = WheelEventProxy;
  31619. WheelEventProxy.prototype.bindEvent = function (event) {
  31620. // Generate stubs automatically
  31621. if (!WheelEventProxy._stubsGenerated && event)
  31622. {
  31623. var makeBinder = function (name) {
  31624. return function () {
  31625. var v = this.originalEvent[name];
  31626. return typeof v !== 'function' ? v : v.bind(this.originalEvent);
  31627. };
  31628. };
  31629. for (var prop in event)
  31630. {
  31631. if (!(prop in WheelEventProxy.prototype))
  31632. {
  31633. Object.defineProperty(WheelEventProxy.prototype, prop, {
  31634. get: makeBinder(prop)
  31635. });
  31636. }
  31637. }
  31638. WheelEventProxy._stubsGenerated = true;
  31639. }
  31640. this.originalEvent = event;
  31641. return this;
  31642. };
  31643. Object.defineProperties(WheelEventProxy.prototype, {
  31644. "type": { value: "wheel" },
  31645. "deltaMode": { get: function () { return this._deltaMode; } },
  31646. "deltaY": {
  31647. get: function () {
  31648. return (this._scaleFactor * (this.originalEvent.wheelDelta || this.originalEvent.detail)) || 0;
  31649. }
  31650. },
  31651. "deltaX": {
  31652. get: function () {
  31653. return (this._scaleFactor * this.originalEvent.wheelDeltaX) || 0;
  31654. }
  31655. },
  31656. "deltaZ": { value: 0 }
  31657. });
  31658. /**
  31659. * @author Richard Davey <rich@photonstorm.com>
  31660. * @copyright 2016 Photon Storm Ltd.
  31661. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  31662. */
  31663. /**
  31664. * The MSPointer class handles {@link https://developers.google.com/web/updates/2016/10/pointer-events Pointer-event} interactions with the game via a dedicated {@link Phaser.Pointer}. (It's named after the nonstandard {@link https://msdn.microsoft.com/library/hh673557(v=vs.85).aspx MSPointerEvent} since that was the first browser implementation.)
  31665. *
  31666. * It's {@link http://caniuse.com/#feat=pointer currently supported in IE 10+, Edge, Chrome (including Android), and Opera}.
  31667. *
  31668. * You should not normally access this class directly, but instead use a {@link Phaser.Pointer} object which
  31669. * normalises all game input for you including accurate button handling.
  31670. *
  31671. * Please note that at the current time of writing Phaser does not yet support chorded button interactions:
  31672. * http://www.w3.org/TR/pointerevents/#chorded-button-interactions
  31673. *
  31674. * You can disable Phaser's use of Pointer Events by either of two ways:
  31675. *
  31676. * ```javascript
  31677. * // **Before** `new Phaser.Game(…)`:
  31678. * Phaser.Device.onInitialized.add(function () {
  31679. * this.mspointer = false;
  31680. * });
  31681. * ```
  31682. *
  31683. * ```javascript
  31684. * // Once, in the earliest State `init` or `create` callback (e.g., Boot):
  31685. * this.input.mspointer.stop();
  31686. * ```
  31687. *
  31688. * @class Phaser.MSPointer
  31689. * @constructor
  31690. * @param {Phaser.Game} game - A reference to the currently running game.
  31691. */
  31692. Phaser.MSPointer = function (game) {
  31693. /**
  31694. * @property {Phaser.Game} game - A reference to the currently running game.
  31695. */
  31696. this.game = game;
  31697. /**
  31698. * @property {Phaser.Input} input - A reference to the Phaser Input Manager.
  31699. * @protected
  31700. */
  31701. this.input = game.input;
  31702. /**
  31703. * @property {object} callbackContext - The context under which callbacks are called (defaults to game).
  31704. */
  31705. this.callbackContext = this.game;
  31706. /**
  31707. * @property {function} pointerDownCallback - A callback that can be fired on a MSPointerDown event.
  31708. */
  31709. this.pointerDownCallback = null;
  31710. /**
  31711. * @property {function} pointerMoveCallback - A callback that can be fired on a MSPointerMove event.
  31712. */
  31713. this.pointerMoveCallback = null;
  31714. /**
  31715. * @property {function} pointerUpCallback - A callback that can be fired on a MSPointerUp event.
  31716. */
  31717. this.pointerUpCallback = null;
  31718. /**
  31719. * @property {boolean} capture - If true the Pointer events will have event.preventDefault applied to them, canceling the corresponding MouseEvent or TouchEvent.
  31720. */
  31721. this.capture = true;
  31722. /**
  31723. * This property was removed in Phaser 2.4 and should no longer be used.
  31724. * Instead please see the Pointer button properties such as `Pointer.leftButton`, `Pointer.rightButton` and so on.
  31725. * Or Pointer.button holds the DOM event button value if you require that.
  31726. * @property {number} button
  31727. */
  31728. this.button = -1;
  31729. /**
  31730. * The most recent PointerEvent from the browser. Will be null if no event has ever been received.
  31731. * Access this property only inside a Pointer event handler and do not keep references to it.
  31732. * @property {MSPointerEvent|PointerEvent|null} event
  31733. * @default
  31734. */
  31735. this.event = null;
  31736. /**
  31737. * PointerEvent input will only be processed if enabled.
  31738. * @property {boolean} enabled
  31739. * @default
  31740. */
  31741. this.enabled = true;
  31742. /**
  31743. * @property {function} _onMSPointerDown - Internal function to handle MSPointer events.
  31744. * @private
  31745. */
  31746. this._onMSPointerDown = null;
  31747. /**
  31748. * @property {function} _onMSPointerMove - Internal function to handle MSPointer events.
  31749. * @private
  31750. */
  31751. this._onMSPointerMove = null;
  31752. /**
  31753. * @property {function} _onMSPointerUp - Internal function to handle MSPointer events.
  31754. * @private
  31755. */
  31756. this._onMSPointerUp = null;
  31757. /**
  31758. * @property {function} _onMSPointerUpGlobal - Internal function to handle MSPointer events.
  31759. * @private
  31760. */
  31761. this._onMSPointerUpGlobal = null;
  31762. /**
  31763. * @property {function} _onMSPointerOut - Internal function to handle MSPointer events.
  31764. * @private
  31765. */
  31766. this._onMSPointerOut = null;
  31767. /**
  31768. * @property {function} _onMSPointerOver - Internal function to handle MSPointer events.
  31769. * @private
  31770. */
  31771. this._onMSPointerOver = null;
  31772. };
  31773. Phaser.MSPointer.prototype = {
  31774. /**
  31775. * Starts the event listeners running.
  31776. * @method Phaser.MSPointer#start
  31777. */
  31778. start: function () {
  31779. if (this._onMSPointerDown !== null)
  31780. {
  31781. // Avoid setting multiple listeners
  31782. return;
  31783. }
  31784. var _this = this;
  31785. if (this.game.device.mspointer)
  31786. {
  31787. this._onMSPointerDown = function (event) {
  31788. return _this.onPointerDown(event);
  31789. };
  31790. this._onMSPointerMove = function (event) {
  31791. return _this.onPointerMove(event);
  31792. };
  31793. this._onMSPointerUp = function (event) {
  31794. return _this.onPointerUp(event);
  31795. };
  31796. this._onMSPointerUpGlobal = function (event) {
  31797. return _this.onPointerUpGlobal(event);
  31798. };
  31799. this._onMSPointerOut = function (event) {
  31800. return _this.onPointerOut(event);
  31801. };
  31802. this._onMSPointerOver = function (event) {
  31803. return _this.onPointerOver(event);
  31804. };
  31805. var canvas = this.game.canvas;
  31806. canvas.addEventListener('MSPointerDown', this._onMSPointerDown, false);
  31807. canvas.addEventListener('MSPointerMove', this._onMSPointerMove, false);
  31808. canvas.addEventListener('MSPointerUp', this._onMSPointerUp, false);
  31809. // IE11+ uses non-prefix events
  31810. canvas.addEventListener('pointerdown', this._onMSPointerDown, false);
  31811. canvas.addEventListener('pointermove', this._onMSPointerMove, false);
  31812. canvas.addEventListener('pointerup', this._onMSPointerUp, false);
  31813. canvas.style['-ms-content-zooming'] = 'none';
  31814. canvas.style['-ms-touch-action'] = 'none';
  31815. if (!this.game.device.cocoonJS)
  31816. {
  31817. window.addEventListener('MSPointerUp', this._onMSPointerUpGlobal, true);
  31818. canvas.addEventListener('MSPointerOver', this._onMSPointerOver, true);
  31819. canvas.addEventListener('MSPointerOut', this._onMSPointerOut, true);
  31820. // IE11+ uses non-prefix events
  31821. window.addEventListener('pointerup', this._onMSPointerUpGlobal, true);
  31822. canvas.addEventListener('pointerover', this._onMSPointerOver, true);
  31823. canvas.addEventListener('pointerout', this._onMSPointerOut, true);
  31824. }
  31825. }
  31826. },
  31827. /**
  31828. * The function that handles the PointerDown event.
  31829. *
  31830. * @method Phaser.MSPointer#onPointerDown
  31831. * @param {PointerEvent} event - The native DOM event.
  31832. */
  31833. onPointerDown: function (event) {
  31834. this.game.input.executeTouchLockCallbacks(false, event);
  31835. this.event = event;
  31836. if (this.capture)
  31837. {
  31838. event.preventDefault();
  31839. }
  31840. if (this.pointerDownCallback)
  31841. {
  31842. this.pointerDownCallback.call(this.callbackContext, event);
  31843. }
  31844. if (!this.input.enabled || !this.enabled)
  31845. {
  31846. return;
  31847. }
  31848. event.identifier = event.pointerId;
  31849. if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
  31850. {
  31851. this.input.mousePointer.start(event);
  31852. }
  31853. else
  31854. {
  31855. this.input.startPointer(event);
  31856. }
  31857. },
  31858. /**
  31859. * The function that handles the PointerMove event.
  31860. * @method Phaser.MSPointer#onPointerMove
  31861. * @param {PointerEvent} event - The native DOM event.
  31862. */
  31863. onPointerMove: function (event) {
  31864. this.event = event;
  31865. if (this.capture)
  31866. {
  31867. event.preventDefault();
  31868. }
  31869. if (this.pointerMoveCallback)
  31870. {
  31871. this.pointerMoveCallback.call(this.callbackContext, event);
  31872. }
  31873. if (!this.input.enabled || !this.enabled)
  31874. {
  31875. return;
  31876. }
  31877. event.identifier = event.pointerId;
  31878. if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
  31879. {
  31880. this.input.mousePointer.move(event);
  31881. }
  31882. else
  31883. {
  31884. this.input.updatePointer(event);
  31885. }
  31886. },
  31887. /**
  31888. * The function that handles the PointerUp event.
  31889. * @method Phaser.MSPointer#onPointerUp
  31890. * @param {PointerEvent} event - The native DOM event.
  31891. */
  31892. onPointerUp: function (event) {
  31893. this.game.input.executeTouchLockCallbacks(true, event);
  31894. this.event = event;
  31895. if (this.capture)
  31896. {
  31897. event.preventDefault();
  31898. }
  31899. if (this.pointerUpCallback)
  31900. {
  31901. this.pointerUpCallback.call(this.callbackContext, event);
  31902. }
  31903. if (!this.input.enabled || !this.enabled)
  31904. {
  31905. return;
  31906. }
  31907. event.identifier = event.pointerId;
  31908. if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
  31909. {
  31910. this.input.mousePointer.stop(event);
  31911. }
  31912. else
  31913. {
  31914. this.input.stopPointer(event);
  31915. }
  31916. },
  31917. /**
  31918. * The internal method that handles the mouse up event from the window.
  31919. *
  31920. * @method Phaser.MSPointer#onPointerUpGlobal
  31921. * @param {PointerEvent} event - The native event from the browser. This gets stored in MSPointer.event.
  31922. */
  31923. onPointerUpGlobal: function (event) {
  31924. if ((event.pointerType === 'mouse' || event.pointerType === 0x00000004) && !this.input.mousePointer.withinGame)
  31925. {
  31926. this.onPointerUp(event);
  31927. }
  31928. else
  31929. {
  31930. var pointer = this.input.getPointerFromIdentifier(event.identifier);
  31931. if (pointer && pointer.withinGame)
  31932. {
  31933. this.onPointerUp(event);
  31934. }
  31935. }
  31936. },
  31937. /**
  31938. * The internal method that handles the pointer out event from the browser.
  31939. *
  31940. * @method Phaser.MSPointer#onPointerOut
  31941. * @param {PointerEvent} event - The native event from the browser. This gets stored in MSPointer.event.
  31942. */
  31943. onPointerOut: function (event) {
  31944. this.event = event;
  31945. if (this.capture)
  31946. {
  31947. event.preventDefault();
  31948. }
  31949. if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
  31950. {
  31951. this.input.mousePointer.withinGame = false;
  31952. }
  31953. else
  31954. {
  31955. var pointer = this.input.getPointerFromIdentifier(event.identifier);
  31956. if (pointer)
  31957. {
  31958. pointer.withinGame = false;
  31959. }
  31960. }
  31961. if (this.input.mouse.mouseOutCallback)
  31962. {
  31963. this.input.mouse.mouseOutCallback.call(this.input.mouse.callbackContext, event);
  31964. }
  31965. if (!this.input.enabled || !this.enabled)
  31966. {
  31967. return;
  31968. }
  31969. if (this.input.mouse.stopOnGameOut)
  31970. {
  31971. event['identifier'] = 0;
  31972. if (pointer)
  31973. {
  31974. pointer.stop(event);
  31975. }
  31976. else
  31977. {
  31978. this.input.mousePointer.stop(event);
  31979. }
  31980. }
  31981. },
  31982. /**
  31983. * The internal method that handles the pointer out event from the browser.
  31984. *
  31985. * @method Phaser.MSPointer#onPointerOut
  31986. * @param {PointerEvent} event - The native event from the browser. This gets stored in MSPointer.event.
  31987. */
  31988. onPointerOver: function (event) {
  31989. this.event = event;
  31990. if (this.capture)
  31991. {
  31992. event.preventDefault();
  31993. }
  31994. if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
  31995. {
  31996. this.input.mousePointer.withinGame = true;
  31997. }
  31998. else
  31999. {
  32000. var pointer = this.input.getPointerFromIdentifier(event.identifier);
  32001. if (pointer)
  32002. {
  32003. pointer.withinGame = true;
  32004. }
  32005. }
  32006. if (this.input.mouse.mouseOverCallback)
  32007. {
  32008. this.input.mouse.mouseOverCallback.call(this.input.mouse.callbackContext, event);
  32009. }
  32010. },
  32011. /**
  32012. * Stop the event listeners.
  32013. * @method Phaser.MSPointer#stop
  32014. */
  32015. stop: function () {
  32016. var canvas = this.game.canvas;
  32017. canvas.removeEventListener('MSPointerDown', this._onMSPointerDown, false);
  32018. canvas.removeEventListener('MSPointerMove', this._onMSPointerMove, false);
  32019. canvas.removeEventListener('MSPointerUp', this._onMSPointerUp, false);
  32020. // IE11+ uses non-prefix events
  32021. canvas.removeEventListener('pointerdown', this._onMSPointerDown, false);
  32022. canvas.removeEventListener('pointermove', this._onMSPointerMove, false);
  32023. canvas.removeEventListener('pointerup', this._onMSPointerUp, false);
  32024. window.removeEventListener('MSPointerUp', this._onMSPointerUpGlobal, true);
  32025. canvas.removeEventListener('MSPointerOver', this._onMSPointerOver, true);
  32026. canvas.removeEventListener('MSPointerOut', this._onMSPointerOut, true);
  32027. // IE11+ uses non-prefix events
  32028. window.removeEventListener('pointerup', this._onMSPointerUpGlobal, true);
  32029. canvas.removeEventListener('pointerover', this._onMSPointerOver, true);
  32030. canvas.removeEventListener('pointerout', this._onMSPointerOut, true);
  32031. }
  32032. };
  32033. Phaser.MSPointer.prototype.constructor = Phaser.MSPointer;
  32034. /**
  32035. * @author Richard Davey <rich@photonstorm.com>
  32036. * @author @karlmacklin <tacklemcclean@gmail.com>
  32037. * @copyright 2016 Photon Storm Ltd.
  32038. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  32039. */
  32040. /**
  32041. * DeviceButtons belong to both `Phaser.Pointer` and `Phaser.SinglePad` (Gamepad) instances.
  32042. *
  32043. * For Pointers they represent the various buttons that can exist on mice and pens, such as the left button, right button,
  32044. * middle button and advanced buttons like back and forward.
  32045. *
  32046. * Access them via `Pointer.leftbutton`, `Pointer.rightButton` and so on.
  32047. *
  32048. * On Gamepads they represent all buttons on the pad: from shoulder buttons to action buttons.
  32049. *
  32050. * At the time of writing this there are device limitations you should be aware of:
  32051. *
  32052. * - On Windows, if you install a mouse driver, and its utility software allows you to customize button actions
  32053. * (e.g., IntelliPoint and SetPoint), the middle (wheel) button, the 4th button, and the 5th button might not be set,
  32054. * even when they are pressed.
  32055. * - On Linux (GTK), the 4th button and the 5th button are not supported.
  32056. * - On Mac OS X 10.5 there is no platform API for implementing any advanced buttons.
  32057. *
  32058. * @class Phaser.DeviceButton
  32059. * @constructor
  32060. * @param {Phaser.Pointer|Phaser.SinglePad} parent - A reference to the parent of this button. Either a Pointer or a Gamepad.
  32061. * @param {number} buttonCode - The button code this DeviceButton is responsible for.
  32062. */
  32063. Phaser.DeviceButton = function (parent, buttonCode) {
  32064. /**
  32065. * @property {Phaser.Pointer|Phaser.SinglePad} parent - A reference to the Pointer or Gamepad that owns this button.
  32066. */
  32067. this.parent = parent;
  32068. /**
  32069. * @property {Phaser.Game} game - A reference to the currently running game.
  32070. */
  32071. this.game = parent.game;
  32072. /**
  32073. * @property {object} event - The DOM event that caused the change in button state.
  32074. * @default
  32075. */
  32076. this.event = null;
  32077. /**
  32078. * @property {boolean} isDown - The "down" state of the button.
  32079. * @default
  32080. */
  32081. this.isDown = false;
  32082. /**
  32083. * @property {boolean} isUp - The "up" state of the button.
  32084. * @default
  32085. */
  32086. this.isUp = true;
  32087. /**
  32088. * @property {number} timeDown - The timestamp when the button was last pressed down.
  32089. * @default
  32090. */
  32091. this.timeDown = 0;
  32092. /**
  32093. * @property {number} timeUp - The timestamp when the button was last released.
  32094. * @default
  32095. */
  32096. this.timeUp = 0;
  32097. /**
  32098. * Gamepad only.
  32099. * If a button is held down this holds down the number of times the button has 'repeated'.
  32100. * @property {number} repeats
  32101. * @default
  32102. */
  32103. this.repeats = 0;
  32104. /**
  32105. * True if the alt key was held down when this button was last pressed or released.
  32106. * Not supported on Gamepads.
  32107. * @property {boolean} altKey
  32108. * @default
  32109. */
  32110. this.altKey = false;
  32111. /**
  32112. * True if the shift key was held down when this button was last pressed or released.
  32113. * Not supported on Gamepads.
  32114. * @property {boolean} shiftKey
  32115. * @default
  32116. */
  32117. this.shiftKey = false;
  32118. /**
  32119. * True if the control key was held down when this button was last pressed or released.
  32120. * Not supported on Gamepads.
  32121. * @property {boolean} ctrlKey
  32122. * @default
  32123. */
  32124. this.ctrlKey = false;
  32125. /**
  32126. * @property {number} value - Button value. Mainly useful for checking analog buttons (like shoulder triggers) on Gamepads.
  32127. * @default
  32128. */
  32129. this.value = 0;
  32130. /**
  32131. * @property {number} buttonCode - The buttoncode of this button if a Gamepad, or the DOM button event value if a Pointer.
  32132. */
  32133. this.buttonCode = buttonCode;
  32134. /**
  32135. * This Signal is dispatched every time this DeviceButton is pressed down.
  32136. * It is only dispatched once (until the button is released again).
  32137. * When dispatched it sends 2 arguments: A reference to this DeviceButton and the value of the button.
  32138. * @property {Phaser.Signal} onDown
  32139. */
  32140. this.onDown = new Phaser.Signal();
  32141. /**
  32142. * This Signal is dispatched every time this DeviceButton is released from a down state.
  32143. * It is only dispatched once (until the button is pressed again).
  32144. * When dispatched it sends 2 arguments: A reference to this DeviceButton and the value of the button.
  32145. * @property {Phaser.Signal} onUp
  32146. */
  32147. this.onUp = new Phaser.Signal();
  32148. /**
  32149. * Gamepad only.
  32150. * This Signal is dispatched every time this DeviceButton changes floating value (between, but not exactly, 0 and 1).
  32151. * When dispatched it sends 2 arguments: A reference to this DeviceButton and the value of the button.
  32152. * @property {Phaser.Signal} onFloat
  32153. */
  32154. this.onFloat = new Phaser.Signal();
  32155. };
  32156. Phaser.DeviceButton.prototype = {
  32157. /**
  32158. * Called automatically by Phaser.Pointer and Phaser.SinglePad.
  32159. * Handles the button down state.
  32160. *
  32161. * @method Phaser.DeviceButton#start
  32162. * @protected
  32163. * @param {object} [event] - The DOM event that triggered the button change.
  32164. * @param {number} [value] - The button value. Only get for Gamepads.
  32165. */
  32166. start: function (event, value) {
  32167. if (this.isDown)
  32168. {
  32169. return;
  32170. }
  32171. this.isDown = true;
  32172. this.isUp = false;
  32173. this.timeDown = this.game.time.time;
  32174. this.repeats = 0;
  32175. this.event = event;
  32176. this.value = value;
  32177. if (event)
  32178. {
  32179. this.altKey = event.altKey;
  32180. this.shiftKey = event.shiftKey;
  32181. this.ctrlKey = event.ctrlKey;
  32182. }
  32183. this.onDown.dispatch(this, value);
  32184. },
  32185. /**
  32186. * Called automatically by Phaser.Pointer and Phaser.SinglePad.
  32187. * Handles the button up state.
  32188. *
  32189. * @method Phaser.DeviceButton#stop
  32190. * @protected
  32191. * @param {object} [event] - The DOM event that triggered the button change.
  32192. * @param {number} [value] - The button value. Only get for Gamepads.
  32193. */
  32194. stop: function (event, value) {
  32195. if (this.isUp)
  32196. {
  32197. return;
  32198. }
  32199. this.isDown = false;
  32200. this.isUp = true;
  32201. this.timeUp = this.game.time.time;
  32202. this.event = event;
  32203. this.value = value;
  32204. if (event)
  32205. {
  32206. this.altKey = event.altKey;
  32207. this.shiftKey = event.shiftKey;
  32208. this.ctrlKey = event.ctrlKey;
  32209. }
  32210. this.onUp.dispatch(this, value);
  32211. },
  32212. /**
  32213. * Called automatically by Phaser.Pointer.
  32214. * Starts or stops button based on condition.
  32215. *
  32216. * @method Phaser.DeviceButton#startStop
  32217. * @protected
  32218. * @param {boolean} [condition] - The condition that decides between start or stop.
  32219. * @param {object} [event] - The DOM event that triggered the button change.
  32220. * @param {number} [value] - The button value. Only get for Gamepads.
  32221. */
  32222. startStop: function (condition, event, value) {
  32223. if (condition)
  32224. {
  32225. this.start(event, value);
  32226. }
  32227. else
  32228. {
  32229. this.stop(event, value);
  32230. }
  32231. },
  32232. /**
  32233. * Called automatically by Phaser.SinglePad.
  32234. *
  32235. * @method Phaser.DeviceButton#padFloat
  32236. * @protected
  32237. * @param {number} value - Button value
  32238. */
  32239. padFloat: function (value) {
  32240. this.isDown = false;
  32241. this.isUp = false;
  32242. this.value = value;
  32243. this.onFloat.dispatch(this, value);
  32244. },
  32245. /**
  32246. * Returns the "just pressed" state of this button.
  32247. * Just pressed is considered true if the button was pressed down within the duration given (default 250ms).
  32248. *
  32249. * @method Phaser.DeviceButton#justPressed
  32250. * @param {number} [duration=250] - The duration in ms below which the button is considered as being just pressed.
  32251. * @return {boolean} True if the button is just pressed otherwise false.
  32252. */
  32253. justPressed: function (duration) {
  32254. duration = duration || 250;
  32255. return (this.isDown && (this.timeDown + duration) > this.game.time.time);
  32256. },
  32257. /**
  32258. * Returns the "just released" state of this button.
  32259. * Just released is considered as being true if the button was released within the duration given (default 250ms).
  32260. *
  32261. * @method Phaser.DeviceButton#justReleased
  32262. * @param {number} [duration=250] - The duration in ms below which the button is considered as being just released.
  32263. * @return {boolean} True if the button is just released otherwise false.
  32264. */
  32265. justReleased: function (duration) {
  32266. duration = duration || 250;
  32267. return (this.isUp && (this.timeUp + duration) > this.game.time.time);
  32268. },
  32269. /**
  32270. * Resets this DeviceButton, changing it to an isUp state and resetting the duration and repeats counters.
  32271. *
  32272. * @method Phaser.DeviceButton#reset
  32273. */
  32274. reset: function () {
  32275. this.isDown = false;
  32276. this.isUp = true;
  32277. this.timeDown = this.game.time.time;
  32278. this.repeats = 0;
  32279. this.altKey = false;
  32280. this.shiftKey = false;
  32281. this.ctrlKey = false;
  32282. },
  32283. /**
  32284. * Destroys this DeviceButton, this disposes of the onDown, onUp and onFloat signals
  32285. * and clears the parent and game references.
  32286. *
  32287. * @method Phaser.DeviceButton#destroy
  32288. */
  32289. destroy: function () {
  32290. this.onDown.dispose();
  32291. this.onUp.dispose();
  32292. this.onFloat.dispose();
  32293. this.parent = null;
  32294. this.game = null;
  32295. }
  32296. };
  32297. Phaser.DeviceButton.prototype.constructor = Phaser.DeviceButton;
  32298. /**
  32299. * How long the button has been held down for in milliseconds.
  32300. * If not currently down it returns -1.
  32301. *
  32302. * @name Phaser.DeviceButton#duration
  32303. * @property {number} duration
  32304. * @readonly
  32305. */
  32306. Object.defineProperty(Phaser.DeviceButton.prototype, "duration", {
  32307. get: function () {
  32308. if (this.isUp)
  32309. {
  32310. return -1;
  32311. }
  32312. return this.game.time.time - this.timeDown;
  32313. }
  32314. });
  32315. /**
  32316. * @author Richard Davey <rich@photonstorm.com>
  32317. * @copyright 2016 Photon Storm Ltd.
  32318. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  32319. */
  32320. /**
  32321. * A Pointer object is used by the Mouse, Touch and MSPoint managers and represents a single finger on the touch screen.
  32322. *
  32323. * @class Phaser.Pointer
  32324. * @constructor
  32325. * @param {Phaser.Game} game - A reference to the currently running game.
  32326. * @param {number} id - The ID of the Pointer object within the game. Each game can have up to 10 active pointers.
  32327. * @param {Phaser.PointerMode} pointerMode=(CURSOR|CONTACT) - The operational mode of this pointer, eg. CURSOR or TOUCH.
  32328. */
  32329. Phaser.Pointer = function (game, id, pointerMode) {
  32330. /**
  32331. * @property {Phaser.Game} game - A reference to the currently running game.
  32332. */
  32333. this.game = game;
  32334. /**
  32335. * @property {number} id - The ID of the Pointer object within the game. Each game can have up to 10 active pointers.
  32336. */
  32337. this.id = id;
  32338. /**
  32339. * @property {number} type - The const type of this object.
  32340. * @readonly
  32341. */
  32342. this.type = Phaser.POINTER;
  32343. /**
  32344. * @property {boolean} exists - A Pointer object that exists is allowed to be checked for physics collisions and overlaps.
  32345. * @default
  32346. */
  32347. this.exists = true;
  32348. /**
  32349. * @property {number} identifier - The identifier property of the Pointer as set by the DOM event when this Pointer is started.
  32350. * @default
  32351. */
  32352. this.identifier = 0;
  32353. /**
  32354. * @property {number} pointerId - The pointerId property of the Pointer as set by the DOM event when this Pointer is started. The browser can and will recycle this value.
  32355. * @default
  32356. */
  32357. this.pointerId = null;
  32358. /**
  32359. * @property {Phaser.PointerMode} pointerMode - The operational mode of this pointer.
  32360. */
  32361. this.pointerMode = pointerMode || (Phaser.PointerMode.CURSOR | Phaser.PointerMode.CONTACT);
  32362. /**
  32363. * @property {any} target - The target property of the Pointer as set by the DOM event when this Pointer is started.
  32364. * @default
  32365. */
  32366. this.target = null;
  32367. /**
  32368. * The button property of the most recent DOM event when this Pointer is started.
  32369. * You should not rely on this value for accurate button detection, instead use the Pointer properties
  32370. * `leftButton`, `rightButton`, `middleButton` and so on.
  32371. * @property {any} button
  32372. * @default
  32373. */
  32374. this.button = null;
  32375. /**
  32376. * If this Pointer is a Mouse or Pen / Stylus then you can access its left button directly through this property.
  32377. *
  32378. * The DeviceButton has its own properties such as `isDown`, `duration` and methods like `justReleased` for more fine-grained
  32379. * button control.
  32380. *
  32381. * @property {Phaser.DeviceButton} leftButton
  32382. * @default
  32383. */
  32384. this.leftButton = new Phaser.DeviceButton(this, Phaser.Pointer.LEFT_BUTTON);
  32385. /**
  32386. * If this Pointer is a Mouse or Pen / Stylus then you can access its middle button directly through this property.
  32387. *
  32388. * The DeviceButton has its own properties such as `isDown`, `duration` and methods like `justReleased` for more fine-grained
  32389. * button control.
  32390. *
  32391. * Please see the DeviceButton docs for details on browser button limitations.
  32392. *
  32393. * @property {Phaser.DeviceButton} middleButton
  32394. * @default
  32395. */
  32396. this.middleButton = new Phaser.DeviceButton(this, Phaser.Pointer.MIDDLE_BUTTON);
  32397. /**
  32398. * If this Pointer is a Mouse or Pen / Stylus then you can access its right button directly through this property.
  32399. *
  32400. * The DeviceButton has its own properties such as `isDown`, `duration` and methods like `justReleased` for more fine-grained
  32401. * button control.
  32402. *
  32403. * Please see the DeviceButton docs for details on browser button limitations.
  32404. *
  32405. * @property {Phaser.DeviceButton} rightButton
  32406. * @default
  32407. */
  32408. this.rightButton = new Phaser.DeviceButton(this, Phaser.Pointer.RIGHT_BUTTON);
  32409. /**
  32410. * If this Pointer is a Mouse or Pen / Stylus then you can access its X1 (back) button directly through this property.
  32411. *
  32412. * The DeviceButton has its own properties such as `isDown`, `duration` and methods like `justReleased` for more fine-grained
  32413. * button control.
  32414. *
  32415. * Please see the DeviceButton docs for details on browser button limitations.
  32416. *
  32417. * @property {Phaser.DeviceButton} backButton
  32418. * @default
  32419. */
  32420. this.backButton = new Phaser.DeviceButton(this, Phaser.Pointer.BACK_BUTTON);
  32421. /**
  32422. * If this Pointer is a Mouse or Pen / Stylus then you can access its X2 (forward) button directly through this property.
  32423. *
  32424. * The DeviceButton has its own properties such as `isDown`, `duration` and methods like `justReleased` for more fine-grained
  32425. * button control.
  32426. *
  32427. * Please see the DeviceButton docs for details on browser button limitations.
  32428. *
  32429. * @property {Phaser.DeviceButton} forwardButton
  32430. * @default
  32431. */
  32432. this.forwardButton = new Phaser.DeviceButton(this, Phaser.Pointer.FORWARD_BUTTON);
  32433. /**
  32434. * If this Pointer is a Pen / Stylus then you can access its eraser button directly through this property.
  32435. *
  32436. * The DeviceButton has its own properties such as `isDown`, `duration` and methods like `justReleased` for more fine-grained
  32437. * button control.
  32438. *
  32439. * Please see the DeviceButton docs for details on browser button limitations.
  32440. *
  32441. * @property {Phaser.DeviceButton} eraserButton
  32442. * @default
  32443. */
  32444. this.eraserButton = new Phaser.DeviceButton(this, Phaser.Pointer.ERASER_BUTTON);
  32445. /**
  32446. * @property {boolean} _holdSent - Local private variable to store the status of dispatching a hold event.
  32447. * @private
  32448. * @default
  32449. */
  32450. this._holdSent = false;
  32451. /**
  32452. * @property {array} _history - Local private variable storing the short-term history of pointer movements.
  32453. * @private
  32454. */
  32455. this._history = [];
  32456. /**
  32457. * @property {number} _nextDrop - Local private variable storing the time at which the next history drop should occur.
  32458. * @private
  32459. */
  32460. this._nextDrop = 0;
  32461. /**
  32462. * @property {boolean} _stateReset - Monitor events outside of a state reset loop.
  32463. * @private
  32464. */
  32465. this._stateReset = false;
  32466. /**
  32467. * @property {boolean} withinGame - true if the Pointer is over the game canvas, otherwise false.
  32468. */
  32469. this.withinGame = false;
  32470. /**
  32471. * @property {number} clientX - The horizontal coordinate of the Pointer within the application's client area at which the event occurred (as opposed to the coordinates within the page).
  32472. */
  32473. this.clientX = -1;
  32474. /**
  32475. * @property {number} clientY - The vertical coordinate of the Pointer within the application's client area at which the event occurred (as opposed to the coordinates within the page).
  32476. */
  32477. this.clientY = -1;
  32478. /**
  32479. * @property {number} pageX - The horizontal coordinate of the Pointer relative to whole document.
  32480. */
  32481. this.pageX = -1;
  32482. /**
  32483. * @property {number} pageY - The vertical coordinate of the Pointer relative to whole document.
  32484. */
  32485. this.pageY = -1;
  32486. /**
  32487. * @property {number} screenX - The horizontal coordinate of the Pointer relative to the screen.
  32488. */
  32489. this.screenX = -1;
  32490. /**
  32491. * @property {number} screenY - The vertical coordinate of the Pointer relative to the screen.
  32492. */
  32493. this.screenY = -1;
  32494. /**
  32495. * @property {number} rawMovementX - The horizontal raw relative movement of the Pointer in pixels since last event.
  32496. * @default
  32497. */
  32498. this.rawMovementX = 0;
  32499. /**
  32500. * @property {number} rawMovementY - The vertical raw relative movement of the Pointer in pixels since last event.
  32501. * @default
  32502. */
  32503. this.rawMovementY = 0;
  32504. /**
  32505. * @property {number} movementX - The horizontal processed relative movement of the Pointer in pixels since last event.
  32506. * @default
  32507. */
  32508. this.movementX = 0;
  32509. /**
  32510. * @property {number} movementY - The vertical processed relative movement of the Pointer in pixels since last event.
  32511. * @default
  32512. */
  32513. this.movementY = 0;
  32514. /**
  32515. * @property {number} x - The horizontal coordinate of the Pointer. This value is automatically scaled based on the game scale.
  32516. * @default
  32517. */
  32518. this.x = -1;
  32519. /**
  32520. * @property {number} y - The vertical coordinate of the Pointer. This value is automatically scaled based on the game scale.
  32521. * @default
  32522. */
  32523. this.y = -1;
  32524. /**
  32525. * @property {boolean} isMouse - If the Pointer is a mouse or pen / stylus this is true, otherwise false.
  32526. */
  32527. this.isMouse = (id === 0);
  32528. /**
  32529. * If the Pointer is touching the touchscreen, or *any* mouse or pen button is held down, isDown is set to true.
  32530. * If you need to check a specific mouse or pen button then use the button properties, i.e. Pointer.rightButton.isDown.
  32531. * @property {boolean} isDown
  32532. * @default
  32533. */
  32534. this.isDown = false;
  32535. /**
  32536. * If the Pointer is not touching the touchscreen, or *all* mouse or pen buttons are up, isUp is set to true.
  32537. * If you need to check a specific mouse or pen button then use the button properties, i.e. Pointer.rightButton.isUp.
  32538. * @property {boolean} isUp
  32539. * @default
  32540. */
  32541. this.isUp = true;
  32542. /**
  32543. * @property {number} timeDown - A timestamp representing when the Pointer first touched the touchscreen.
  32544. * @default
  32545. */
  32546. this.timeDown = 0;
  32547. /**
  32548. * @property {number} timeUp - A timestamp representing when the Pointer left the touchscreen.
  32549. * @default
  32550. */
  32551. this.timeUp = 0;
  32552. /**
  32553. * @property {number} previousTapTime - A timestamp representing when the Pointer was last tapped or clicked.
  32554. * @default
  32555. */
  32556. this.previousTapTime = 0;
  32557. /**
  32558. * @property {number} totalTouches - The total number of times this Pointer has been touched to the touchscreen.
  32559. * @default
  32560. */
  32561. this.totalTouches = 0;
  32562. /**
  32563. * @property {number} msSinceLastClick - The number of milliseconds since the last click or touch event.
  32564. * @default
  32565. */
  32566. this.msSinceLastClick = Number.MAX_VALUE;
  32567. /**
  32568. * @property {any} targetObject - The Game Object this Pointer is currently over / touching / dragging.
  32569. * @default
  32570. */
  32571. this.targetObject = null;
  32572. /**
  32573. * This array is erased and re-populated every time this Pointer is updated. It contains references to all
  32574. * of the Game Objects that were considered as being valid for processing by this Pointer, this frame. To be
  32575. * valid they must have suitable a `priorityID`, be Input enabled, visible and actually have the Pointer over
  32576. * them. You can check the contents of this array in events such as `onInputDown`, but beware it is reset
  32577. * every frame.
  32578. * @property {array} interactiveCandidates
  32579. * @default
  32580. */
  32581. this.interactiveCandidates = [];
  32582. /**
  32583. * @property {boolean} active - An active pointer is one that is currently pressed down on the display. A Mouse is always active.
  32584. * @default
  32585. */
  32586. this.active = false;
  32587. /**
  32588. * @property {boolean} dirty - A dirty pointer needs to re-poll any interactive objects it may have been over, regardless if it has moved or not.
  32589. * @default
  32590. */
  32591. this.dirty = false;
  32592. /**
  32593. * @property {Phaser.Point} position - A Phaser.Point object containing the current x/y values of the pointer on the display.
  32594. */
  32595. this.position = new Phaser.Point();
  32596. /**
  32597. * @property {Phaser.Point} positionDown - A Phaser.Point object containing the x/y values of the pointer when it was last in a down state on the display.
  32598. */
  32599. this.positionDown = new Phaser.Point();
  32600. /**
  32601. * @property {Phaser.Point} positionUp - A Phaser.Point object containing the x/y values of the pointer when it was last released.
  32602. */
  32603. this.positionUp = new Phaser.Point();
  32604. /**
  32605. * A Phaser.Circle that is centered on the x/y coordinates of this pointer, useful for hit detection.
  32606. * The Circle size is 44px (Apples recommended "finger tip" size).
  32607. * @property {Phaser.Circle} circle
  32608. */
  32609. this.circle = new Phaser.Circle(0, 0, 44);
  32610. /**
  32611. * Click trampolines associated with this pointer. See `addClickTrampoline`.
  32612. * @property {object[]|null} _clickTrampolines
  32613. * @private
  32614. */
  32615. this._clickTrampolines = null;
  32616. /**
  32617. * When the Pointer has click trampolines the last target object is stored here
  32618. * so it can be used to check for validity of the trampoline in a post-Up/'stop'.
  32619. * @property {object} _trampolineTargetObject
  32620. * @private
  32621. */
  32622. this._trampolineTargetObject = null;
  32623. };
  32624. /**
  32625. * No buttons at all.
  32626. * @constant
  32627. * @type {number}
  32628. */
  32629. Phaser.Pointer.NO_BUTTON = 0;
  32630. /**
  32631. * The Left Mouse button, or in PointerEvent devices a Touch contact or Pen contact.
  32632. * @constant
  32633. * @type {number}
  32634. */
  32635. Phaser.Pointer.LEFT_BUTTON = 1;
  32636. /**
  32637. * The Right Mouse button, or in PointerEvent devices a Pen contact with a barrel button.
  32638. * @constant
  32639. * @type {number}
  32640. */
  32641. Phaser.Pointer.RIGHT_BUTTON = 2;
  32642. /**
  32643. * The Middle Mouse button.
  32644. * @constant
  32645. * @type {number}
  32646. */
  32647. Phaser.Pointer.MIDDLE_BUTTON = 4;
  32648. /**
  32649. * The X1 button. This is typically the mouse Back button, but is often reconfigured.
  32650. * On Linux (GTK) this is unsupported. On Windows if advanced pointer software (such as IntelliPoint) is installed this doesn't register.
  32651. * @constant
  32652. * @type {number}
  32653. */
  32654. Phaser.Pointer.BACK_BUTTON = 8;
  32655. /**
  32656. * The X2 button. This is typically the mouse Forward button, but is often reconfigured.
  32657. * On Linux (GTK) this is unsupported. On Windows if advanced pointer software (such as IntelliPoint) is installed this doesn't register.
  32658. * @constant
  32659. * @type {number}
  32660. */
  32661. Phaser.Pointer.FORWARD_BUTTON = 16;
  32662. /**
  32663. * The Eraser pen button on PointerEvent supported devices only.
  32664. * @constant
  32665. * @type {number}
  32666. */
  32667. Phaser.Pointer.ERASER_BUTTON = 32;
  32668. Phaser.Pointer.prototype = {
  32669. /**
  32670. * Resets the states of all the button booleans.
  32671. *
  32672. * @method Phaser.Pointer#resetButtons
  32673. * @protected
  32674. */
  32675. resetButtons: function () {
  32676. this.isDown = false;
  32677. this.isUp = true;
  32678. if (this.isMouse)
  32679. {
  32680. this.leftButton.reset();
  32681. this.middleButton.reset();
  32682. this.rightButton.reset();
  32683. this.backButton.reset();
  32684. this.forwardButton.reset();
  32685. this.eraserButton.reset();
  32686. }
  32687. },
  32688. /**
  32689. * Called by processButtonsUpDown.
  32690. *
  32691. * @method Phaser.Pointer#processButtonsDown
  32692. * @private
  32693. * @param {integer} button - {@link https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button MouseEvent#button} value.
  32694. * @param {MouseEvent} event - The DOM event.
  32695. */
  32696. processButtonsDown: function (button, event) {
  32697. // Note: These are bitwise checks, not booleans
  32698. if (button === Phaser.Mouse.LEFT_BUTTON)
  32699. {
  32700. this.leftButton.start(event);
  32701. }
  32702. if (button === Phaser.Mouse.RIGHT_BUTTON)
  32703. {
  32704. this.rightButton.start(event);
  32705. }
  32706. if (button === Phaser.Mouse.MIDDLE_BUTTON)
  32707. {
  32708. this.middleButton.start(event);
  32709. }
  32710. if (button === Phaser.Mouse.BACK_BUTTON)
  32711. {
  32712. this.backButton.start(event);
  32713. }
  32714. if (button === Phaser.Mouse.FORWARD_BUTTON)
  32715. {
  32716. this.forwardButton.start(event);
  32717. }
  32718. },
  32719. /**
  32720. * Called by processButtonsUpDown.
  32721. *
  32722. * @method Phaser.Pointer#processButtonsUp
  32723. * @private
  32724. * @param {integer} button - {@link https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button MouseEvent#button} value.
  32725. * @param {MouseEvent} event - The DOM event.
  32726. */
  32727. processButtonsUp: function (button, event) {
  32728. // Note: These are bitwise checks, not booleans
  32729. if (button === Phaser.Mouse.LEFT_BUTTON)
  32730. {
  32731. this.leftButton.stop(event);
  32732. }
  32733. if (button === Phaser.Mouse.RIGHT_BUTTON)
  32734. {
  32735. this.rightButton.stop(event);
  32736. }
  32737. if (button === Phaser.Mouse.MIDDLE_BUTTON)
  32738. {
  32739. this.middleButton.stop(event);
  32740. }
  32741. if (button === Phaser.Mouse.BACK_BUTTON)
  32742. {
  32743. this.backButton.stop(event);
  32744. }
  32745. if (button === Phaser.Mouse.FORWARD_BUTTON)
  32746. {
  32747. this.forwardButton.stop(event);
  32748. }
  32749. },
  32750. /**
  32751. * Called by updateButtons.
  32752. *
  32753. * @method Phaser.Pointer#processButtonsUpDown
  32754. * @private
  32755. * @param {integer} buttons - {@link https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons MouseEvent#buttons} value.
  32756. * @param {MouseEvent} event - The DOM event.
  32757. */
  32758. processButtonsUpDown: function (buttons, event) {
  32759. var down = (event.type.toLowerCase().substr(-4) === 'down');
  32760. var move = (event.type.toLowerCase().substr(-4) === 'move');
  32761. if (buttons !== undefined)
  32762. {
  32763. // On OS X (and other devices with trackpads) you have to press CTRL + the pad to initiate a right-click event.
  32764. if (down && buttons === 1 && event.ctrlKey)
  32765. {
  32766. buttons = 2;
  32767. }
  32768. // Note: These are bitwise checks, not booleans
  32769. this.leftButton.startStop(Phaser.Pointer.LEFT_BUTTON & buttons, event);
  32770. this.rightButton.startStop(Phaser.Pointer.RIGHT_BUTTON & buttons, event);
  32771. this.middleButton.startStop(Phaser.Pointer.MIDDLE_BUTTON & buttons, event);
  32772. this.backButton.startStop(Phaser.Pointer.BACK_BUTTON & buttons, event);
  32773. this.forwardButton.startStop(Phaser.Pointer.FORWARD_BUTTON & buttons, event);
  32774. this.eraserButton.startStop(Phaser.Pointer.ERASER_BUTTON & buttons, event);
  32775. }
  32776. else
  32777. {
  32778. // No buttons property (like Safari on OSX when using a trackpad)
  32779. // Attempt to use event.button property or fallback to default
  32780. if (event.button !== undefined)
  32781. {
  32782. // On OS X (and other devices with trackpads) you have to press CTRL + the pad to initiate a right-click event.
  32783. if (down && event.ctrlKey && event.button === 0)
  32784. {
  32785. this.rightButton.start(event);
  32786. }
  32787. else
  32788. {
  32789. if (down)
  32790. {
  32791. this.processButtonsDown(event.button, event);
  32792. }
  32793. else if (!move)
  32794. {
  32795. this.processButtonsUp(event.button, event);
  32796. }
  32797. }
  32798. }
  32799. else
  32800. {
  32801. if (down)
  32802. {
  32803. // On OS X (and other devices with trackpads) you have to press CTRL + the pad to initiate a right-click event.
  32804. if (event.ctrlKey)
  32805. {
  32806. this.rightButton.start(event);
  32807. }
  32808. else
  32809. {
  32810. this.leftButton.start(event);
  32811. }
  32812. }
  32813. else
  32814. {
  32815. this.leftButton.stop(event);
  32816. this.rightButton.stop(event);
  32817. }
  32818. }
  32819. }
  32820. },
  32821. /**
  32822. * Called when the event.buttons property changes from zero.
  32823. * Contains a button bitmask.
  32824. *
  32825. * @method Phaser.Pointer#updateButtons
  32826. * @protected
  32827. * @param {MouseEvent} event - The DOM event.
  32828. */
  32829. updateButtons: function (event) {
  32830. this.button = event.button;
  32831. this.processButtonsUpDown(event.buttons, event);
  32832. this.isUp = true;
  32833. this.isDown = false;
  32834. if (this.leftButton.isDown || this.rightButton.isDown || this.middleButton.isDown || this.backButton.isDown || this.forwardButton.isDown || this.eraserButton.isDown)
  32835. {
  32836. this.isUp = false;
  32837. this.isDown = true;
  32838. }
  32839. },
  32840. /**
  32841. * Called when the Pointer is pressed onto the touchscreen.
  32842. * @method Phaser.Pointer#start
  32843. * @param {any} event - The DOM event from the browser.
  32844. */
  32845. start: function (event) {
  32846. var input = this.game.input;
  32847. if (event['pointerId'])
  32848. {
  32849. this.pointerId = event.pointerId;
  32850. }
  32851. this.identifier = event.identifier;
  32852. this.target = event.target;
  32853. if (this.isMouse)
  32854. {
  32855. this.updateButtons(event);
  32856. }
  32857. else
  32858. {
  32859. this.isDown = true;
  32860. this.isUp = false;
  32861. }
  32862. this.active = true;
  32863. this.withinGame = true;
  32864. this.dirty = false;
  32865. this._history = [];
  32866. this._clickTrampolines = null;
  32867. this._trampolineTargetObject = null;
  32868. // Work out how long it has been since the last click
  32869. this.msSinceLastClick = this.game.time.time - this.timeDown;
  32870. this.timeDown = this.game.time.time;
  32871. this._holdSent = false;
  32872. // This sets the x/y and other local values
  32873. this.move(event, true);
  32874. // x and y are the old values here?
  32875. this.positionDown.setTo(this.x, this.y);
  32876. if (input.multiInputOverride === Phaser.Input.MOUSE_OVERRIDES_TOUCH ||
  32877. input.multiInputOverride === Phaser.Input.MOUSE_TOUCH_COMBINE ||
  32878. (input.multiInputOverride === Phaser.Input.TOUCH_OVERRIDES_MOUSE && input.totalActivePointers === 0))
  32879. {
  32880. input.x = this.x;
  32881. input.y = this.y;
  32882. input.position.setTo(this.x, this.y);
  32883. input.onDown.dispatch(this, event);
  32884. input.resetSpeed(this.x, this.y);
  32885. }
  32886. this._stateReset = false;
  32887. this.totalTouches++;
  32888. if (this.targetObject !== null)
  32889. {
  32890. this.targetObject._touchedHandler(this);
  32891. }
  32892. return this;
  32893. },
  32894. /**
  32895. * Called by the Input Manager.
  32896. * @method Phaser.Pointer#update
  32897. */
  32898. update: function () {
  32899. var input = this.game.input;
  32900. if (this.active)
  32901. {
  32902. // Force a check?
  32903. if (this.dirty)
  32904. {
  32905. if (input.interactiveItems.total > 0)
  32906. {
  32907. this.processInteractiveObjects(false);
  32908. }
  32909. this.dirty = false;
  32910. }
  32911. if (this._holdSent === false && this.duration >= input.holdRate)
  32912. {
  32913. if (input.multiInputOverride === Phaser.Input.MOUSE_OVERRIDES_TOUCH ||
  32914. input.multiInputOverride === Phaser.Input.MOUSE_TOUCH_COMBINE ||
  32915. (input.multiInputOverride === Phaser.Input.TOUCH_OVERRIDES_MOUSE && input.totalActivePointers === 0))
  32916. {
  32917. input.onHold.dispatch(this);
  32918. }
  32919. this._holdSent = true;
  32920. }
  32921. // Update the droppings history
  32922. if (input.recordPointerHistory && this.game.time.time >= this._nextDrop)
  32923. {
  32924. this._nextDrop = this.game.time.time + input.recordRate;
  32925. this._history.push({
  32926. x: this.position.x,
  32927. y: this.position.y
  32928. });
  32929. if (this._history.length > input.recordLimit)
  32930. {
  32931. this._history.shift();
  32932. }
  32933. }
  32934. }
  32935. },
  32936. /**
  32937. * Called when the Pointer is moved.
  32938. *
  32939. * @method Phaser.Pointer#move
  32940. * @param {MouseEvent|PointerEvent|TouchEvent} event - The event passed up from the input handler.
  32941. * @param {boolean} [fromClick=false] - Was this called from the click event?
  32942. */
  32943. move: function (event, fromClick) {
  32944. var input = this.game.input;
  32945. if (input.pollLocked)
  32946. {
  32947. return;
  32948. }
  32949. if (fromClick === undefined) { fromClick = false; }
  32950. if (event.button !== undefined)
  32951. {
  32952. this.button = event.button;
  32953. }
  32954. if (this.isMouse)
  32955. {
  32956. this.updateButtons(event);
  32957. }
  32958. this.clientX = event.clientX;
  32959. this.clientY = event.clientY;
  32960. this.pageX = event.pageX;
  32961. this.pageY = event.pageY;
  32962. this.screenX = event.screenX;
  32963. this.screenY = event.screenY;
  32964. if (this.isMouse && input.mouse.locked && !fromClick)
  32965. {
  32966. this.rawMovementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
  32967. this.rawMovementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
  32968. this.movementX += this.rawMovementX;
  32969. this.movementY += this.rawMovementY;
  32970. }
  32971. this.x = (this.pageX - this.game.scale.offset.x) * input.scale.x;
  32972. this.y = (this.pageY - this.game.scale.offset.y) * input.scale.y;
  32973. this.position.setTo(this.x, this.y);
  32974. this.circle.x = this.x;
  32975. this.circle.y = this.y;
  32976. if (input.multiInputOverride === Phaser.Input.MOUSE_OVERRIDES_TOUCH ||
  32977. input.multiInputOverride === Phaser.Input.MOUSE_TOUCH_COMBINE ||
  32978. (input.multiInputOverride === Phaser.Input.TOUCH_OVERRIDES_MOUSE && input.totalActivePointers === 0))
  32979. {
  32980. input.activePointer = this;
  32981. input.x = this.x;
  32982. input.y = this.y;
  32983. input.position.setTo(input.x, input.y);
  32984. input.circle.x = input.x;
  32985. input.circle.y = input.y;
  32986. }
  32987. this.withinGame = this.game.scale.bounds.contains(this.pageX, this.pageY);
  32988. var i = input.moveCallbacks.length;
  32989. while (i--)
  32990. {
  32991. input.moveCallbacks[i].callback.call(input.moveCallbacks[i].context, this, this.x, this.y, fromClick);
  32992. }
  32993. // Easy out if we're dragging something and it still exists
  32994. if (this.targetObject !== null && (!this.game.paused || this.targetObject.noPause) && this.targetObject.isDragged === true)
  32995. {
  32996. if (this.targetObject.update(this) === false)
  32997. {
  32998. this.targetObject = null;
  32999. }
  33000. }
  33001. else if (input.interactiveItems.total > 0)
  33002. {
  33003. this.processInteractiveObjects(fromClick);
  33004. }
  33005. return this;
  33006. },
  33007. /**
  33008. * Process all interactive objects to find out which ones were updated in the recent Pointer move.
  33009. *
  33010. * @method Phaser.Pointer#processInteractiveObjects
  33011. * @protected
  33012. * @param {boolean} [fromClick=false] - Was this called from the click event?
  33013. * @return {boolean} True if this method processes an object (i.e. a Sprite becomes the Pointers currentTarget), otherwise false.
  33014. */
  33015. processInteractiveObjects: function (fromClick) {
  33016. // Work out which object is on the top
  33017. var highestRenderOrderID = 0;
  33018. var highestInputPriorityID = -1;
  33019. var candidateTarget = null;
  33020. // First pass gets all objects that the pointer is over that DON'T use pixelPerfect checks and get the highest ID
  33021. // We know they'll be valid for input detection but not which is the top just yet
  33022. var currentNode = this.game.input.interactiveItems.first;
  33023. this.interactiveCandidates = [];
  33024. while (currentNode)
  33025. {
  33026. // Reset checked status
  33027. currentNode.checked = false;
  33028. if (currentNode.validForInput(highestInputPriorityID, highestRenderOrderID, false) && (!this.game.paused || currentNode.sprite.noPause))
  33029. {
  33030. // Flag it as checked so we don't re-scan it on the next phase
  33031. currentNode.checked = true;
  33032. if ((fromClick && currentNode.checkPointerDown(this, true)) ||
  33033. (!fromClick && currentNode.checkPointerOver(this, true)))
  33034. {
  33035. highestRenderOrderID = currentNode.sprite.renderOrderID;
  33036. highestInputPriorityID = currentNode.priorityID;
  33037. candidateTarget = currentNode;
  33038. this.interactiveCandidates.push(currentNode);
  33039. }
  33040. }
  33041. currentNode = this.game.input.interactiveItems.next;
  33042. }
  33043. // Then in the second sweep we process ONLY the pixel perfect ones that are checked and who have a higher ID
  33044. // because if their ID is lower anyway then we can just automatically discount them
  33045. // (A node that was previously checked did not request a pixel-perfect check.)
  33046. currentNode = this.game.input.interactiveItems.first;
  33047. while (currentNode)
  33048. {
  33049. if (!currentNode.checked &&
  33050. currentNode.validForInput(highestInputPriorityID, highestRenderOrderID, true))
  33051. {
  33052. if ((fromClick && currentNode.checkPointerDown(this, false)) ||
  33053. (!fromClick && currentNode.checkPointerOver(this, false)))
  33054. {
  33055. highestRenderOrderID = currentNode.sprite.renderOrderID;
  33056. highestInputPriorityID = currentNode.priorityID;
  33057. candidateTarget = currentNode;
  33058. this.interactiveCandidates.push(currentNode);
  33059. }
  33060. }
  33061. currentNode = this.game.input.interactiveItems.next;
  33062. }
  33063. if (this.game.input.customCandidateHandler)
  33064. {
  33065. candidateTarget = this.game.input.customCandidateHandler.call(this.game.input.customCandidateHandlerContext, this, this.interactiveCandidates, candidateTarget);
  33066. }
  33067. this.swapTarget(candidateTarget, false);
  33068. return (this.targetObject !== null);
  33069. },
  33070. /**
  33071. * This will change the `Pointer.targetObject` object to be the one provided.
  33072. *
  33073. * This allows you to have fine-grained control over which object the Pointer is targeting.
  33074. *
  33075. * Note that even if you set a new Target here, it is still able to be replaced by any other valid
  33076. * target during the next Pointer update.
  33077. *
  33078. * @method Phaser.Pointer#swapTarget
  33079. * @param {Phaser.InputHandler} newTarget - The new target for this Pointer. Note this is an `InputHandler`, so don't pass a Sprite, instead pass `sprite.input` to it.
  33080. * @param {boolean} [silent=false] - If true the new target AND the old one will NOT dispatch their `onInputOver` or `onInputOut` events.
  33081. */
  33082. swapTarget: function (newTarget, silent) {
  33083. if (silent === undefined) { silent = false; }
  33084. // Now we know the top-most item (if any) we can process it
  33085. if (newTarget === null)
  33086. {
  33087. // The pointer isn't currently over anything, check if we've got a lingering previous target
  33088. if (this.targetObject)
  33089. {
  33090. this.targetObject._pointerOutHandler(this, silent);
  33091. this.targetObject = null;
  33092. }
  33093. }
  33094. else
  33095. {
  33096. if (this.targetObject === null)
  33097. {
  33098. // And now set the new one
  33099. this.targetObject = newTarget;
  33100. newTarget._pointerOverHandler(this, silent);
  33101. }
  33102. else
  33103. {
  33104. // We've got a target from the last update
  33105. if (this.targetObject === newTarget)
  33106. {
  33107. // Same target as before, so update it
  33108. if (newTarget.update(this) === false)
  33109. {
  33110. this.targetObject = null;
  33111. }
  33112. }
  33113. else
  33114. {
  33115. // The target has changed, so tell the old one we've left it
  33116. this.targetObject._pointerOutHandler(this, silent);
  33117. // And now set the new one
  33118. this.targetObject = newTarget;
  33119. this.targetObject._pointerOverHandler(this, silent);
  33120. }
  33121. }
  33122. }
  33123. },
  33124. /**
  33125. * Called when the Pointer leaves the target area.
  33126. *
  33127. * @method Phaser.Pointer#leave
  33128. * @param {MouseEvent|PointerEvent|TouchEvent} event - The event passed up from the input handler.
  33129. */
  33130. leave: function (event) {
  33131. this.withinGame = false;
  33132. this.move(event, false);
  33133. },
  33134. /**
  33135. * Called when the Pointer leaves the touchscreen.
  33136. *
  33137. * @method Phaser.Pointer#stop
  33138. * @param {MouseEvent|PointerEvent|TouchEvent} event - The event passed up from the input handler.
  33139. */
  33140. stop: function (event) {
  33141. var input = this.game.input;
  33142. if (this._stateReset && this.withinGame)
  33143. {
  33144. event.preventDefault();
  33145. return;
  33146. }
  33147. this.timeUp = this.game.time.time;
  33148. if (input.multiInputOverride === Phaser.Input.MOUSE_OVERRIDES_TOUCH ||
  33149. input.multiInputOverride === Phaser.Input.MOUSE_TOUCH_COMBINE ||
  33150. (input.multiInputOverride === Phaser.Input.TOUCH_OVERRIDES_MOUSE && input.totalActivePointers === 0))
  33151. {
  33152. input.onUp.dispatch(this, event);
  33153. // Was it a tap?
  33154. if (this.duration >= 0 && this.duration <= input.tapRate)
  33155. {
  33156. // Was it a double-tap?
  33157. if (this.timeUp - this.previousTapTime < input.doubleTapRate)
  33158. {
  33159. // Yes, let's dispatch the signal then with the 2nd parameter set to true
  33160. input.onTap.dispatch(this, true);
  33161. }
  33162. else
  33163. {
  33164. // Wasn't a double-tap, so dispatch a single tap signal
  33165. input.onTap.dispatch(this, false);
  33166. }
  33167. this.previousTapTime = this.timeUp;
  33168. }
  33169. }
  33170. if (this.isMouse)
  33171. {
  33172. this.updateButtons(event);
  33173. }
  33174. else
  33175. {
  33176. this.isDown = false;
  33177. this.isUp = true;
  33178. }
  33179. // Mouse is always active
  33180. if (this.id > 0)
  33181. {
  33182. this.active = false;
  33183. }
  33184. this.withinGame = this.game.scale.bounds.contains(event.pageX, event.pageY);
  33185. this.pointerId = null;
  33186. this.identifier = null;
  33187. this.positionUp.setTo(this.x, this.y);
  33188. if (this.isMouse === false)
  33189. {
  33190. input.currentPointers--;
  33191. }
  33192. input.interactiveItems.callAll('_releasedHandler', this);
  33193. if (this._clickTrampolines)
  33194. {
  33195. this._trampolineTargetObject = this.targetObject;
  33196. }
  33197. this.targetObject = null;
  33198. return this;
  33199. },
  33200. /**
  33201. * The Pointer is considered justPressed if the time it was pressed onto the touchscreen or clicked is less than justPressedRate.
  33202. * Note that calling justPressed doesn't reset the pressed status of the Pointer, it will return `true` for as long as the duration is valid.
  33203. * If you wish to check if the Pointer was pressed down just once then see the Sprite.events.onInputDown event.
  33204. * @method Phaser.Pointer#justPressed
  33205. * @param {number} [duration] - The time to check against. If none given it will use InputManager.justPressedRate.
  33206. * @return {boolean} true if the Pointer was pressed down within the duration given.
  33207. */
  33208. justPressed: function (duration) {
  33209. duration = duration || this.game.input.justPressedRate;
  33210. return (this.isDown === true && (this.timeDown + duration) > this.game.time.time);
  33211. },
  33212. /**
  33213. * The Pointer is considered justReleased if the time it left the touchscreen is less than justReleasedRate.
  33214. * Note that calling justReleased doesn't reset the pressed status of the Pointer, it will return `true` for as long as the duration is valid.
  33215. * If you wish to check if the Pointer was released just once then see the Sprite.events.onInputUp event.
  33216. * @method Phaser.Pointer#justReleased
  33217. * @param {number} [duration] - The time to check against. If none given it will use InputManager.justReleasedRate.
  33218. * @return {boolean} true if the Pointer was released within the duration given.
  33219. */
  33220. justReleased: function (duration) {
  33221. duration = duration || this.game.input.justReleasedRate;
  33222. return (this.isUp && (this.timeUp + duration) > this.game.time.time);
  33223. },
  33224. /**
  33225. * Add a click trampoline to this pointer.
  33226. *
  33227. * A click trampoline is a callback that is run on the DOM 'click' event; this is primarily
  33228. * needed with certain browsers (ie. IE11) which restrict some actions like requestFullscreen
  33229. * to the DOM 'click' event and rejects it for 'pointer*' and 'mouse*' events.
  33230. *
  33231. * This is used internally by the ScaleManager; click trampoline usage is uncommon.
  33232. * Click trampolines can only be added to pointers that are currently down.
  33233. *
  33234. * @method Phaser.Pointer#addClickTrampoline
  33235. * @protected
  33236. * @param {string} name - The name of the trampoline; must be unique among active trampolines in this pointer.
  33237. * @param {function} callback - Callback to run/trampoline.
  33238. * @param {object} callbackContext - Context of the callback.
  33239. * @param {object[]|null} callbackArgs - Additional callback args, if any. Supplied as an array.
  33240. */
  33241. addClickTrampoline: function (name, callback, callbackContext, callbackArgs) {
  33242. if (!this.isDown)
  33243. {
  33244. return;
  33245. }
  33246. var trampolines = (this._clickTrampolines = this._clickTrampolines || []);
  33247. for (var i = 0; i < trampolines.length; i++)
  33248. {
  33249. if (trampolines[i].name === name)
  33250. {
  33251. trampolines.splice(i, 1);
  33252. break;
  33253. }
  33254. }
  33255. trampolines.push({
  33256. name: name,
  33257. targetObject: this.targetObject,
  33258. callback: callback,
  33259. callbackContext: callbackContext,
  33260. callbackArgs: callbackArgs
  33261. });
  33262. },
  33263. /**
  33264. * Fire all click trampolines for which the pointers are still referring to the registered object.
  33265. * @method Phaser.Pointer#processClickTrampolines
  33266. * @private
  33267. */
  33268. processClickTrampolines: function () {
  33269. var trampolines = this._clickTrampolines;
  33270. if (!trampolines)
  33271. {
  33272. return;
  33273. }
  33274. for (var i = 0; i < trampolines.length; i++)
  33275. {
  33276. var trampoline = trampolines[i];
  33277. if (trampoline.targetObject === this._trampolineTargetObject)
  33278. {
  33279. trampoline.callback.apply(trampoline.callbackContext, trampoline.callbackArgs);
  33280. }
  33281. }
  33282. this._clickTrampolines = null;
  33283. this._trampolineTargetObject = null;
  33284. },
  33285. /**
  33286. * Resets the Pointer properties. Called by InputManager.reset when you perform a State change.
  33287. * @method Phaser.Pointer#reset
  33288. */
  33289. reset: function () {
  33290. if (this.isMouse === false)
  33291. {
  33292. this.active = false;
  33293. }
  33294. this.pointerId = null;
  33295. this.identifier = null;
  33296. this.dirty = false;
  33297. this.totalTouches = 0;
  33298. this._holdSent = false;
  33299. this._history.length = 0;
  33300. this._stateReset = true;
  33301. this.resetButtons();
  33302. if (this.targetObject)
  33303. {
  33304. this.targetObject._releasedHandler(this);
  33305. }
  33306. this.targetObject = null;
  33307. },
  33308. /**
  33309. * Resets the movementX and movementY properties. Use in your update handler after retrieving the values.
  33310. * @method Phaser.Pointer#resetMovement
  33311. */
  33312. resetMovement: function() {
  33313. this.movementX = 0;
  33314. this.movementY = 0;
  33315. }
  33316. };
  33317. Phaser.Pointer.prototype.constructor = Phaser.Pointer;
  33318. /**
  33319. * How long the Pointer has been depressed on the touchscreen or *any* of the mouse buttons have been held down.
  33320. * If not currently down it returns -1.
  33321. * If you need to test a specific mouse or pen button then access the buttons directly, i.e. `Pointer.rightButton.duration`.
  33322. *
  33323. * @name Phaser.Pointer#duration
  33324. * @property {number} duration
  33325. * @readonly
  33326. */
  33327. Object.defineProperty(Phaser.Pointer.prototype, "duration", {
  33328. get: function () {
  33329. if (this.isUp)
  33330. {
  33331. return -1;
  33332. }
  33333. return this.game.time.time - this.timeDown;
  33334. }
  33335. });
  33336. /**
  33337. * Gets the X value of this Pointer in world coordinates based on the world camera.
  33338. * @name Phaser.Pointer#worldX
  33339. * @property {number} worldX - The X value of this Pointer in world coordinates based on the world camera.
  33340. * @readonly
  33341. */
  33342. Object.defineProperty(Phaser.Pointer.prototype, "worldX", {
  33343. get: function () {
  33344. return this.game.world.camera.x + this.x;
  33345. }
  33346. });
  33347. /**
  33348. * Gets the Y value of this Pointer in world coordinates based on the world camera.
  33349. * @name Phaser.Pointer#worldY
  33350. * @property {number} worldY - The Y value of this Pointer in world coordinates based on the world camera.
  33351. * @readonly
  33352. */
  33353. Object.defineProperty(Phaser.Pointer.prototype, "worldY", {
  33354. get: function () {
  33355. return this.game.world.camera.y + this.y;
  33356. }
  33357. });
  33358. /**
  33359. * Enumeration categorizing operational modes of pointers.
  33360. *
  33361. * PointerType values represent valid bitmasks.
  33362. * For example, a value representing both Mouse and Touch devices
  33363. * can be expressed as `PointerMode.CURSOR | PointerMode.CONTACT`.
  33364. *
  33365. * Values may be added for future mode categorizations.
  33366. * @class Phaser.PointerMode
  33367. */
  33368. Phaser.PointerMode = {
  33369. /**
  33370. * A 'CURSOR' is a pointer with a *passive cursor* such as a mouse, touchpad, watcom stylus, or even TV-control arrow-pad.
  33371. *
  33372. * It has the property that a cursor is passively moved without activating the input.
  33373. * This currently corresponds with {@link Phaser.Pointer#isMouse} property.
  33374. * @constant
  33375. */
  33376. CURSOR: 1 << 0,
  33377. /**
  33378. * A 'CONTACT' pointer has an *active cursor* that only tracks movement when actived; notably this is a touch-style input.
  33379. * @constant
  33380. */
  33381. CONTACT: 1 << 1
  33382. };
  33383. /**
  33384. * @author Richard Davey <rich@photonstorm.com>
  33385. * @copyright 2016 Photon Storm Ltd.
  33386. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  33387. */
  33388. /**
  33389. * Phaser.Touch handles touch events with your game. Note: Android 2.x only supports 1 touch event at once, no multi-touch.
  33390. *
  33391. * You should not normally access this class directly, but instead use a Phaser.Pointer object which normalises all game input for you.
  33392. *
  33393. * @class Phaser.Touch
  33394. * @constructor
  33395. * @param {Phaser.Game} game - A reference to the currently running game.
  33396. */
  33397. Phaser.Touch = function (game) {
  33398. /**
  33399. * @property {Phaser.Game} game - A reference to the currently running game.
  33400. */
  33401. this.game = game;
  33402. /**
  33403. * Touch events will only be processed if enabled.
  33404. * @property {boolean} enabled
  33405. * @default
  33406. */
  33407. this.enabled = true;
  33408. /**
  33409. * @property {object} callbackContext - The context under which callbacks are called.
  33410. */
  33411. this.callbackContext = this.game;
  33412. /**
  33413. * @property {function} touchStartCallback - A callback that can be fired on a touchStart event.
  33414. */
  33415. this.touchStartCallback = null;
  33416. /**
  33417. * @property {function} touchMoveCallback - A callback that can be fired on a touchMove event.
  33418. */
  33419. this.touchMoveCallback = null;
  33420. /**
  33421. * @property {function} touchEndCallback - A callback that can be fired on a touchEnd event.
  33422. */
  33423. this.touchEndCallback = null;
  33424. /**
  33425. * @property {function} touchEnterCallback - A callback that can be fired on a touchEnter event.
  33426. */
  33427. this.touchEnterCallback = null;
  33428. /**
  33429. * @property {function} touchLeaveCallback - A callback that can be fired on a touchLeave event.
  33430. */
  33431. this.touchLeaveCallback = null;
  33432. /**
  33433. * @property {function} touchCancelCallback - A callback that can be fired on a touchCancel event.
  33434. */
  33435. this.touchCancelCallback = null;
  33436. /**
  33437. * @property {boolean} preventDefault - If true the TouchEvent will have prevent.default called on it.
  33438. * @default
  33439. */
  33440. this.preventDefault = true;
  33441. /**
  33442. * @property {TouchEvent} event - The browser touch DOM event. Will be set to null if no touch event has ever been received.
  33443. * @default
  33444. */
  33445. this.event = null;
  33446. /**
  33447. * @property {function} _onTouchStart - Internal event handler reference.
  33448. * @private
  33449. */
  33450. this._onTouchStart = null;
  33451. /**
  33452. * @property {function} _onTouchMove - Internal event handler reference.
  33453. * @private
  33454. */
  33455. this._onTouchMove = null;
  33456. /**
  33457. * @property {function} _onTouchEnd - Internal event handler reference.
  33458. * @private
  33459. */
  33460. this._onTouchEnd = null;
  33461. /**
  33462. * @property {function} _onTouchEnter - Internal event handler reference.
  33463. * @private
  33464. */
  33465. this._onTouchEnter = null;
  33466. /**
  33467. * @property {function} _onTouchLeave - Internal event handler reference.
  33468. * @private
  33469. */
  33470. this._onTouchLeave = null;
  33471. /**
  33472. * @property {function} _onTouchCancel - Internal event handler reference.
  33473. * @private
  33474. */
  33475. this._onTouchCancel = null;
  33476. /**
  33477. * @property {function} _onTouchMove - Internal event handler reference.
  33478. * @private
  33479. */
  33480. this._onTouchMove = null;
  33481. };
  33482. Phaser.Touch.prototype = {
  33483. /**
  33484. * Starts the event listeners running.
  33485. * @method Phaser.Touch#start
  33486. */
  33487. start: function () {
  33488. if (this._onTouchStart !== null)
  33489. {
  33490. // Avoid setting multiple listeners
  33491. return;
  33492. }
  33493. var _this = this;
  33494. if (this.game.device.touch)
  33495. {
  33496. this._onTouchStart = function (event) {
  33497. return _this.onTouchStart(event);
  33498. };
  33499. this._onTouchMove = function (event) {
  33500. return _this.onTouchMove(event);
  33501. };
  33502. this._onTouchEnd = function (event) {
  33503. return _this.onTouchEnd(event);
  33504. };
  33505. this._onTouchEnter = function (event) {
  33506. return _this.onTouchEnter(event);
  33507. };
  33508. this._onTouchLeave = function (event) {
  33509. return _this.onTouchLeave(event);
  33510. };
  33511. this._onTouchCancel = function (event) {
  33512. return _this.onTouchCancel(event);
  33513. };
  33514. this.game.canvas.addEventListener('touchstart', this._onTouchStart, false);
  33515. this.game.canvas.addEventListener('touchmove', this._onTouchMove, false);
  33516. this.game.canvas.addEventListener('touchend', this._onTouchEnd, false);
  33517. this.game.canvas.addEventListener('touchcancel', this._onTouchCancel, false);
  33518. if (!this.game.device.cocoonJS)
  33519. {
  33520. this.game.canvas.addEventListener('touchenter', this._onTouchEnter, false);
  33521. this.game.canvas.addEventListener('touchleave', this._onTouchLeave, false);
  33522. }
  33523. }
  33524. /**
  33525. * Adds a callback that is fired when a browser touchstart or touchend event is received.
  33526. *
  33527. * @method Phaser.Touch#addTouchLockCallback
  33528. * @deprecated Use {@link Phaser.Input#addTouchLockCallback} instead.
  33529. */
  33530. this.addTouchLockCallback = this.game.input.addTouchLockCallback.bind(this.game.input);
  33531. /**
  33532. * Removes the callback at the defined index from the touchLockCallbacks array.
  33533. *
  33534. * @method Phaser.Touch#removeTouchLockCallback
  33535. * @deprecated Use {@link Phaser.Input#removeTouchLockCallback} instead.
  33536. */
  33537. this.removeTouchLockCallback = this.game.input.removeTouchLockCallback.bind(this.game.input);
  33538. },
  33539. /**
  33540. * Consumes all touchmove events on the document (only enable this if you know you need it!).
  33541. * @method Phaser.Touch#consumeTouchMove
  33542. */
  33543. consumeDocumentTouches: function () {
  33544. this._documentTouchMove = function (event) {
  33545. event.preventDefault();
  33546. };
  33547. document.addEventListener('touchmove', this._documentTouchMove, false);
  33548. },
  33549. /**
  33550. * The internal method that handles the touchstart event from the browser.
  33551. * @method Phaser.Touch#onTouchStart
  33552. * @param {TouchEvent} event - The native event from the browser. This gets stored in Touch.event.
  33553. */
  33554. onTouchStart: function (event) {
  33555. this.game.input.executeTouchLockCallbacks(false, event);
  33556. this.event = event;
  33557. if (!this.game.input.enabled || !this.enabled)
  33558. {
  33559. return;
  33560. }
  33561. if (this.touchStartCallback)
  33562. {
  33563. this.touchStartCallback.call(this.callbackContext, event);
  33564. }
  33565. if (this.preventDefault)
  33566. {
  33567. event.preventDefault();
  33568. }
  33569. // event.targetTouches = list of all touches on the TARGET ELEMENT (i.e. game dom element)
  33570. // event.touches = list of all touches on the ENTIRE DOCUMENT, not just the target element
  33571. // event.changedTouches = the touches that CHANGED in this event, not the total number of them
  33572. for (var i = 0; i < event.changedTouches.length; i++)
  33573. {
  33574. this.game.input.startPointer(event.changedTouches[i]);
  33575. }
  33576. },
  33577. /**
  33578. * Touch cancel - touches that were disrupted (perhaps by moving into a plugin or browser chrome).
  33579. * Occurs for example on iOS when you put down 4 fingers and the app selector UI appears.
  33580. * @method Phaser.Touch#onTouchCancel
  33581. * @param {TouchEvent} event - The native event from the browser. This gets stored in Touch.event.
  33582. */
  33583. onTouchCancel: function (event) {
  33584. this.event = event;
  33585. if (this.touchCancelCallback)
  33586. {
  33587. this.touchCancelCallback.call(this.callbackContext, event);
  33588. }
  33589. if (!this.game.input.enabled || !this.enabled)
  33590. {
  33591. return;
  33592. }
  33593. if (this.preventDefault)
  33594. {
  33595. event.preventDefault();
  33596. }
  33597. // Touch cancel - touches that were disrupted (perhaps by moving into a plugin or browser chrome)
  33598. // http://www.w3.org/TR/touch-events/#dfn-touchcancel
  33599. for (var i = 0; i < event.changedTouches.length; i++)
  33600. {
  33601. this.game.input.stopPointer(event.changedTouches[i]);
  33602. }
  33603. },
  33604. /**
  33605. * For touch enter and leave its a list of the touch points that have entered or left the target.
  33606. * Doesn't appear to be supported by most browsers on a canvas element yet.
  33607. * @method Phaser.Touch#onTouchEnter
  33608. * @param {TouchEvent} event - The native event from the browser. This gets stored in Touch.event.
  33609. */
  33610. onTouchEnter: function (event) {
  33611. this.event = event;
  33612. if (this.touchEnterCallback)
  33613. {
  33614. this.touchEnterCallback.call(this.callbackContext, event);
  33615. }
  33616. if (!this.game.input.enabled || !this.enabled)
  33617. {
  33618. return;
  33619. }
  33620. if (this.preventDefault)
  33621. {
  33622. event.preventDefault();
  33623. }
  33624. },
  33625. /**
  33626. * For touch enter and leave its a list of the touch points that have entered or left the target.
  33627. * Doesn't appear to be supported by most browsers on a canvas element yet.
  33628. * @method Phaser.Touch#onTouchLeave
  33629. * @param {TouchEvent} event - The native event from the browser. This gets stored in Touch.event.
  33630. */
  33631. onTouchLeave: function (event) {
  33632. this.event = event;
  33633. if (this.touchLeaveCallback)
  33634. {
  33635. this.touchLeaveCallback.call(this.callbackContext, event);
  33636. }
  33637. if (this.preventDefault)
  33638. {
  33639. event.preventDefault();
  33640. }
  33641. },
  33642. /**
  33643. * The handler for the touchmove events.
  33644. * @method Phaser.Touch#onTouchMove
  33645. * @param {TouchEvent} event - The native event from the browser. This gets stored in Touch.event.
  33646. */
  33647. onTouchMove: function (event) {
  33648. this.event = event;
  33649. if (this.touchMoveCallback)
  33650. {
  33651. this.touchMoveCallback.call(this.callbackContext, event);
  33652. }
  33653. if (this.preventDefault)
  33654. {
  33655. event.preventDefault();
  33656. }
  33657. for (var i = 0; i < event.changedTouches.length; i++)
  33658. {
  33659. this.game.input.updatePointer(event.changedTouches[i]);
  33660. }
  33661. },
  33662. /**
  33663. * The handler for the touchend events.
  33664. * @method Phaser.Touch#onTouchEnd
  33665. * @param {TouchEvent} event - The native event from the browser. This gets stored in Touch.event.
  33666. */
  33667. onTouchEnd: function (event) {
  33668. this.game.input.executeTouchLockCallbacks(true, event);
  33669. this.event = event;
  33670. if (this.touchEndCallback)
  33671. {
  33672. this.touchEndCallback.call(this.callbackContext, event);
  33673. }
  33674. if (this.preventDefault)
  33675. {
  33676. event.preventDefault();
  33677. }
  33678. // For touch end its a list of the touch points that have been removed from the surface
  33679. // https://developer.mozilla.org/en-US/docs/DOM/TouchList
  33680. // event.changedTouches = the touches that CHANGED in this event, not the total number of them
  33681. for (var i = 0; i < event.changedTouches.length; i++)
  33682. {
  33683. this.game.input.stopPointer(event.changedTouches[i]);
  33684. }
  33685. },
  33686. /**
  33687. * Stop the event listeners.
  33688. * @method Phaser.Touch#stop
  33689. */
  33690. stop: function () {
  33691. if (this.game.device.touch)
  33692. {
  33693. this.game.canvas.removeEventListener('touchstart', this._onTouchStart);
  33694. this.game.canvas.removeEventListener('touchmove', this._onTouchMove);
  33695. this.game.canvas.removeEventListener('touchend', this._onTouchEnd);
  33696. this.game.canvas.removeEventListener('touchenter', this._onTouchEnter);
  33697. this.game.canvas.removeEventListener('touchleave', this._onTouchLeave);
  33698. this.game.canvas.removeEventListener('touchcancel', this._onTouchCancel);
  33699. }
  33700. }
  33701. };
  33702. Phaser.Touch.prototype.constructor = Phaser.Touch;
  33703. /**
  33704. * @author Richard Davey <rich@photonstorm.com>
  33705. * @copyright 2016 Photon Storm Ltd.
  33706. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  33707. */
  33708. /**
  33709. * The Input Handler is bound to a specific Sprite and is responsible for managing all Input events on that Sprite.
  33710. *
  33711. * @class Phaser.InputHandler
  33712. * @constructor
  33713. * @param {Phaser.Sprite} sprite - The Sprite object to which this Input Handler belongs.
  33714. */
  33715. Phaser.InputHandler = function (sprite) {
  33716. /**
  33717. * @property {Phaser.Sprite} sprite - The Sprite object to which this Input Handler belongs.
  33718. */
  33719. this.sprite = sprite;
  33720. /**
  33721. * @property {Phaser.Game} game - A reference to the currently running game.
  33722. */
  33723. this.game = sprite.game;
  33724. /**
  33725. * @property {boolean} enabled - If enabled the Input Handler will process input requests and monitor pointer activity.
  33726. * @default
  33727. */
  33728. this.enabled = false;
  33729. /**
  33730. * @property {boolean} checked - A disposable flag used by the Pointer class when performing priority checks.
  33731. * @protected
  33732. */
  33733. this.checked = false;
  33734. /**
  33735. * The priorityID is used to determine which game objects should get priority when input events occur. For example if you have
  33736. * several Sprites that overlap, by default the one at the top of the display list is given priority for input events. You can
  33737. * stop this from happening by controlling the priorityID value. The higher the value, the more important they are considered to the Input events.
  33738. * @property {number} priorityID
  33739. * @default
  33740. */
  33741. this.priorityID = 0;
  33742. /**
  33743. * @property {boolean} useHandCursor - On a desktop browser you can set the 'hand' cursor to appear when moving over the Sprite.
  33744. * @default
  33745. */
  33746. this.useHandCursor = false;
  33747. /**
  33748. * @property {boolean} _setHandCursor - Did this Sprite trigger the hand cursor?
  33749. * @private
  33750. */
  33751. this._setHandCursor = false;
  33752. /**
  33753. * @property {boolean} isDragged - true if the Sprite is being currently dragged.
  33754. * @default
  33755. */
  33756. this.isDragged = false;
  33757. /**
  33758. * @property {boolean} allowHorizontalDrag - Controls if the Sprite is allowed to be dragged horizontally.
  33759. * @default
  33760. */
  33761. this.allowHorizontalDrag = true;
  33762. /**
  33763. * @property {boolean} allowVerticalDrag - Controls if the Sprite is allowed to be dragged vertically.
  33764. * @default
  33765. */
  33766. this.allowVerticalDrag = true;
  33767. /**
  33768. * @property {boolean} bringToTop - If true when this Sprite is clicked or dragged it will automatically be bought to the top of the Group it is within.
  33769. * @default
  33770. */
  33771. this.bringToTop = false;
  33772. /**
  33773. * @property {Phaser.Point} snapOffset - A Point object that contains by how far the Sprite snap is offset.
  33774. * @default
  33775. */
  33776. this.snapOffset = null;
  33777. /**
  33778. * @property {boolean} snapOnDrag - When the Sprite is dragged this controls if the center of the Sprite will snap to the pointer on drag or not.
  33779. * @default
  33780. */
  33781. this.snapOnDrag = false;
  33782. /**
  33783. * @property {boolean} snapOnRelease - When the Sprite is dragged this controls if the Sprite will be snapped on release.
  33784. * @default
  33785. */
  33786. this.snapOnRelease = false;
  33787. /**
  33788. * @property {number} snapX - When a Sprite has snapping enabled this holds the width of the snap grid.
  33789. * @default
  33790. */
  33791. this.snapX = 0;
  33792. /**
  33793. * @property {number} snapY - When a Sprite has snapping enabled this holds the height of the snap grid.
  33794. * @default
  33795. */
  33796. this.snapY = 0;
  33797. /**
  33798. * @property {number} snapOffsetX - This defines the top-left X coordinate of the snap grid.
  33799. * @default
  33800. */
  33801. this.snapOffsetX = 0;
  33802. /**
  33803. * @property {number} snapOffsetY - This defines the top-left Y coordinate of the snap grid..
  33804. * @default
  33805. */
  33806. this.snapOffsetY = 0;
  33807. /**
  33808. * Set to true to use pixel perfect hit detection when checking if the pointer is over this Sprite.
  33809. * The x/y coordinates of the pointer are tested against the image in combination with the InputHandler.pixelPerfectAlpha value.
  33810. * This feature only works for display objects with image based textures such as Sprites. It won't work on BitmapText or Rope.
  33811. * Warning: This is expensive, especially on mobile (where it's not even needed!) so only enable if required. Also see the less-expensive InputHandler.pixelPerfectClick.
  33812. * @property {boolean} pixelPerfectOver - Use a pixel perfect check when testing for pointer over.
  33813. * @default
  33814. */
  33815. this.pixelPerfectOver = false;
  33816. /**
  33817. * Set to true to use pixel perfect hit detection when checking if the pointer is over this Sprite when it's clicked or touched.
  33818. * The x/y coordinates of the pointer are tested against the image in combination with the InputHandler.pixelPerfectAlpha value.
  33819. * This feature only works for display objects with image based textures such as Sprites. It won't work on BitmapText or Rope.
  33820. * Warning: This is expensive so only enable if you really need it.
  33821. * @property {boolean} pixelPerfectClick - Use a pixel perfect check when testing for clicks or touches on the Sprite.
  33822. * @default
  33823. */
  33824. this.pixelPerfectClick = false;
  33825. /**
  33826. * @property {number} pixelPerfectAlpha - The alpha tolerance threshold. If the alpha value of the pixel matches or is above this value, it's considered a hit.
  33827. * @default
  33828. */
  33829. this.pixelPerfectAlpha = 255;
  33830. /**
  33831. * @property {boolean} draggable - Is this sprite allowed to be dragged by the mouse? true = yes, false = no
  33832. * @default
  33833. */
  33834. this.draggable = false;
  33835. /**
  33836. * @property {Phaser.Rectangle} boundsRect - A region of the game world within which the sprite is restricted during drag.
  33837. * @default
  33838. */
  33839. this.boundsRect = null;
  33840. /**
  33841. * @property {Phaser.Sprite} boundsSprite - A Sprite the bounds of which this sprite is restricted during drag.
  33842. * @default
  33843. */
  33844. this.boundsSprite = null;
  33845. /**
  33846. * @property {boolean} scaleLayer - EXPERIMENTAL: Please do not use this property unless you know what it does. Likely to change in the future.
  33847. */
  33848. this.scaleLayer = false;
  33849. /**
  33850. * @property {Phaser.Point} dragOffset - The offset from the Sprites position that dragging takes place from.
  33851. */
  33852. this.dragOffset = new Phaser.Point();
  33853. /**
  33854. * @property {boolean} dragFromCenter - Is the Sprite dragged from its center, or the point at which the Pointer was pressed down upon it?
  33855. */
  33856. this.dragFromCenter = false;
  33857. /**
  33858. * @property {boolean} dragStopBlocksInputUp - If enabled, when the Sprite stops being dragged, it will only dispatch the `onDragStop` event, and not the `onInputUp` event. If set to `false` it will dispatch both events.
  33859. */
  33860. this.dragStopBlocksInputUp = false;
  33861. /**
  33862. * @property {Phaser.Point} dragStartPoint - The Point from which the most recent drag started from. Useful if you need to return an object to its starting position.
  33863. */
  33864. this.dragStartPoint = new Phaser.Point();
  33865. /**
  33866. * @property {integer} dragDistanceThreshold - The distance, in pixels, the pointer has to move while being held down, before the Sprite thinks it is being dragged.
  33867. */
  33868. this.dragDistanceThreshold = 0;
  33869. /**
  33870. * @property {integer} dragTimeThreshold - The amount of time, in ms, the pointer has to be held down over the Sprite before it thinks it is being dragged.
  33871. */
  33872. this.dragTimeThreshold = 0;
  33873. /**
  33874. * @property {Phaser.Point} downPoint - A Point object containing the coordinates of the Pointer when it was first pressed down onto this Sprite.
  33875. */
  33876. this.downPoint = new Phaser.Point();
  33877. /**
  33878. * @property {Phaser.Point} snapPoint - If the sprite is set to snap while dragging this holds the point of the most recent 'snap' event.
  33879. */
  33880. this.snapPoint = new Phaser.Point();
  33881. /**
  33882. * @property {Phaser.Point} _dragPoint - Internal cache var.
  33883. * @private
  33884. */
  33885. this._dragPoint = new Phaser.Point();
  33886. /**
  33887. * @property {boolean} _dragPhase - Internal cache var.
  33888. * @private
  33889. */
  33890. this._dragPhase = false;
  33891. /**
  33892. * @property {boolean} _pendingDrag - Internal cache var.
  33893. * @private
  33894. */
  33895. this._pendingDrag = false;
  33896. /**
  33897. * @property {boolean} _dragTimePass - Internal cache var.
  33898. * @private
  33899. */
  33900. this._dragTimePass = false;
  33901. /**
  33902. * @property {boolean} _dragDistancePass - Internal cache var.
  33903. * @private
  33904. */
  33905. this._dragDistancePass = false;
  33906. /**
  33907. * @property {boolean} _wasEnabled - Internal cache var.
  33908. * @private
  33909. */
  33910. this._wasEnabled = false;
  33911. /**
  33912. * @property {Phaser.Point} _tempPoint - Internal cache var.
  33913. * @private
  33914. */
  33915. this._tempPoint = new Phaser.Point();
  33916. /**
  33917. * @property {array} _pointerData - Internal cache var.
  33918. * @private
  33919. */
  33920. this._pointerData = [];
  33921. this._pointerData.push({
  33922. id: 0,
  33923. x: 0,
  33924. y: 0,
  33925. camX: 0,
  33926. camY: 0,
  33927. isDown: false,
  33928. isUp: false,
  33929. isOver: false,
  33930. isOut: false,
  33931. timeOver: 0,
  33932. timeOut: 0,
  33933. timeDown: 0,
  33934. timeUp: 0,
  33935. downDuration: 0,
  33936. isDragged: false
  33937. });
  33938. };
  33939. Phaser.InputHandler.prototype = {
  33940. /**
  33941. * Starts the Input Handler running. This is called automatically when you enable input on a Sprite, or can be called directly if you need to set a specific priority.
  33942. *
  33943. * @method Phaser.InputHandler#start
  33944. * @param {number} [priority=0] - Higher priority sprites take click priority over low-priority sprites when they are stacked on-top of each other.
  33945. * @param {boolean} [useHandCursor=false] - If true the Sprite will show the hand cursor on mouse-over (doesn't apply to mobile browsers)
  33946. * @return {Phaser.Sprite} The Sprite object to which the Input Handler is bound.
  33947. */
  33948. start: function (priority, useHandCursor) {
  33949. priority = priority || 0;
  33950. if (useHandCursor === undefined) { useHandCursor = false; }
  33951. // Turning on
  33952. if (this.enabled === false)
  33953. {
  33954. // Register, etc
  33955. this.game.input.interactiveItems.add(this);
  33956. this.useHandCursor = useHandCursor;
  33957. this.priorityID = priority;
  33958. for (var i = 0; i < 10; i++)
  33959. {
  33960. this._pointerData[i] = {
  33961. id: i,
  33962. x: 0,
  33963. y: 0,
  33964. isDown: false,
  33965. isUp: false,
  33966. isOver: false,
  33967. isOut: false,
  33968. timeOver: 0,
  33969. timeOut: 0,
  33970. timeDown: 0,
  33971. timeUp: 0,
  33972. downDuration: 0,
  33973. isDragged: false
  33974. };
  33975. }
  33976. this.snapOffset = new Phaser.Point();
  33977. this.enabled = true;
  33978. this._wasEnabled = true;
  33979. }
  33980. this.sprite.events.onAddedToGroup.add(this.addedToGroup, this);
  33981. this.sprite.events.onRemovedFromGroup.add(this.removedFromGroup, this);
  33982. return this.sprite;
  33983. },
  33984. /**
  33985. * Handles when the parent Sprite is added to a new Group.
  33986. *
  33987. * @method Phaser.InputHandler#addedToGroup
  33988. * @private
  33989. */
  33990. addedToGroup: function () {
  33991. if (this._dragPhase)
  33992. {
  33993. return;
  33994. }
  33995. if (this._wasEnabled && !this.enabled)
  33996. {
  33997. this.start();
  33998. }
  33999. },
  34000. /**
  34001. * Handles when the parent Sprite is removed from a Group.
  34002. *
  34003. * @method Phaser.InputHandler#removedFromGroup
  34004. * @private
  34005. */
  34006. removedFromGroup: function () {
  34007. if (this._dragPhase)
  34008. {
  34009. return;
  34010. }
  34011. if (this.enabled)
  34012. {
  34013. this._wasEnabled = true;
  34014. this.stop();
  34015. }
  34016. else
  34017. {
  34018. this._wasEnabled = false;
  34019. }
  34020. },
  34021. /**
  34022. * Resets the Input Handler and disables it.
  34023. * @method Phaser.InputHandler#reset
  34024. */
  34025. reset: function () {
  34026. this.enabled = false;
  34027. for (var i = 0; i < 10; i++)
  34028. {
  34029. this._pointerData[i] = {
  34030. id: i,
  34031. x: 0,
  34032. y: 0,
  34033. isDown: false,
  34034. isUp: false,
  34035. isOver: false,
  34036. isOut: false,
  34037. timeOver: 0,
  34038. timeOut: 0,
  34039. timeDown: 0,
  34040. timeUp: 0,
  34041. downDuration: 0,
  34042. isDragged: false
  34043. };
  34044. }
  34045. },
  34046. /**
  34047. * Stops the Input Handler from running.
  34048. * @method Phaser.InputHandler#stop
  34049. */
  34050. stop: function () {
  34051. // Turning off
  34052. if (this.enabled === false)
  34053. {
  34054. return;
  34055. }
  34056. else
  34057. {
  34058. // De-register, etc
  34059. this.enabled = false;
  34060. this.game.input.interactiveItems.remove(this);
  34061. }
  34062. },
  34063. /**
  34064. * Clean up memory.
  34065. * @method Phaser.InputHandler#destroy
  34066. */
  34067. destroy: function () {
  34068. if (this.sprite)
  34069. {
  34070. if (this._setHandCursor)
  34071. {
  34072. this.game.canvas.style.cursor = "";
  34073. this._setHandCursor = false;
  34074. }
  34075. this.enabled = false;
  34076. this.game.input.interactiveItems.remove(this);
  34077. this._pointerData.length = 0;
  34078. this.boundsRect = null;
  34079. this.boundsSprite = null;
  34080. this.sprite = null;
  34081. }
  34082. },
  34083. /**
  34084. * Checks if the object this InputHandler is bound to is valid for consideration in the Pointer move event.
  34085. * This is called by Phaser.Pointer and shouldn't typically be called directly.
  34086. *
  34087. * @method Phaser.InputHandler#validForInput
  34088. * @protected
  34089. * @param {number} highestID - The highest ID currently processed by the Pointer.
  34090. * @param {number} highestRenderID - The highest Render Order ID currently processed by the Pointer.
  34091. * @param {boolean} [includePixelPerfect=true] - If this object has `pixelPerfectClick` or `pixelPerfectOver` set should it be considered as valid?
  34092. * @return {boolean} True if the object this InputHandler is bound to should be considered as valid for input detection.
  34093. */
  34094. validForInput: function (highestID, highestRenderID, includePixelPerfect) {
  34095. if (includePixelPerfect === undefined) { includePixelPerfect = true; }
  34096. if (!this.enabled ||
  34097. this.sprite.scale.x === 0 ||
  34098. this.sprite.scale.y === 0 ||
  34099. this.priorityID < this.game.input.minPriorityID ||
  34100. (this.sprite.parent && this.sprite.parent.ignoreChildInput))
  34101. {
  34102. return false;
  34103. }
  34104. // If we're trying to specifically IGNORE pixel perfect objects, then set includePixelPerfect to false and skip it
  34105. if (!includePixelPerfect && (this.pixelPerfectClick || this.pixelPerfectOver))
  34106. {
  34107. return false;
  34108. }
  34109. if (this.priorityID > highestID || (this.priorityID === highestID && this.sprite.renderOrderID > highestRenderID))
  34110. {
  34111. return true;
  34112. }
  34113. return false;
  34114. },
  34115. /**
  34116. * Is this object using pixel perfect checking?
  34117. *
  34118. * @method Phaser.InputHandler#isPixelPerfect
  34119. * @return {boolean} True if the this InputHandler has either `pixelPerfectClick` or `pixelPerfectOver` set to `true`.
  34120. */
  34121. isPixelPerfect: function () {
  34122. return (this.pixelPerfectClick || this.pixelPerfectOver);
  34123. },
  34124. /**
  34125. * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite.
  34126. * This value is only set when the pointer is over this Sprite.
  34127. *
  34128. * @method Phaser.InputHandler#pointerX
  34129. * @param {integer} [pointerId=0]
  34130. * @return {number} The x coordinate of the Input pointer.
  34131. */
  34132. pointerX: function (pointerId) {
  34133. pointerId = pointerId || 0;
  34134. return this._pointerData[pointerId].x;
  34135. },
  34136. /**
  34137. * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite
  34138. * This value is only set when the pointer is over this Sprite.
  34139. *
  34140. * @method Phaser.InputHandler#pointerY
  34141. * @param {integer} [pointerId=0]
  34142. * @return {number} The y coordinate of the Input pointer.
  34143. */
  34144. pointerY: function (pointerId) {
  34145. pointerId = pointerId || 0;
  34146. return this._pointerData[pointerId].y;
  34147. },
  34148. /**
  34149. * If the Pointer is down this returns true.
  34150. * This *only* checks if the Pointer is down, not if it's down over any specific Sprite.
  34151. *
  34152. * @method Phaser.InputHandler#pointerDown
  34153. * @param {integer} [pointerId=0]
  34154. * @return {boolean} - True if the given pointer is down, otherwise false.
  34155. */
  34156. pointerDown: function (pointerId) {
  34157. pointerId = pointerId || 0;
  34158. return this._pointerData[pointerId].isDown;
  34159. },
  34160. /**
  34161. * If the Pointer is up this returns true.
  34162. * This *only* checks if the Pointer is up, not if it's up over any specific Sprite.
  34163. *
  34164. * @method Phaser.InputHandler#pointerUp
  34165. * @param {integer} [pointerId=0]
  34166. * @return {boolean} - True if the given pointer is up, otherwise false.
  34167. */
  34168. pointerUp: function (pointerId) {
  34169. pointerId = pointerId || 0;
  34170. return this._pointerData[pointerId].isUp;
  34171. },
  34172. /**
  34173. * A timestamp representing when the Pointer first touched the touchscreen.
  34174. *
  34175. * @method Phaser.InputHandler#pointerTimeDown
  34176. * @param {integer} [pointerId=(check all)]
  34177. * @return {number}
  34178. */
  34179. pointerTimeDown: function (pointerId) {
  34180. pointerId = pointerId || 0;
  34181. return this._pointerData[pointerId].timeDown;
  34182. },
  34183. /**
  34184. * A timestamp representing when the Pointer left the touchscreen.
  34185. *
  34186. * @method Phaser.InputHandler#pointerTimeUp
  34187. * @param {integer} [pointerId=0]
  34188. * @return {number}
  34189. */
  34190. pointerTimeUp: function (pointerId) {
  34191. pointerId = pointerId || 0;
  34192. return this._pointerData[pointerId].timeUp;
  34193. },
  34194. /**
  34195. * Is the Pointer over this Sprite?
  34196. *
  34197. * @method Phaser.InputHandler#pointerOver
  34198. * @param {integer} [pointerId=(check all)] The ID number of a Pointer to check. If you don't provide a number it will check all Pointers.
  34199. * @return {boolean} - True if the given pointer (if a index was given, or any pointer if not) is over this object.
  34200. */
  34201. pointerOver: function (pointerId) {
  34202. if (!this.enabled)
  34203. {
  34204. return false;
  34205. }
  34206. if (pointerId === undefined)
  34207. {
  34208. for (var i = 0; i < 10; i++)
  34209. {
  34210. if (this._pointerData[i].isOver)
  34211. {
  34212. return true;
  34213. }
  34214. }
  34215. return false;
  34216. }
  34217. else
  34218. {
  34219. return this._pointerData[pointerId].isOver;
  34220. }
  34221. },
  34222. /**
  34223. * Is the Pointer outside of this Sprite?
  34224. *
  34225. * @method Phaser.InputHandler#pointerOut
  34226. * @param {integer} [pointerId=(check all)] The ID number of a Pointer to check. If you don't provide a number it will check all Pointers.
  34227. * @return {boolean} True if the given pointer (if a index was given, or any pointer if not) is out of this object.
  34228. */
  34229. pointerOut: function (pointerId) {
  34230. if (!this.enabled)
  34231. {
  34232. return false;
  34233. }
  34234. if (pointerId === undefined)
  34235. {
  34236. for (var i = 0; i < 10; i++)
  34237. {
  34238. if (this._pointerData[i].isOut)
  34239. {
  34240. return true;
  34241. }
  34242. }
  34243. }
  34244. else
  34245. {
  34246. return this._pointerData[pointerId].isOut;
  34247. }
  34248. },
  34249. /**
  34250. * A timestamp representing when the Pointer first touched the touchscreen.
  34251. *
  34252. * @method Phaser.InputHandler#pointerTimeOver
  34253. * @param {integer} [pointerId=0]
  34254. * @return {number}
  34255. */
  34256. pointerTimeOver: function (pointerId) {
  34257. pointerId = pointerId || 0;
  34258. return this._pointerData[pointerId].timeOver;
  34259. },
  34260. /**
  34261. * A timestamp representing when the Pointer left the touchscreen.
  34262. *
  34263. * @method Phaser.InputHandler#pointerTimeOut
  34264. * @param {integer} [pointerId=0]
  34265. * @return {number}
  34266. */
  34267. pointerTimeOut: function (pointerId) {
  34268. pointerId = pointerId || 0;
  34269. return this._pointerData[pointerId].timeOut;
  34270. },
  34271. /**
  34272. * Is this sprite being dragged by the mouse or not?
  34273. *
  34274. * @method Phaser.InputHandler#pointerDragged
  34275. * @param {integer} [pointerId=0]
  34276. * @return {boolean} True if the pointer is dragging an object, otherwise false.
  34277. */
  34278. pointerDragged: function (pointerId) {
  34279. pointerId = pointerId || 0;
  34280. return this._pointerData[pointerId].isDragged;
  34281. },
  34282. /**
  34283. * Checks if the given pointer is both down and over the Sprite this InputHandler belongs to.
  34284. * Use the `fastTest` flag is to quickly check just the bounding hit area even if `InputHandler.pixelPerfectOver` is `true`.
  34285. *
  34286. * @method Phaser.InputHandler#checkPointerDown
  34287. * @param {Phaser.Pointer} pointer
  34288. * @param {boolean} [fastTest=false] - Force a simple hit area check even if `pixelPerfectOver` is true for this object?
  34289. * @return {boolean} True if the pointer is down, otherwise false.
  34290. */
  34291. checkPointerDown: function (pointer, fastTest) {
  34292. if (!pointer.isDown ||
  34293. !this.enabled ||
  34294. !this.sprite ||
  34295. !this.sprite.parent ||
  34296. !this.sprite.visible ||
  34297. !this.sprite.parent.visible ||
  34298. this.sprite.worldScale.x === 0 ||
  34299. this.sprite.worldScale.y === 0)
  34300. {
  34301. return false;
  34302. }
  34303. // Need to pass it a temp point, in case we need it again for the pixel check
  34304. if (this.game.input.hitTest(this.sprite, pointer, this._tempPoint))
  34305. {
  34306. if (fastTest === undefined)
  34307. {
  34308. fastTest = false;
  34309. }
  34310. if (!fastTest && this.pixelPerfectClick)
  34311. {
  34312. return this.checkPixel(this._tempPoint.x, this._tempPoint.y);
  34313. }
  34314. else
  34315. {
  34316. return true;
  34317. }
  34318. }
  34319. return false;
  34320. },
  34321. /**
  34322. * Checks if the given pointer is over the Sprite this InputHandler belongs to.
  34323. * Use the `fastTest` flag is to quickly check just the bounding hit area even if `InputHandler.pixelPerfectOver` is `true`.
  34324. *
  34325. * @method Phaser.InputHandler#checkPointerOver
  34326. * @param {Phaser.Pointer} pointer
  34327. * @param {boolean} [fastTest=false] - Force a simple hit area check even if `pixelPerfectOver` is true for this object?
  34328. * @return {boolean}
  34329. */
  34330. checkPointerOver: function (pointer, fastTest) {
  34331. if (!this.enabled ||
  34332. !this.sprite ||
  34333. !this.sprite.parent ||
  34334. !this.sprite.visible ||
  34335. !this.sprite.parent.visible ||
  34336. this.sprite.worldScale.x === 0 ||
  34337. this.sprite.worldScale.y === 0)
  34338. {
  34339. return false;
  34340. }
  34341. // Need to pass it a temp point, in case we need it again for the pixel check
  34342. if (this.game.input.hitTest(this.sprite, pointer, this._tempPoint))
  34343. {
  34344. if (fastTest === undefined)
  34345. {
  34346. fastTest = false;
  34347. }
  34348. if (!fastTest && this.pixelPerfectOver)
  34349. {
  34350. return this.checkPixel(this._tempPoint.x, this._tempPoint.y);
  34351. }
  34352. else
  34353. {
  34354. return true;
  34355. }
  34356. }
  34357. return false;
  34358. },
  34359. /**
  34360. * Runs a pixel perfect check against the given x/y coordinates of the Sprite this InputHandler is bound to.
  34361. * It compares the alpha value of the pixel and if >= InputHandler.pixelPerfectAlpha it returns true.
  34362. *
  34363. * @method Phaser.InputHandler#checkPixel
  34364. * @param {number} x - The x coordinate to check.
  34365. * @param {number} y - The y coordinate to check.
  34366. * @param {Phaser.Pointer} [pointer] - The pointer to get the x/y coordinate from if not passed as the first two parameters.
  34367. * @return {boolean} true if there is the alpha of the pixel is >= InputHandler.pixelPerfectAlpha
  34368. */
  34369. checkPixel: function (x, y, pointer) {
  34370. // Grab a pixel from our image into the hitCanvas and then test it
  34371. if (this.sprite.texture.baseTexture.source)
  34372. {
  34373. if (x === null && y === null)
  34374. {
  34375. // Use the pointer parameter
  34376. this.game.input.getLocalPosition(this.sprite, pointer, this._tempPoint);
  34377. var x = this._tempPoint.x;
  34378. var y = this._tempPoint.y;
  34379. }
  34380. if (this.sprite.anchor.x !== 0)
  34381. {
  34382. x -= -this.sprite.texture.frame.width * this.sprite.anchor.x;
  34383. }
  34384. if (this.sprite.anchor.y !== 0)
  34385. {
  34386. y -= -this.sprite.texture.frame.height * this.sprite.anchor.y;
  34387. }
  34388. x += this.sprite.texture.frame.x;
  34389. y += this.sprite.texture.frame.y;
  34390. if (this.sprite.texture.trim)
  34391. {
  34392. x -= this.sprite.texture.trim.x;
  34393. y -= this.sprite.texture.trim.y;
  34394. // If the coordinates are outside the trim area we return false immediately, to save doing a draw call
  34395. if (x < this.sprite.texture.crop.x || x > this.sprite.texture.crop.right || y < this.sprite.texture.crop.y || y > this.sprite.texture.crop.bottom)
  34396. {
  34397. this._dx = x;
  34398. this._dy = y;
  34399. return false;
  34400. }
  34401. }
  34402. this._dx = x;
  34403. this._dy = y;
  34404. this.game.input.hitContext.clearRect(0, 0, 1, 1);
  34405. this.game.input.hitContext.drawImage(this.sprite.texture.baseTexture.source, x, y, 1, 1, 0, 0, 1, 1);
  34406. var rgb = this.game.input.hitContext.getImageData(0, 0, 1, 1);
  34407. if (rgb.data[3] >= this.pixelPerfectAlpha)
  34408. {
  34409. return true;
  34410. }
  34411. }
  34412. return false;
  34413. },
  34414. /**
  34415. * Internal Update method. This is called automatically and handles the Pointer
  34416. * and drag update loops.
  34417. *
  34418. * @method Phaser.InputHandler#update
  34419. * @protected
  34420. * @param {Phaser.Pointer} pointer
  34421. * @return {boolean} True if the pointer is still active, otherwise false.
  34422. */
  34423. update: function (pointer) {
  34424. if (this.sprite === null || this.sprite.parent === undefined)
  34425. {
  34426. // Abort. We've been destroyed.
  34427. return;
  34428. }
  34429. if (!this.enabled || !this.sprite.visible || !this.sprite.parent.visible)
  34430. {
  34431. this._pointerOutHandler(pointer);
  34432. return false;
  34433. }
  34434. if (this._pendingDrag)
  34435. {
  34436. if (!this._dragDistancePass)
  34437. {
  34438. this._dragDistancePass = (Phaser.Math.distance(pointer.x, pointer.y, this.downPoint.x, this.downPoint.y) >= this.dragDistanceThreshold);
  34439. }
  34440. if (this._dragDistancePass && this._dragTimePass)
  34441. {
  34442. this.startDrag(pointer);
  34443. }
  34444. return true;
  34445. }
  34446. else if (this.draggable && this._draggedPointerID === pointer.id)
  34447. {
  34448. return this.updateDrag(pointer, false);
  34449. }
  34450. else if (this._pointerData[pointer.id].isOver)
  34451. {
  34452. if (this.checkPointerOver(pointer))
  34453. {
  34454. this._pointerData[pointer.id].x = pointer.x - this.sprite.x;
  34455. this._pointerData[pointer.id].y = pointer.y - this.sprite.y;
  34456. return true;
  34457. }
  34458. else
  34459. {
  34460. this._pointerOutHandler(pointer);
  34461. return false;
  34462. }
  34463. }
  34464. },
  34465. /**
  34466. * Internal method handling the pointer over event.
  34467. *
  34468. * @method Phaser.InputHandler#_pointerOverHandler
  34469. * @private
  34470. * @param {Phaser.Pointer} pointer - The pointer that triggered the event
  34471. * @param {boolean} [silent=false] - If silent is `true` then this method will not dispatch any Signals from the parent Sprite.
  34472. */
  34473. _pointerOverHandler: function (pointer, silent) {
  34474. if (this.sprite === null)
  34475. {
  34476. // Abort. We've been destroyed.
  34477. return;
  34478. }
  34479. var data = this._pointerData[pointer.id];
  34480. if (data.isOver === false || pointer.dirty)
  34481. {
  34482. var sendEvent = (data.isOver === false);
  34483. data.isOver = true;
  34484. data.isOut = false;
  34485. data.timeOver = this.game.time.time;
  34486. data.x = pointer.x - this.sprite.x;
  34487. data.y = pointer.y - this.sprite.y;
  34488. if (this.useHandCursor && data.isDragged === false)
  34489. {
  34490. this.game.canvas.style.cursor = "pointer";
  34491. this._setHandCursor = true;
  34492. }
  34493. if (!silent && sendEvent && this.sprite && this.sprite.events)
  34494. {
  34495. this.sprite.events.onInputOver$dispatch(this.sprite, pointer);
  34496. }
  34497. if (this.sprite.parent && this.sprite.parent.onChildInputOver)
  34498. {
  34499. this.sprite.parent.onChildInputOver.dispatch(this.sprite, pointer);
  34500. }
  34501. }
  34502. },
  34503. /**
  34504. * Internal method handling the pointer out event.
  34505. *
  34506. * @method Phaser.InputHandler#_pointerOutHandler
  34507. * @private
  34508. * @param {Phaser.Pointer} pointer - The pointer that triggered the event.
  34509. * @param {boolean} [silent=false] - If silent is `true` then this method will not dispatch any Signals from the parent Sprite.
  34510. */
  34511. _pointerOutHandler: function (pointer, silent) {
  34512. if (this.sprite === null)
  34513. {
  34514. // Abort. We've been destroyed.
  34515. return;
  34516. }
  34517. var data = this._pointerData[pointer.id];
  34518. data.isOver = false;
  34519. data.isOut = true;
  34520. data.timeOut = this.game.time.time;
  34521. if (this.useHandCursor && data.isDragged === false)
  34522. {
  34523. this.game.canvas.style.cursor = "";
  34524. this._setHandCursor = false;
  34525. }
  34526. if (!silent && this.sprite && this.sprite.events)
  34527. {
  34528. this.sprite.events.onInputOut$dispatch(this.sprite, pointer);
  34529. if (this.sprite && this.sprite.parent && this.sprite.parent.onChildInputOut)
  34530. {
  34531. this.sprite.parent.onChildInputOut.dispatch(this.sprite, pointer);
  34532. }
  34533. }
  34534. },
  34535. /**
  34536. * Internal method handling the touched / clicked event.
  34537. *
  34538. * @method Phaser.InputHandler#_touchedHandler
  34539. * @private
  34540. * @param {Phaser.Pointer} pointer - The pointer that triggered the event.
  34541. */
  34542. _touchedHandler: function (pointer) {
  34543. if (this.sprite === null)
  34544. {
  34545. // Abort. We've been destroyed.
  34546. return;
  34547. }
  34548. var data = this._pointerData[pointer.id];
  34549. if (!data.isDown && data.isOver)
  34550. {
  34551. if (this.pixelPerfectClick && !this.checkPixel(null, null, pointer))
  34552. {
  34553. return;
  34554. }
  34555. data.isDown = true;
  34556. data.isUp = false;
  34557. data.timeDown = this.game.time.time;
  34558. this.downPoint.set(pointer.x, pointer.y);
  34559. // It's possible the onInputDown event creates a new Sprite that is on-top of this one, so we ought to force a Pointer update
  34560. pointer.dirty = true;
  34561. if (this.sprite && this.sprite.events)
  34562. {
  34563. this.sprite.events.onInputDown$dispatch(this.sprite, pointer);
  34564. // The event above might have destroyed this sprite.
  34565. if (this.sprite && this.sprite.parent && this.sprite.parent.onChildInputDown)
  34566. {
  34567. this.sprite.parent.onChildInputDown.dispatch(this.sprite, pointer);
  34568. }
  34569. // The events might have destroyed this sprite.
  34570. if (this.sprite === null)
  34571. {
  34572. return;
  34573. }
  34574. }
  34575. // Start drag
  34576. if (this.draggable && this.isDragged === false)
  34577. {
  34578. if (this.dragTimeThreshold === 0 && this.dragDistanceThreshold === 0)
  34579. {
  34580. this.startDrag(pointer);
  34581. }
  34582. else
  34583. {
  34584. this._pendingDrag = true;
  34585. this._dragDistancePass = (this.dragDistanceThreshold === 0);
  34586. if (this.dragTimeThreshold > 0)
  34587. {
  34588. this._dragTimePass = false;
  34589. this.game.time.events.add(this.dragTimeThreshold, this.dragTimeElapsed, this, pointer);
  34590. }
  34591. else
  34592. {
  34593. this._dragTimePass = true;
  34594. }
  34595. }
  34596. }
  34597. if (this.bringToTop)
  34598. {
  34599. this.sprite.bringToTop();
  34600. }
  34601. }
  34602. },
  34603. /**
  34604. * Internal method handling the drag threshold timer.
  34605. *
  34606. * @method Phaser.InputHandler#dragTimeElapsed
  34607. * @private
  34608. * @param {Phaser.Pointer} pointer
  34609. */
  34610. dragTimeElapsed: function (pointer) {
  34611. this._dragTimePass = true;
  34612. if (this._pendingDrag && this.sprite)
  34613. {
  34614. if (this._dragDistancePass)
  34615. {
  34616. this.startDrag(pointer);
  34617. }
  34618. }
  34619. },
  34620. /**
  34621. * Internal method handling the pointer released event.
  34622. * @method Phaser.InputHandler#_releasedHandler
  34623. * @private
  34624. * @param {Phaser.Pointer} pointer
  34625. */
  34626. _releasedHandler: function (pointer) {
  34627. if (this.sprite === null)
  34628. {
  34629. // Abort. We've been destroyed.
  34630. return;
  34631. }
  34632. var data = this._pointerData[pointer.id];
  34633. // If was previously touched by this Pointer, check if still is AND still over this item
  34634. if (data.isDown && pointer.isUp)
  34635. {
  34636. data.isDown = false;
  34637. data.isUp = true;
  34638. data.timeUp = this.game.time.time;
  34639. data.downDuration = data.timeUp - data.timeDown;
  34640. // Only release the InputUp signal if the pointer is still over this sprite
  34641. var isOver = this.checkPointerOver(pointer);
  34642. if (this.sprite && this.sprite.events)
  34643. {
  34644. if (!this.dragStopBlocksInputUp ||
  34645. this.dragStopBlocksInputUp && !(this.draggable && this.isDragged && this._draggedPointerID === pointer.id))
  34646. {
  34647. this.sprite.events.onInputUp$dispatch(this.sprite, pointer, isOver);
  34648. }
  34649. if (this.sprite && this.sprite.parent && this.sprite.parent.onChildInputUp)
  34650. {
  34651. this.sprite.parent.onChildInputUp.dispatch(this.sprite, pointer, isOver);
  34652. }
  34653. // The onInputUp event may have changed the sprite so that checkPointerOver is no longer true, so update it.
  34654. if (isOver)
  34655. {
  34656. isOver = this.checkPointerOver(pointer);
  34657. }
  34658. }
  34659. data.isOver = isOver;
  34660. if (!isOver && this.useHandCursor)
  34661. {
  34662. this.game.canvas.style.cursor = "default";
  34663. this._setHandCursor = false;
  34664. }
  34665. // It's possible the onInputUp event created a new Sprite that is on-top of this one, so force a Pointer update
  34666. pointer.dirty = true;
  34667. this._pendingDrag = false;
  34668. // Stop drag
  34669. if (this.draggable && this.isDragged && this._draggedPointerID === pointer.id)
  34670. {
  34671. this.stopDrag(pointer);
  34672. }
  34673. }
  34674. },
  34675. /**
  34676. * Called as a Pointer actively drags this Game Object.
  34677. *
  34678. * @method Phaser.InputHandler#updateDrag
  34679. * @private
  34680. * @param {Phaser.Pointer} pointer - The Pointer causing the drag update.
  34681. * @param {boolean} fromStart - True if this is the first update, immediately after the drag has started.
  34682. * @return {boolean}
  34683. */
  34684. updateDrag: function (pointer, fromStart) {
  34685. if (fromStart === undefined) { fromStart = false; }
  34686. if (pointer.isUp)
  34687. {
  34688. this.stopDrag(pointer);
  34689. return false;
  34690. }
  34691. var pointerLocalCoord = this.globalToLocal(pointer);
  34692. var px = pointerLocalCoord.x + this._dragPoint.x + this.dragOffset.x;
  34693. var py = pointerLocalCoord.y + this._dragPoint.y + this.dragOffset.y;
  34694. if (this.sprite.fixedToCamera)
  34695. {
  34696. if (this.allowHorizontalDrag)
  34697. {
  34698. this.sprite.cameraOffset.x = px - this.game.camera.x;
  34699. }
  34700. if (this.allowVerticalDrag)
  34701. {
  34702. this.sprite.cameraOffset.y = py - this.game.camera.y;
  34703. }
  34704. if (this.boundsRect)
  34705. {
  34706. this.checkBoundsRect();
  34707. }
  34708. if (this.boundsSprite)
  34709. {
  34710. this.checkBoundsSprite();
  34711. }
  34712. if (this.snapOnDrag)
  34713. {
  34714. this.sprite.cameraOffset.x = Math.round((this.sprite.cameraOffset.x - (this.snapOffsetX % this.snapX)) / this.snapX) * this.snapX + (this.snapOffsetX % this.snapX);
  34715. this.sprite.cameraOffset.y = Math.round((this.sprite.cameraOffset.y - (this.snapOffsetY % this.snapY)) / this.snapY) * this.snapY + (this.snapOffsetY % this.snapY);
  34716. this.snapPoint.set(this.sprite.cameraOffset.x, this.sprite.cameraOffset.y);
  34717. }
  34718. }
  34719. else
  34720. {
  34721. var cx = this.game.camera.x - this._pointerData[pointer.id].camX;
  34722. var cy = this.game.camera.y - this._pointerData[pointer.id].camY;
  34723. if (this.allowHorizontalDrag)
  34724. {
  34725. this.sprite.x = px + cx;
  34726. }
  34727. if (this.allowVerticalDrag)
  34728. {
  34729. this.sprite.y = py + cy;
  34730. }
  34731. if (this.boundsRect)
  34732. {
  34733. this.checkBoundsRect();
  34734. }
  34735. if (this.boundsSprite)
  34736. {
  34737. this.checkBoundsSprite();
  34738. }
  34739. if (this.snapOnDrag)
  34740. {
  34741. this.sprite.x = Math.round((this.sprite.x - (this.snapOffsetX % this.snapX)) / this.snapX) * this.snapX + (this.snapOffsetX % this.snapX);
  34742. this.sprite.y = Math.round((this.sprite.y - (this.snapOffsetY % this.snapY)) / this.snapY) * this.snapY + (this.snapOffsetY % this.snapY);
  34743. this.snapPoint.set(this.sprite.x, this.sprite.y);
  34744. }
  34745. }
  34746. this.sprite.events.onDragUpdate.dispatch(this.sprite, pointer, px, py, this.snapPoint, fromStart);
  34747. return true;
  34748. },
  34749. /**
  34750. * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second)
  34751. *
  34752. * @method Phaser.InputHandler#justOver
  34753. * @param {integer} [pointerId=0]
  34754. * @param {number} delay - The time below which the pointer is considered as just over.
  34755. * @return {boolean}
  34756. */
  34757. justOver: function (pointerId, delay) {
  34758. pointerId = pointerId || 0;
  34759. delay = delay || 500;
  34760. return (this._pointerData[pointerId].isOver && this.overDuration(pointerId) < delay);
  34761. },
  34762. /**
  34763. * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second)
  34764. *
  34765. * @method Phaser.InputHandler#justOut
  34766. * @param {integer} [pointerId=0]
  34767. * @param {number} delay - The time below which the pointer is considered as just out.
  34768. * @return {boolean}
  34769. */
  34770. justOut: function (pointerId, delay) {
  34771. pointerId = pointerId || 0;
  34772. delay = delay || 500;
  34773. return (this._pointerData[pointerId].isOut && (this.game.time.time - this._pointerData[pointerId].timeOut < delay));
  34774. },
  34775. /**
  34776. * Returns true if the pointer has touched or clicked on the Sprite within the specified delay time (defaults to 500ms, half a second)
  34777. *
  34778. * @method Phaser.InputHandler#justPressed
  34779. * @param {integer} [pointerId=0]
  34780. * @param {number} delay - The time below which the pointer is considered as just over.
  34781. * @return {boolean}
  34782. */
  34783. justPressed: function (pointerId, delay) {
  34784. pointerId = pointerId || 0;
  34785. delay = delay || 500;
  34786. return (this._pointerData[pointerId].isDown && this.downDuration(pointerId) < delay);
  34787. },
  34788. /**
  34789. * Returns true if the pointer was touching this Sprite, but has been released within the specified delay time (defaults to 500ms, half a second)
  34790. *
  34791. * @method Phaser.InputHandler#justReleased
  34792. * @param {integer} [pointerId=0]
  34793. * @param {number} delay - The time below which the pointer is considered as just out.
  34794. * @return {boolean}
  34795. */
  34796. justReleased: function (pointerId, delay) {
  34797. pointerId = pointerId || 0;
  34798. delay = delay || 500;
  34799. return (this._pointerData[pointerId].isUp && (this.game.time.time - this._pointerData[pointerId].timeUp < delay));
  34800. },
  34801. /**
  34802. * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds.
  34803. *
  34804. * @method Phaser.InputHandler#overDuration
  34805. * @param {integer} [pointerId=0]
  34806. * @return {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over.
  34807. */
  34808. overDuration: function (pointerId) {
  34809. pointerId = pointerId || 0;
  34810. if (this._pointerData[pointerId].isOver)
  34811. {
  34812. return this.game.time.time - this._pointerData[pointerId].timeOver;
  34813. }
  34814. return -1;
  34815. },
  34816. /**
  34817. * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds.
  34818. *
  34819. * @method Phaser.InputHandler#downDuration
  34820. * @param {integer} [pointerId=0]
  34821. * @return {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over.
  34822. */
  34823. downDuration: function (pointerId) {
  34824. pointerId = pointerId || 0;
  34825. if (this._pointerData[pointerId].isDown)
  34826. {
  34827. return this.game.time.time - this._pointerData[pointerId].timeDown;
  34828. }
  34829. return -1;
  34830. },
  34831. /**
  34832. * Allow this Sprite to be dragged by any valid pointer.
  34833. *
  34834. * When the drag begins the Sprite.events.onDragStart event will be dispatched.
  34835. *
  34836. * When the drag completes by way of the user letting go of the pointer that was dragging the sprite, the Sprite.events.onDragStop event is dispatched.
  34837. *
  34838. * You can control the thresholds over when a drag starts via the properties:
  34839. *
  34840. * `Pointer.dragDistanceThreshold` the distance, in pixels, that the pointer has to move
  34841. * before the drag will start.
  34842. *
  34843. * `Pointer.dragTimeThreshold` the time, in ms, that the pointer must be held down on
  34844. * the Sprite before the drag will start.
  34845. *
  34846. * You can set either (or both) of these properties after enabling a Sprite for drag.
  34847. *
  34848. * For the duration of the drag the Sprite.events.onDragUpdate event is dispatched. This event is only dispatched when the pointer actually
  34849. * changes position and moves. The event sends 5 parameters: `sprite`, `pointer`, `dragX`, `dragY` and `snapPoint`.
  34850. *
  34851. * @method Phaser.InputHandler#enableDrag
  34852. * @param {boolean} [lockCenter=false] - If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer.
  34853. * @param {boolean} [bringToTop=false] - If true the Sprite will be bought to the top of the rendering list in its current Group.
  34854. * @param {boolean} [pixelPerfect=false] - If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box.
  34855. * @param {integer} [alphaThreshold=255] - If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed.
  34856. * @param {Phaser.Rectangle} [boundsRect=null] - If you want to restrict the drag of this sprite to a specific Rectangle, pass the Phaser.Rectangle here, otherwise it's free to drag anywhere.
  34857. * @param {Phaser.Sprite} [boundsSprite=null] - If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here.
  34858. */
  34859. enableDrag: function (lockCenter, bringToTop, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) {
  34860. if (lockCenter === undefined) { lockCenter = false; }
  34861. if (bringToTop === undefined) { bringToTop = false; }
  34862. if (pixelPerfect === undefined) { pixelPerfect = false; }
  34863. if (alphaThreshold === undefined) { alphaThreshold = 255; }
  34864. if (boundsRect === undefined) { boundsRect = null; }
  34865. if (boundsSprite === undefined) { boundsSprite = null; }
  34866. this._dragPoint = new Phaser.Point();
  34867. this.draggable = true;
  34868. this.bringToTop = bringToTop;
  34869. this.dragOffset = new Phaser.Point();
  34870. this.dragFromCenter = lockCenter;
  34871. this.pixelPerfectClick = pixelPerfect;
  34872. this.pixelPerfectAlpha = alphaThreshold;
  34873. if (boundsRect)
  34874. {
  34875. this.boundsRect = boundsRect;
  34876. }
  34877. if (boundsSprite)
  34878. {
  34879. this.boundsSprite = boundsSprite;
  34880. }
  34881. },
  34882. /**
  34883. * Stops this sprite from being able to be dragged.
  34884. * If it is currently the target of an active drag it will be stopped immediately; also disables any set callbacks.
  34885. *
  34886. * @method Phaser.InputHandler#disableDrag
  34887. */
  34888. disableDrag: function () {
  34889. if (this._pointerData)
  34890. {
  34891. for (var i = 0; i < 10; i++)
  34892. {
  34893. this._pointerData[i].isDragged = false;
  34894. }
  34895. }
  34896. this.draggable = false;
  34897. this.isDragged = false;
  34898. this._draggedPointerID = -1;
  34899. this._pendingDrag = false;
  34900. },
  34901. /**
  34902. * Called by Pointer when drag starts on this Sprite. Should not usually be called directly.
  34903. *
  34904. * @method Phaser.InputHandler#startDrag
  34905. * @param {Phaser.Pointer} pointer
  34906. */
  34907. startDrag: function (pointer) {
  34908. var x = this.sprite.x;
  34909. var y = this.sprite.y;
  34910. var pointerLocalCoord = this.globalToLocal(pointer);
  34911. this.isDragged = true;
  34912. this._draggedPointerID = pointer.id;
  34913. this._pointerData[pointer.id].camX = this.game.camera.x;
  34914. this._pointerData[pointer.id].camY = this.game.camera.y;
  34915. this._pointerData[pointer.id].isDragged = true;
  34916. if (this.sprite.fixedToCamera)
  34917. {
  34918. if (this.dragFromCenter)
  34919. {
  34920. var bounds = this.sprite.getBounds();
  34921. var boundsCenterLocalCoord = this.globalToLocal(new Phaser.Point(bounds.centerX, bounds.centerY));
  34922. this.sprite.cameraOffset.x = pointerLocalCoord.x + (this.sprite.cameraOffset.x - boundsCenterLocalCoord.x);
  34923. this.sprite.cameraOffset.y = pointerLocalCoord.y + (this.sprite.cameraOffset.y - boundsCenterLocalCoord.y);
  34924. }
  34925. this._dragPoint.setTo(this.sprite.cameraOffset.x - pointer.x, this.sprite.cameraOffset.y - pointer.y);
  34926. }
  34927. else
  34928. {
  34929. if (this.dragFromCenter)
  34930. {
  34931. var bounds = this.sprite.getBounds();
  34932. var boundsCenterLocalCoord = this.globalToLocal(new Phaser.Point(bounds.centerX, bounds.centerY));
  34933. this.sprite.x = pointerLocalCoord.x + (this.sprite.x - boundsCenterLocalCoord.x);
  34934. this.sprite.y = pointerLocalCoord.y + (this.sprite.y - boundsCenterLocalCoord.y);
  34935. }
  34936. this._dragPoint.setTo(this.sprite.x - pointerLocalCoord.x, this.sprite.y - pointerLocalCoord.y);
  34937. }
  34938. this.updateDrag(pointer, true);
  34939. if (this.bringToTop)
  34940. {
  34941. this._dragPhase = true;
  34942. this.sprite.bringToTop();
  34943. }
  34944. this.dragStartPoint.set(x, y);
  34945. this.sprite.events.onDragStart$dispatch(this.sprite, pointer, x, y);
  34946. this._pendingDrag = false;
  34947. },
  34948. /**
  34949. * Warning: EXPERIMENTAL
  34950. *
  34951. * @method Phaser.InputHandler#globalToLocalX
  34952. * @param {number} x
  34953. */
  34954. globalToLocalX: function (x) {
  34955. if (this.scaleLayer)
  34956. {
  34957. x -= this.game.scale.grid.boundsFluid.x;
  34958. x *= this.game.scale.grid.scaleFluidInversed.x;
  34959. }
  34960. return x;
  34961. },
  34962. /**
  34963. * Warning: EXPERIMENTAL
  34964. *
  34965. * @method Phaser.InputHandler#globalToLocalY
  34966. * @param {number} y
  34967. */
  34968. globalToLocalY: function (y) {
  34969. if (this.scaleLayer)
  34970. {
  34971. y -= this.game.scale.grid.boundsFluid.y;
  34972. y *= this.game.scale.grid.scaleFluidInversed.y;
  34973. }
  34974. return y;
  34975. },
  34976. /**
  34977. * Convert global coordinates to local sprite coordinates
  34978. *
  34979. * @method Phaser.InputHandler#globalToLocal
  34980. * @param {Phaser.Point} globalCoord - The global coordinates to convert.
  34981. * @return {Phaser.Point} A point containing the local coordinates.
  34982. */
  34983. globalToLocal: function (globalCoord) {
  34984. if (this.sprite.parent)
  34985. {
  34986. return this.game.input.getLocalPosition(this.sprite.parent, {x: globalCoord.x, y: globalCoord.y});
  34987. }
  34988. else
  34989. {
  34990. return globalCoord;
  34991. }
  34992. },
  34993. /**
  34994. * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly.
  34995. *
  34996. * @method Phaser.InputHandler#stopDrag
  34997. * @param {Phaser.Pointer} pointer
  34998. */
  34999. stopDrag: function (pointer) {
  35000. this.isDragged = false;
  35001. this._draggedPointerID = -1;
  35002. this._pointerData[pointer.id].isDragged = false;
  35003. this._dragPhase = false;
  35004. this._pendingDrag = false;
  35005. if (this.snapOnRelease)
  35006. {
  35007. if (this.sprite.fixedToCamera)
  35008. {
  35009. this.sprite.cameraOffset.x = Math.round((this.sprite.cameraOffset.x - (this.snapOffsetX % this.snapX)) / this.snapX) * this.snapX + (this.snapOffsetX % this.snapX);
  35010. this.sprite.cameraOffset.y = Math.round((this.sprite.cameraOffset.y - (this.snapOffsetY % this.snapY)) / this.snapY) * this.snapY + (this.snapOffsetY % this.snapY);
  35011. }
  35012. else
  35013. {
  35014. this.sprite.x = Math.round((this.sprite.x - (this.snapOffsetX % this.snapX)) / this.snapX) * this.snapX + (this.snapOffsetX % this.snapX);
  35015. this.sprite.y = Math.round((this.sprite.y - (this.snapOffsetY % this.snapY)) / this.snapY) * this.snapY + (this.snapOffsetY % this.snapY);
  35016. }
  35017. }
  35018. this.sprite.events.onDragStop$dispatch(this.sprite, pointer);
  35019. if (this.checkPointerOver(pointer) === false)
  35020. {
  35021. this._pointerOutHandler(pointer);
  35022. }
  35023. },
  35024. /**
  35025. * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move!
  35026. *
  35027. * @method Phaser.InputHandler#setDragLock
  35028. * @param {boolean} [allowHorizontal=true] - To enable the sprite to be dragged horizontally set to true, otherwise false.
  35029. * @param {boolean} [allowVertical=true] - To enable the sprite to be dragged vertically set to true, otherwise false.
  35030. */
  35031. setDragLock: function (allowHorizontal, allowVertical) {
  35032. if (allowHorizontal === undefined) { allowHorizontal = true; }
  35033. if (allowVertical === undefined) { allowVertical = true; }
  35034. this.allowHorizontalDrag = allowHorizontal;
  35035. this.allowVerticalDrag = allowVertical;
  35036. },
  35037. /**
  35038. * Make this Sprite snap to the given grid either during drag or when it's released.
  35039. * For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels.
  35040. *
  35041. * @method Phaser.InputHandler#enableSnap
  35042. * @param {number} snapX - The width of the grid cell to snap to.
  35043. * @param {number} snapY - The height of the grid cell to snap to.
  35044. * @param {boolean} [onDrag=true] - If true the sprite will snap to the grid while being dragged.
  35045. * @param {boolean} [onRelease=false] - If true the sprite will snap to the grid when released.
  35046. * @param {number} [snapOffsetX=0] - Used to offset the top-left starting point of the snap grid.
  35047. * @param {number} [snapOffsetY=0] - Used to offset the top-left starting point of the snap grid.
  35048. */
  35049. enableSnap: function (snapX, snapY, onDrag, onRelease, snapOffsetX, snapOffsetY) {
  35050. if (onDrag === undefined) { onDrag = true; }
  35051. if (onRelease === undefined) { onRelease = false; }
  35052. if (snapOffsetX === undefined) { snapOffsetX = 0; }
  35053. if (snapOffsetY === undefined) { snapOffsetY = 0; }
  35054. this.snapX = snapX;
  35055. this.snapY = snapY;
  35056. this.snapOffsetX = snapOffsetX;
  35057. this.snapOffsetY = snapOffsetY;
  35058. this.snapOnDrag = onDrag;
  35059. this.snapOnRelease = onRelease;
  35060. },
  35061. /**
  35062. * Stops the sprite from snapping to a grid during drag or release.
  35063. *
  35064. * @method Phaser.InputHandler#disableSnap
  35065. */
  35066. disableSnap: function () {
  35067. this.snapOnDrag = false;
  35068. this.snapOnRelease = false;
  35069. },
  35070. /**
  35071. * Bounds Rect check for the sprite drag
  35072. *
  35073. * @method Phaser.InputHandler#checkBoundsRect
  35074. */
  35075. checkBoundsRect: function () {
  35076. if (this.sprite.fixedToCamera)
  35077. {
  35078. if (this.sprite.cameraOffset.x < this.boundsRect.left)
  35079. {
  35080. this.sprite.cameraOffset.x = this.boundsRect.left;
  35081. }
  35082. else if ((this.sprite.cameraOffset.x + this.sprite.width) > this.boundsRect.right)
  35083. {
  35084. this.sprite.cameraOffset.x = this.boundsRect.right - this.sprite.width;
  35085. }
  35086. if (this.sprite.cameraOffset.y < this.boundsRect.top)
  35087. {
  35088. this.sprite.cameraOffset.y = this.boundsRect.top;
  35089. }
  35090. else if ((this.sprite.cameraOffset.y + this.sprite.height) > this.boundsRect.bottom)
  35091. {
  35092. this.sprite.cameraOffset.y = this.boundsRect.bottom - this.sprite.height;
  35093. }
  35094. }
  35095. else
  35096. {
  35097. if (this.sprite.left < this.boundsRect.left)
  35098. {
  35099. this.sprite.x = this.boundsRect.x + this.sprite.offsetX;
  35100. }
  35101. else if (this.sprite.right > this.boundsRect.right)
  35102. {
  35103. this.sprite.x = this.boundsRect.right - (this.sprite.width - this.sprite.offsetX);
  35104. }
  35105. if (this.sprite.top < this.boundsRect.top)
  35106. {
  35107. this.sprite.y = this.boundsRect.top + this.sprite.offsetY;
  35108. }
  35109. else if (this.sprite.bottom > this.boundsRect.bottom)
  35110. {
  35111. this.sprite.y = this.boundsRect.bottom - (this.sprite.height - this.sprite.offsetY);
  35112. }
  35113. }
  35114. },
  35115. /**
  35116. * Parent Sprite Bounds check for the sprite drag.
  35117. *
  35118. * @method Phaser.InputHandler#checkBoundsSprite
  35119. */
  35120. checkBoundsSprite: function () {
  35121. if (this.sprite.fixedToCamera && this.boundsSprite.fixedToCamera)
  35122. {
  35123. if (this.sprite.cameraOffset.x < this.boundsSprite.cameraOffset.x)
  35124. {
  35125. this.sprite.cameraOffset.x = this.boundsSprite.cameraOffset.x;
  35126. }
  35127. else if ((this.sprite.cameraOffset.x + this.sprite.width) > (this.boundsSprite.cameraOffset.x + this.boundsSprite.width))
  35128. {
  35129. this.sprite.cameraOffset.x = (this.boundsSprite.cameraOffset.x + this.boundsSprite.width) - this.sprite.width;
  35130. }
  35131. if (this.sprite.cameraOffset.y < this.boundsSprite.cameraOffset.y)
  35132. {
  35133. this.sprite.cameraOffset.y = this.boundsSprite.cameraOffset.y;
  35134. }
  35135. else if ((this.sprite.cameraOffset.y + this.sprite.height) > (this.boundsSprite.cameraOffset.y + this.boundsSprite.height))
  35136. {
  35137. this.sprite.cameraOffset.y = (this.boundsSprite.cameraOffset.y + this.boundsSprite.height) - this.sprite.height;
  35138. }
  35139. }
  35140. else
  35141. {
  35142. if (this.sprite.left < this.boundsSprite.left)
  35143. {
  35144. this.sprite.x = this.boundsSprite.left + this.sprite.offsetX;
  35145. }
  35146. else if (this.sprite.right > this.boundsSprite.right)
  35147. {
  35148. this.sprite.x = this.boundsSprite.right - (this.sprite.width - this.sprite.offsetX);
  35149. }
  35150. if (this.sprite.top < this.boundsSprite.top)
  35151. {
  35152. this.sprite.y = this.boundsSprite.top + this.sprite.offsetY;
  35153. }
  35154. else if (this.sprite.bottom > this.boundsSprite.bottom)
  35155. {
  35156. this.sprite.y = this.boundsSprite.bottom - (this.sprite.height - this.sprite.offsetY);
  35157. }
  35158. }
  35159. }
  35160. };
  35161. Phaser.InputHandler.prototype.constructor = Phaser.InputHandler;
  35162. /**
  35163. * @author @karlmacklin <tacklemcclean@gmail.com>
  35164. * @copyright 2016 Photon Storm Ltd.
  35165. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  35166. */
  35167. /**
  35168. * The Gamepad class handles gamepad input and dispatches gamepad events.
  35169. *
  35170. * Remember to call `gamepad.start()`.
  35171. *
  35172. * HTML5 GAMEPAD API SUPPORT IS AT AN EXPERIMENTAL STAGE!
  35173. * At moment of writing this (end of 2013) only Chrome supports parts of it out of the box. Firefox supports it
  35174. * via prefs flags (about:config, search gamepad). The browsers map the same controllers differently.
  35175. * This class has constants for Windows 7 Chrome mapping of XBOX 360 controller.
  35176. *
  35177. * @class Phaser.Gamepad
  35178. * @constructor
  35179. * @param {Phaser.Game} game - A reference to the currently running game.
  35180. */
  35181. Phaser.Gamepad = function (game) {
  35182. /**
  35183. * @property {Phaser.Game} game - Local reference to game.
  35184. */
  35185. this.game = game;
  35186. /**
  35187. * @property {object} _gamepadIndexMap - Maps the browsers gamepad indices to our Phaser Gamepads
  35188. * @private
  35189. */
  35190. this._gamepadIndexMap = {};
  35191. /**
  35192. * @property {Array} _rawPads - The raw state of the gamepads from the browser
  35193. * @private
  35194. */
  35195. this._rawPads = [];
  35196. /**
  35197. * @property {boolean} _active - Private flag for whether or not the API is polled
  35198. * @private
  35199. * @default
  35200. */
  35201. this._active = false;
  35202. /**
  35203. * Gamepad input will only be processed if enabled.
  35204. * @property {boolean} enabled
  35205. * @default
  35206. */
  35207. this.enabled = true;
  35208. /**
  35209. * Whether or not gamepads are supported in the current browser. Note that as of Dec. 2013 this check is actually not accurate at all due to poor implementation.
  35210. * @property {boolean} _gamepadSupportAvailable - Are gamepads supported in this browser or not?
  35211. * @private
  35212. */
  35213. this._gamepadSupportAvailable = !!navigator.webkitGetGamepads || !!navigator.webkitGamepads || (navigator.userAgent.indexOf('Firefox/') !== -1) || !!navigator.getGamepads;
  35214. /**
  35215. * Used to check for differences between earlier polls and current state of gamepads.
  35216. * @property {Array} _prevRawGamepadTypes
  35217. * @private
  35218. * @default
  35219. */
  35220. this._prevRawGamepadTypes = [];
  35221. /**
  35222. * Used to check for differences between earlier polls and current state of gamepads.
  35223. * @property {Array} _prevTimestamps
  35224. * @private
  35225. * @default
  35226. */
  35227. this._prevTimestamps = [];
  35228. /**
  35229. * @property {object} callbackContext - The context under which the callbacks are run.
  35230. */
  35231. this.callbackContext = this;
  35232. /**
  35233. * @property {function} onConnectCallback - This callback is invoked every time any gamepad is connected
  35234. */
  35235. this.onConnectCallback = null;
  35236. /**
  35237. * @property {function} onDisconnectCallback - This callback is invoked every time any gamepad is disconnected
  35238. */
  35239. this.onDisconnectCallback = null;
  35240. /**
  35241. * @property {function} onDownCallback - This callback is invoked every time any gamepad button is pressed down.
  35242. */
  35243. this.onDownCallback = null;
  35244. /**
  35245. * @property {function} onUpCallback - This callback is invoked every time any gamepad button is released.
  35246. */
  35247. this.onUpCallback = null;
  35248. /**
  35249. * @property {function} onAxisCallback - This callback is invoked every time any gamepad axis is changed.
  35250. */
  35251. this.onAxisCallback = null;
  35252. /**
  35253. * @property {function} onFloatCallback - This callback is invoked every time any gamepad button is changed to a value where value > 0 and value < 1.
  35254. */
  35255. this.onFloatCallback = null;
  35256. /**
  35257. * @property {function} _ongamepadconnected - Private callback for Firefox gamepad connection handling
  35258. * @private
  35259. */
  35260. this._ongamepadconnected = null;
  35261. /**
  35262. * @property {function} _gamepaddisconnected - Private callback for Firefox gamepad connection handling
  35263. * @private
  35264. */
  35265. this._gamepaddisconnected = null;
  35266. /**
  35267. * @property {Array<Phaser.SinglePad>} _gamepads - The four Phaser Gamepads.
  35268. * @private
  35269. */
  35270. this._gamepads = [
  35271. new Phaser.SinglePad(game, this),
  35272. new Phaser.SinglePad(game, this),
  35273. new Phaser.SinglePad(game, this),
  35274. new Phaser.SinglePad(game, this)
  35275. ];
  35276. };
  35277. Phaser.Gamepad.prototype = {
  35278. /**
  35279. * Add callbacks to the main Gamepad handler to handle connect/disconnect/button down/button up/axis change/float value buttons.
  35280. *
  35281. * @method Phaser.Gamepad#addCallbacks
  35282. * @param {object} context - The context under which the callbacks are run.
  35283. * @param {object} callbacks - Object that takes six different callback methods:
  35284. * onConnectCallback, onDisconnectCallback, onDownCallback, onUpCallback, onAxisCallback, onFloatCallback
  35285. */
  35286. addCallbacks: function (context, callbacks) {
  35287. if (typeof callbacks !== 'undefined')
  35288. {
  35289. this.onConnectCallback = (typeof callbacks.onConnect === 'function') ? callbacks.onConnect : this.onConnectCallback;
  35290. this.onDisconnectCallback = (typeof callbacks.onDisconnect === 'function') ? callbacks.onDisconnect : this.onDisconnectCallback;
  35291. this.onDownCallback = (typeof callbacks.onDown === 'function') ? callbacks.onDown : this.onDownCallback;
  35292. this.onUpCallback = (typeof callbacks.onUp === 'function') ? callbacks.onUp : this.onUpCallback;
  35293. this.onAxisCallback = (typeof callbacks.onAxis === 'function') ? callbacks.onAxis : this.onAxisCallback;
  35294. this.onFloatCallback = (typeof callbacks.onFloat === 'function') ? callbacks.onFloat : this.onFloatCallback;
  35295. this.callbackContext = context;
  35296. }
  35297. },
  35298. /**
  35299. * Starts the Gamepad event handling.
  35300. * This MUST be called manually before Phaser will start polling the Gamepad API.
  35301. *
  35302. * @method Phaser.Gamepad#start
  35303. */
  35304. start: function () {
  35305. if (this._active)
  35306. {
  35307. // Avoid setting multiple listeners
  35308. return;
  35309. }
  35310. this._active = true;
  35311. var _this = this;
  35312. this._onGamepadConnected = function (event) {
  35313. return _this.onGamepadConnected(event);
  35314. };
  35315. this._onGamepadDisconnected = function (event) {
  35316. return _this.onGamepadDisconnected(event);
  35317. };
  35318. window.addEventListener('gamepadconnected', this._onGamepadConnected, false);
  35319. window.addEventListener('gamepaddisconnected', this._onGamepadDisconnected, false);
  35320. },
  35321. /**
  35322. * Handles the connection of a Gamepad.
  35323. *
  35324. * @method onGamepadConnected
  35325. * @private
  35326. * @param {object} event - The DOM event.
  35327. */
  35328. onGamepadConnected: function (event) {
  35329. var newPad = event.gamepad;
  35330. this._rawPads.push(newPad);
  35331. this._gamepads[newPad.index].connect(newPad);
  35332. },
  35333. /**
  35334. * Handles the disconnection of a Gamepad.
  35335. *
  35336. * @method onGamepadDisconnected
  35337. * @private
  35338. * @param {object} event - The DOM event.
  35339. */
  35340. onGamepadDisconnected: function (event) {
  35341. var removedPad = event.gamepad;
  35342. for (var i in this._rawPads)
  35343. {
  35344. if (this._rawPads[i].index === removedPad.index)
  35345. {
  35346. this._rawPads.splice(i,1);
  35347. }
  35348. }
  35349. this._gamepads[removedPad.index].disconnect();
  35350. },
  35351. /**
  35352. * Main gamepad update loop. Should not be called manually.
  35353. * @method Phaser.Gamepad#update
  35354. * @protected
  35355. */
  35356. update: function () {
  35357. this._pollGamepads();
  35358. this.pad1.pollStatus();
  35359. this.pad2.pollStatus();
  35360. this.pad3.pollStatus();
  35361. this.pad4.pollStatus();
  35362. },
  35363. /**
  35364. * Updating connected gamepads (for Google Chrome). Should not be called manually.
  35365. *
  35366. * @method Phaser.Gamepad#_pollGamepads
  35367. * @private
  35368. */
  35369. _pollGamepads: function () {
  35370. if (!this._active)
  35371. {
  35372. return;
  35373. }
  35374. if (navigator['getGamepads'])
  35375. {
  35376. var rawGamepads = navigator.getGamepads();
  35377. }
  35378. else if (navigator['webkitGetGamepads'])
  35379. {
  35380. var rawGamepads = navigator.webkitGetGamepads();
  35381. }
  35382. else if (navigator['webkitGamepads'])
  35383. {
  35384. var rawGamepads = navigator.webkitGamepads();
  35385. }
  35386. if (rawGamepads)
  35387. {
  35388. this._rawPads = [];
  35389. var gamepadsChanged = false;
  35390. for (var i = 0; i < rawGamepads.length; i++)
  35391. {
  35392. if (typeof rawGamepads[i] !== this._prevRawGamepadTypes[i])
  35393. {
  35394. gamepadsChanged = true;
  35395. this._prevRawGamepadTypes[i] = typeof rawGamepads[i];
  35396. }
  35397. if (rawGamepads[i])
  35398. {
  35399. this._rawPads.push(rawGamepads[i]);
  35400. }
  35401. // Support max 4 pads at the moment
  35402. if (i === 3)
  35403. {
  35404. break;
  35405. }
  35406. }
  35407. for (var g = 0; g < this._gamepads.length; g++)
  35408. {
  35409. this._gamepads[g]._rawPad = this._rawPads[g];
  35410. }
  35411. if (gamepadsChanged)
  35412. {
  35413. var validConnections = { rawIndices: {}, padIndices: {} };
  35414. var singlePad;
  35415. for (var j = 0; j < this._gamepads.length; j++)
  35416. {
  35417. singlePad = this._gamepads[j];
  35418. if (singlePad.connected)
  35419. {
  35420. for (var k = 0; k < this._rawPads.length; k++)
  35421. {
  35422. if (this._rawPads[k].index === singlePad.index)
  35423. {
  35424. validConnections.rawIndices[singlePad.index] = true;
  35425. validConnections.padIndices[j] = true;
  35426. }
  35427. }
  35428. }
  35429. }
  35430. for (var l = 0; l < this._gamepads.length; l++)
  35431. {
  35432. singlePad = this._gamepads[l];
  35433. if (validConnections.padIndices[l])
  35434. {
  35435. continue;
  35436. }
  35437. if (this._rawPads.length < 1)
  35438. {
  35439. singlePad.disconnect();
  35440. }
  35441. for (var m = 0; m < this._rawPads.length; m++)
  35442. {
  35443. if (validConnections.padIndices[l])
  35444. {
  35445. break;
  35446. }
  35447. var rawPad = this._rawPads[m];
  35448. if (rawPad)
  35449. {
  35450. if (validConnections.rawIndices[rawPad.index])
  35451. {
  35452. singlePad.disconnect();
  35453. continue;
  35454. }
  35455. else
  35456. {
  35457. singlePad.connect(rawPad);
  35458. validConnections.rawIndices[rawPad.index] = true;
  35459. validConnections.padIndices[l] = true;
  35460. }
  35461. }
  35462. else
  35463. {
  35464. singlePad.disconnect();
  35465. }
  35466. }
  35467. }
  35468. }
  35469. }
  35470. },
  35471. /**
  35472. * Sets the deadZone variable for all four gamepads
  35473. * @method Phaser.Gamepad#setDeadZones
  35474. */
  35475. setDeadZones: function (value) {
  35476. for (var i = 0; i < this._gamepads.length; i++)
  35477. {
  35478. this._gamepads[i].deadZone = value;
  35479. }
  35480. },
  35481. /**
  35482. * Stops the Gamepad event handling.
  35483. *
  35484. * @method Phaser.Gamepad#stop
  35485. */
  35486. stop: function () {
  35487. this._active = false;
  35488. window.removeEventListener('gamepadconnected', this._onGamepadConnected);
  35489. window.removeEventListener('gamepaddisconnected', this._onGamepadDisconnected);
  35490. },
  35491. /**
  35492. * Reset all buttons/axes of all gamepads
  35493. * @method Phaser.Gamepad#reset
  35494. */
  35495. reset: function () {
  35496. this.update();
  35497. for (var i = 0; i < this._gamepads.length; i++)
  35498. {
  35499. this._gamepads[i].reset();
  35500. }
  35501. },
  35502. /**
  35503. * Returns the "just pressed" state of a button from ANY gamepad connected. Just pressed is considered true if the button was pressed down within the duration given (default 250ms).
  35504. * @method Phaser.Gamepad#justPressed
  35505. * @param {number} buttonCode - The buttonCode of the button to check for.
  35506. * @param {number} [duration=250] - The duration below which the button is considered as being just pressed.
  35507. * @return {boolean} True if the button is just pressed otherwise false.
  35508. */
  35509. justPressed: function (buttonCode, duration) {
  35510. for (var i = 0; i < this._gamepads.length; i++)
  35511. {
  35512. if (this._gamepads[i].justPressed(buttonCode, duration) === true)
  35513. {
  35514. return true;
  35515. }
  35516. }
  35517. return false;
  35518. },
  35519. /**
  35520. * Returns the "just released" state of a button from ANY gamepad connected. Just released is considered as being true if the button was released within the duration given (default 250ms).
  35521. * @method Phaser.Gamepad#justPressed
  35522. * @param {number} buttonCode - The buttonCode of the button to check for.
  35523. * @param {number} [duration=250] - The duration below which the button is considered as being just released.
  35524. * @return {boolean} True if the button is just released otherwise false.
  35525. */
  35526. justReleased: function (buttonCode, duration) {
  35527. for (var i = 0; i < this._gamepads.length; i++)
  35528. {
  35529. if (this._gamepads[i].justReleased(buttonCode, duration) === true)
  35530. {
  35531. return true;
  35532. }
  35533. }
  35534. return false;
  35535. },
  35536. /**
  35537. * Returns true if the button is currently pressed down, on ANY gamepad.
  35538. * @method Phaser.Gamepad#isDown
  35539. * @param {number} buttonCode - The buttonCode of the button to check for.
  35540. * @return {boolean} True if a button is currently down.
  35541. */
  35542. isDown: function (buttonCode) {
  35543. for (var i = 0; i < this._gamepads.length; i++)
  35544. {
  35545. if (this._gamepads[i].isDown(buttonCode) === true)
  35546. {
  35547. return true;
  35548. }
  35549. }
  35550. return false;
  35551. },
  35552. /**
  35553. * Destroys this object and the associated event listeners.
  35554. *
  35555. * @method Phaser.Gamepad#destroy
  35556. */
  35557. destroy: function () {
  35558. this.stop();
  35559. for (var i = 0; i < this._gamepads.length; i++)
  35560. {
  35561. this._gamepads[i].destroy();
  35562. }
  35563. }
  35564. };
  35565. Phaser.Gamepad.prototype.constructor = Phaser.Gamepad;
  35566. /**
  35567. * If the gamepad input is active or not - if not active it should not be updated from Input.js
  35568. * @name Phaser.Gamepad#active
  35569. * @property {boolean} active - If the gamepad input is active or not.
  35570. * @readonly
  35571. */
  35572. Object.defineProperty(Phaser.Gamepad.prototype, "active", {
  35573. get: function () {
  35574. return this._active;
  35575. }
  35576. });
  35577. /**
  35578. * Whether or not gamepads are supported in current browser.
  35579. * @name Phaser.Gamepad#supported
  35580. * @property {boolean} supported - Whether or not gamepads are supported in current browser.
  35581. * @readonly
  35582. */
  35583. Object.defineProperty(Phaser.Gamepad.prototype, "supported", {
  35584. get: function () {
  35585. return this._gamepadSupportAvailable;
  35586. }
  35587. });
  35588. /**
  35589. * How many live gamepads are currently connected.
  35590. * @name Phaser.Gamepad#padsConnected
  35591. * @property {number} padsConnected - How many live gamepads are currently connected.
  35592. * @readonly
  35593. */
  35594. Object.defineProperty(Phaser.Gamepad.prototype, "padsConnected", {
  35595. get: function () {
  35596. return this._rawPads.length;
  35597. }
  35598. });
  35599. /**
  35600. * Gamepad #1
  35601. * @name Phaser.Gamepad#pad1
  35602. * @property {Phaser.SinglePad} pad1 - Gamepad #1;
  35603. * @readonly
  35604. */
  35605. Object.defineProperty(Phaser.Gamepad.prototype, "pad1", {
  35606. get: function () {
  35607. return this._gamepads[0];
  35608. }
  35609. });
  35610. /**
  35611. * Gamepad #2
  35612. * @name Phaser.Gamepad#pad2
  35613. * @property {Phaser.SinglePad} pad2 - Gamepad #2
  35614. * @readonly
  35615. */
  35616. Object.defineProperty(Phaser.Gamepad.prototype, "pad2", {
  35617. get: function () {
  35618. return this._gamepads[1];
  35619. }
  35620. });
  35621. /**
  35622. * Gamepad #3
  35623. * @name Phaser.Gamepad#pad3
  35624. * @property {Phaser.SinglePad} pad3 - Gamepad #3
  35625. * @readonly
  35626. */
  35627. Object.defineProperty(Phaser.Gamepad.prototype, "pad3", {
  35628. get: function () {
  35629. return this._gamepads[2];
  35630. }
  35631. });
  35632. /**
  35633. * Gamepad #4
  35634. * @name Phaser.Gamepad#pad4
  35635. * @property {Phaser.SinglePad} pad4 - Gamepad #4
  35636. * @readonly
  35637. */
  35638. Object.defineProperty(Phaser.Gamepad.prototype, "pad4", {
  35639. get: function () {
  35640. return this._gamepads[3];
  35641. }
  35642. });
  35643. Phaser.Gamepad.BUTTON_0 = 0;
  35644. Phaser.Gamepad.BUTTON_1 = 1;
  35645. Phaser.Gamepad.BUTTON_2 = 2;
  35646. Phaser.Gamepad.BUTTON_3 = 3;
  35647. Phaser.Gamepad.BUTTON_4 = 4;
  35648. Phaser.Gamepad.BUTTON_5 = 5;
  35649. Phaser.Gamepad.BUTTON_6 = 6;
  35650. Phaser.Gamepad.BUTTON_7 = 7;
  35651. Phaser.Gamepad.BUTTON_8 = 8;
  35652. Phaser.Gamepad.BUTTON_9 = 9;
  35653. Phaser.Gamepad.BUTTON_10 = 10;
  35654. Phaser.Gamepad.BUTTON_11 = 11;
  35655. Phaser.Gamepad.BUTTON_12 = 12;
  35656. Phaser.Gamepad.BUTTON_13 = 13;
  35657. Phaser.Gamepad.BUTTON_14 = 14;
  35658. Phaser.Gamepad.BUTTON_15 = 15;
  35659. Phaser.Gamepad.AXIS_0 = 0;
  35660. Phaser.Gamepad.AXIS_1 = 1;
  35661. Phaser.Gamepad.AXIS_2 = 2;
  35662. Phaser.Gamepad.AXIS_3 = 3;
  35663. Phaser.Gamepad.AXIS_4 = 4;
  35664. Phaser.Gamepad.AXIS_5 = 5;
  35665. Phaser.Gamepad.AXIS_6 = 6;
  35666. Phaser.Gamepad.AXIS_7 = 7;
  35667. Phaser.Gamepad.AXIS_8 = 8;
  35668. Phaser.Gamepad.AXIS_9 = 9;
  35669. // Below mapping applies to XBOX 360 Wired and Wireless controller on Google Chrome (tested on Windows 7).
  35670. // - Firefox uses different map! Separate amount of buttons and axes. DPAD = axis and not a button.
  35671. // In other words - discrepancies when using gamepads.
  35672. Phaser.Gamepad.XBOX360_A = 0;
  35673. Phaser.Gamepad.XBOX360_B = 1;
  35674. Phaser.Gamepad.XBOX360_X = 2;
  35675. Phaser.Gamepad.XBOX360_Y = 3;
  35676. Phaser.Gamepad.XBOX360_LEFT_BUMPER = 4;
  35677. Phaser.Gamepad.XBOX360_RIGHT_BUMPER = 5;
  35678. Phaser.Gamepad.XBOX360_LEFT_TRIGGER = 6;
  35679. Phaser.Gamepad.XBOX360_RIGHT_TRIGGER = 7;
  35680. Phaser.Gamepad.XBOX360_BACK = 8;
  35681. Phaser.Gamepad.XBOX360_START = 9;
  35682. Phaser.Gamepad.XBOX360_STICK_LEFT_BUTTON = 10;
  35683. Phaser.Gamepad.XBOX360_STICK_RIGHT_BUTTON = 11;
  35684. Phaser.Gamepad.XBOX360_DPAD_LEFT = 14;
  35685. Phaser.Gamepad.XBOX360_DPAD_RIGHT = 15;
  35686. Phaser.Gamepad.XBOX360_DPAD_UP = 12;
  35687. Phaser.Gamepad.XBOX360_DPAD_DOWN = 13;
  35688. // On FF 0 = Y, 1 = X, 2 = Y, 3 = X, 4 = left bumper, 5 = dpad left, 6 = dpad right
  35689. Phaser.Gamepad.XBOX360_STICK_LEFT_X = 0;
  35690. Phaser.Gamepad.XBOX360_STICK_LEFT_Y = 1;
  35691. Phaser.Gamepad.XBOX360_STICK_RIGHT_X = 2;
  35692. Phaser.Gamepad.XBOX360_STICK_RIGHT_Y = 3;
  35693. // PlayStation 3 controller (masquerading as xbox360 controller) button mappings
  35694. Phaser.Gamepad.PS3XC_X = 0;
  35695. Phaser.Gamepad.PS3XC_CIRCLE = 1;
  35696. Phaser.Gamepad.PS3XC_SQUARE = 2;
  35697. Phaser.Gamepad.PS3XC_TRIANGLE = 3;
  35698. Phaser.Gamepad.PS3XC_L1 = 4;
  35699. Phaser.Gamepad.PS3XC_R1 = 5;
  35700. Phaser.Gamepad.PS3XC_L2 = 6; // analog trigger, range 0..1
  35701. Phaser.Gamepad.PS3XC_R2 = 7; // analog trigger, range 0..1
  35702. Phaser.Gamepad.PS3XC_SELECT = 8;
  35703. Phaser.Gamepad.PS3XC_START = 9;
  35704. Phaser.Gamepad.PS3XC_STICK_LEFT_BUTTON = 10;
  35705. Phaser.Gamepad.PS3XC_STICK_RIGHT_BUTTON = 11;
  35706. Phaser.Gamepad.PS3XC_DPAD_UP = 12;
  35707. Phaser.Gamepad.PS3XC_DPAD_DOWN = 13;
  35708. Phaser.Gamepad.PS3XC_DPAD_LEFT = 14;
  35709. Phaser.Gamepad.PS3XC_DPAD_RIGHT = 15;
  35710. Phaser.Gamepad.PS3XC_STICK_LEFT_X = 0; // analog stick, range -1..1
  35711. Phaser.Gamepad.PS3XC_STICK_LEFT_Y = 1; // analog stick, range -1..1
  35712. Phaser.Gamepad.PS3XC_STICK_RIGHT_X = 2; // analog stick, range -1..1
  35713. Phaser.Gamepad.PS3XC_STICK_RIGHT_Y = 3; // analog stick, range -1..1
  35714. /**
  35715. * @author @karlmacklin <tacklemcclean@gmail.com>
  35716. * @author Richard Davey <rich@photonstorm.com>
  35717. * @copyright 2016 Photon Storm Ltd.
  35718. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  35719. */
  35720. /**
  35721. * A single Phaser Gamepad
  35722. *
  35723. * @class Phaser.SinglePad
  35724. * @constructor
  35725. * @param {Phaser.Game} game - Current game instance.
  35726. * @param {object} padParent - The parent Phaser.Gamepad object (all gamepads reside under this)
  35727. */
  35728. Phaser.SinglePad = function (game, padParent) {
  35729. /**
  35730. * @property {Phaser.Game} game - Local reference to game.
  35731. */
  35732. this.game = game;
  35733. /**
  35734. * @property {number} index - The gamepad index as per browsers data
  35735. * @readonly
  35736. */
  35737. this.index = null;
  35738. /**
  35739. * @property {boolean} connected - Whether or not this particular gamepad is connected or not.
  35740. * @readonly
  35741. */
  35742. this.connected = false;
  35743. /**
  35744. * @property {object} callbackContext - The context under which the callbacks are run.
  35745. */
  35746. this.callbackContext = this;
  35747. /**
  35748. * @property {function} onConnectCallback - This callback is invoked every time this gamepad is connected
  35749. */
  35750. this.onConnectCallback = null;
  35751. /**
  35752. * @property {function} onDisconnectCallback - This callback is invoked every time this gamepad is disconnected
  35753. */
  35754. this.onDisconnectCallback = null;
  35755. /**
  35756. * @property {function} onDownCallback - This callback is invoked every time a button is pressed down.
  35757. */
  35758. this.onDownCallback = null;
  35759. /**
  35760. * @property {function} onUpCallback - This callback is invoked every time a gamepad button is released.
  35761. */
  35762. this.onUpCallback = null;
  35763. /**
  35764. * @property {function} onAxisCallback - This callback is invoked every time an axis is changed.
  35765. */
  35766. this.onAxisCallback = null;
  35767. /**
  35768. * @property {function} onFloatCallback - This callback is invoked every time a button is changed to a value where value > 0 and value < 1.
  35769. */
  35770. this.onFloatCallback = null;
  35771. /**
  35772. * @property {number} deadZone - Dead zone for axis feedback - within this value you won't trigger updates.
  35773. */
  35774. this.deadZone = 0.26;
  35775. /**
  35776. * @property {Phaser.Gamepad} padParent - Main Phaser Gamepad object
  35777. * @private
  35778. */
  35779. this._padParent = padParent;
  35780. /**
  35781. * @property {object} _rawPad - The 'raw' gamepad data.
  35782. * @private
  35783. */
  35784. this._rawPad = null;
  35785. /**
  35786. * @property {number} _prevTimestamp - Used to check for differences between earlier polls and current state of gamepads.
  35787. * @private
  35788. */
  35789. this._prevTimestamp = null;
  35790. /**
  35791. * @property {Array} _buttons - Array of Phaser.DeviceButton objects. This array is populated when the gamepad is connected.
  35792. * @private
  35793. */
  35794. this._buttons = [];
  35795. /**
  35796. * @property {number} _buttonsLen - Length of the _buttons array.
  35797. * @private
  35798. */
  35799. this._buttonsLen = 0;
  35800. /**
  35801. * @property {Array} _axes - Current axes state.
  35802. * @private
  35803. */
  35804. this._axes = [];
  35805. /**
  35806. * @property {number} _axesLen - Length of the _axes array.
  35807. * @private
  35808. */
  35809. this._axesLen = 0;
  35810. };
  35811. Phaser.SinglePad.prototype = {
  35812. /**
  35813. * Add callbacks to this Gamepad to handle connect / disconnect / button down / button up / axis change / float value buttons.
  35814. *
  35815. * @method Phaser.SinglePad#addCallbacks
  35816. * @param {object} context - The context under which the callbacks are run.
  35817. * @param {object} callbacks - Object that takes six different callbak methods:
  35818. * onConnectCallback, onDisconnectCallback, onDownCallback, onUpCallback, onAxisCallback, onFloatCallback
  35819. */
  35820. addCallbacks: function (context, callbacks) {
  35821. if (typeof callbacks !== 'undefined')
  35822. {
  35823. this.onConnectCallback = (typeof callbacks.onConnect === 'function') ? callbacks.onConnect : this.onConnectCallback;
  35824. this.onDisconnectCallback = (typeof callbacks.onDisconnect === 'function') ? callbacks.onDisconnect : this.onDisconnectCallback;
  35825. this.onDownCallback = (typeof callbacks.onDown === 'function') ? callbacks.onDown : this.onDownCallback;
  35826. this.onUpCallback = (typeof callbacks.onUp === 'function') ? callbacks.onUp : this.onUpCallback;
  35827. this.onAxisCallback = (typeof callbacks.onAxis === 'function') ? callbacks.onAxis : this.onAxisCallback;
  35828. this.onFloatCallback = (typeof callbacks.onFloat === 'function') ? callbacks.onFloat : this.onFloatCallback;
  35829. this.callbackContext = context;
  35830. }
  35831. },
  35832. /**
  35833. * Gets a DeviceButton object from this controller to be stored and referenced locally.
  35834. * The DeviceButton object can then be polled, have events attached to it, etc.
  35835. *
  35836. * @method Phaser.SinglePad#getButton
  35837. * @param {number} buttonCode - The buttonCode of the button, i.e. Phaser.Gamepad.BUTTON_0, Phaser.Gamepad.XBOX360_A, etc.
  35838. * @return {Phaser.DeviceButton} The DeviceButton object which you can store locally and reference directly.
  35839. */
  35840. getButton: function (buttonCode) {
  35841. if (this._buttons[buttonCode])
  35842. {
  35843. return this._buttons[buttonCode];
  35844. }
  35845. else
  35846. {
  35847. return null;
  35848. }
  35849. },
  35850. /**
  35851. * Main update function called by Phaser.Gamepad.
  35852. *
  35853. * @method Phaser.SinglePad#pollStatus
  35854. */
  35855. pollStatus: function () {
  35856. if (!this.connected || !this.game.input.enabled || !this.game.input.gamepad.enabled || (this._rawPad.timestamp && (this._rawPad.timestamp === this._prevTimestamp)))
  35857. {
  35858. return;
  35859. }
  35860. for (var i = 0; i < this._buttonsLen; i++)
  35861. {
  35862. var rawButtonVal = isNaN(this._rawPad.buttons[i]) ? this._rawPad.buttons[i].value : this._rawPad.buttons[i];
  35863. if (rawButtonVal !== this._buttons[i].value)
  35864. {
  35865. if (rawButtonVal === 1)
  35866. {
  35867. this.processButtonDown(i, rawButtonVal);
  35868. }
  35869. else if (rawButtonVal === 0)
  35870. {
  35871. this.processButtonUp(i, rawButtonVal);
  35872. }
  35873. else
  35874. {
  35875. this.processButtonFloat(i, rawButtonVal);
  35876. }
  35877. }
  35878. }
  35879. for (var index = 0; index < this._axesLen; index++)
  35880. {
  35881. var value = this._rawPad.axes[index];
  35882. if ((value > 0 && value > this.deadZone) || (value < 0 && value < -this.deadZone))
  35883. {
  35884. this.processAxisChange(index, value);
  35885. }
  35886. else
  35887. {
  35888. this.processAxisChange(index, 0);
  35889. }
  35890. }
  35891. this._prevTimestamp = this._rawPad.timestamp;
  35892. },
  35893. /**
  35894. * Gamepad connect function, should be called by Phaser.Gamepad.
  35895. *
  35896. * @method Phaser.SinglePad#connect
  35897. * @param {object} rawPad - The raw gamepad object
  35898. */
  35899. connect: function (rawPad) {
  35900. var triggerCallback = !this.connected;
  35901. this.connected = true;
  35902. this.index = rawPad.index;
  35903. this._rawPad = rawPad;
  35904. this._buttons = [];
  35905. this._buttonsLen = rawPad.buttons.length;
  35906. this._axes = [];
  35907. this._axesLen = rawPad.axes.length;
  35908. for (var a = 0; a < this._axesLen; a++)
  35909. {
  35910. this._axes[a] = rawPad.axes[a];
  35911. }
  35912. for (var buttonCode in rawPad.buttons)
  35913. {
  35914. buttonCode = parseInt(buttonCode, 10);
  35915. this._buttons[buttonCode] = new Phaser.DeviceButton(this, buttonCode);
  35916. }
  35917. if (triggerCallback && this._padParent.onConnectCallback)
  35918. {
  35919. this._padParent.onConnectCallback.call(this._padParent.callbackContext, this.index);
  35920. }
  35921. if (triggerCallback && this.onConnectCallback)
  35922. {
  35923. this.onConnectCallback.call(this.callbackContext);
  35924. }
  35925. },
  35926. /**
  35927. * Gamepad disconnect function, should be called by Phaser.Gamepad.
  35928. *
  35929. * @method Phaser.SinglePad#disconnect
  35930. */
  35931. disconnect: function () {
  35932. var triggerCallback = this.connected;
  35933. var disconnectingIndex = this.index;
  35934. this.connected = false;
  35935. this.index = null;
  35936. this._rawPad = undefined;
  35937. for (var i = 0; i < this._buttonsLen; i++)
  35938. {
  35939. this._buttons[i].destroy();
  35940. }
  35941. this._buttons = [];
  35942. this._buttonsLen = 0;
  35943. this._axes = [];
  35944. this._axesLen = 0;
  35945. if (triggerCallback && this._padParent.onDisconnectCallback)
  35946. {
  35947. this._padParent.onDisconnectCallback.call(this._padParent.callbackContext, disconnectingIndex);
  35948. }
  35949. if (triggerCallback && this.onDisconnectCallback)
  35950. {
  35951. this.onDisconnectCallback.call(this.callbackContext);
  35952. }
  35953. },
  35954. /**
  35955. * Destroys this object and associated callback references.
  35956. *
  35957. * @method Phaser.SinglePad#destroy
  35958. */
  35959. destroy: function () {
  35960. this._rawPad = undefined;
  35961. for (var i = 0; i < this._buttonsLen; i++)
  35962. {
  35963. this._buttons[i].destroy();
  35964. }
  35965. this._buttons = [];
  35966. this._buttonsLen = 0;
  35967. this._axes = [];
  35968. this._axesLen = 0;
  35969. this.onConnectCallback = null;
  35970. this.onDisconnectCallback = null;
  35971. this.onDownCallback = null;
  35972. this.onUpCallback = null;
  35973. this.onAxisCallback = null;
  35974. this.onFloatCallback = null;
  35975. },
  35976. /**
  35977. * Handles changes in axis.
  35978. *
  35979. * @method Phaser.SinglePad#processAxisChange
  35980. * @param {object} axisState - State of the relevant axis
  35981. */
  35982. processAxisChange: function (index, value) {
  35983. if (this._axes[index] === value)
  35984. {
  35985. return;
  35986. }
  35987. this._axes[index] = value;
  35988. if (this._padParent.onAxisCallback)
  35989. {
  35990. this._padParent.onAxisCallback.call(this._padParent.callbackContext, this, index, value);
  35991. }
  35992. if (this.onAxisCallback)
  35993. {
  35994. this.onAxisCallback.call(this.callbackContext, this, index, value);
  35995. }
  35996. },
  35997. /**
  35998. * Handles button down press.
  35999. *
  36000. * @method Phaser.SinglePad#processButtonDown
  36001. * @param {number} buttonCode - Which buttonCode of this button
  36002. * @param {object} value - Button value
  36003. */
  36004. processButtonDown: function (buttonCode, value) {
  36005. if (this._buttons[buttonCode])
  36006. {
  36007. this._buttons[buttonCode].start(null, value);
  36008. }
  36009. if (this._padParent.onDownCallback)
  36010. {
  36011. this._padParent.onDownCallback.call(this._padParent.callbackContext, buttonCode, value, this.index);
  36012. }
  36013. if (this.onDownCallback)
  36014. {
  36015. this.onDownCallback.call(this.callbackContext, buttonCode, value);
  36016. }
  36017. },
  36018. /**
  36019. * Handles button release.
  36020. *
  36021. * @method Phaser.SinglePad#processButtonUp
  36022. * @param {number} buttonCode - Which buttonCode of this button
  36023. * @param {object} value - Button value
  36024. */
  36025. processButtonUp: function (buttonCode, value) {
  36026. if (this._padParent.onUpCallback)
  36027. {
  36028. this._padParent.onUpCallback.call(this._padParent.callbackContext, buttonCode, value, this.index);
  36029. }
  36030. if (this.onUpCallback)
  36031. {
  36032. this.onUpCallback.call(this.callbackContext, buttonCode, value);
  36033. }
  36034. if (this._buttons[buttonCode])
  36035. {
  36036. this._buttons[buttonCode].stop(null, value);
  36037. }
  36038. },
  36039. /**
  36040. * Handles buttons with floating values (like analog buttons that acts almost like an axis but still registers like a button)
  36041. *
  36042. * @method Phaser.SinglePad#processButtonFloat
  36043. * @param {number} buttonCode - Which buttonCode of this button
  36044. * @param {object} value - Button value (will range somewhere between 0 and 1, but not specifically 0 or 1.
  36045. */
  36046. processButtonFloat: function (buttonCode, value) {
  36047. if (this._padParent.onFloatCallback)
  36048. {
  36049. this._padParent.onFloatCallback.call(this._padParent.callbackContext, buttonCode, value, this.index);
  36050. }
  36051. if (this.onFloatCallback)
  36052. {
  36053. this.onFloatCallback.call(this.callbackContext, buttonCode, value);
  36054. }
  36055. if (this._buttons[buttonCode])
  36056. {
  36057. this._buttons[buttonCode].padFloat(value);
  36058. }
  36059. },
  36060. /**
  36061. * Returns value of requested axis.
  36062. *
  36063. * @method Phaser.SinglePad#axis
  36064. * @param {number} axisCode - The index of the axis to check
  36065. * @return {number} Axis value if available otherwise false
  36066. */
  36067. axis: function (axisCode) {
  36068. if (this._axes[axisCode])
  36069. {
  36070. return this._axes[axisCode];
  36071. }
  36072. return false;
  36073. },
  36074. /**
  36075. * Returns true if the button is pressed down.
  36076. *
  36077. * @method Phaser.SinglePad#isDown
  36078. * @param {number} buttonCode - The buttonCode of the button to check.
  36079. * @return {boolean} True if the button is pressed down.
  36080. */
  36081. isDown: function (buttonCode) {
  36082. if (this._buttons[buttonCode])
  36083. {
  36084. return this._buttons[buttonCode].isDown;
  36085. }
  36086. return false;
  36087. },
  36088. /**
  36089. * Returns true if the button is not currently pressed.
  36090. *
  36091. * @method Phaser.SinglePad#isUp
  36092. * @param {number} buttonCode - The buttonCode of the button to check.
  36093. * @return {boolean} True if the button is not currently pressed down.
  36094. */
  36095. isUp: function (buttonCode) {
  36096. if (this._buttons[buttonCode])
  36097. {
  36098. return this._buttons[buttonCode].isUp;
  36099. }
  36100. return false;
  36101. },
  36102. /**
  36103. * Returns the "just released" state of a button from this gamepad. Just released is considered as being true if the button was released within the duration given (default 250ms).
  36104. *
  36105. * @method Phaser.SinglePad#justReleased
  36106. * @param {number} buttonCode - The buttonCode of the button to check for.
  36107. * @param {number} [duration=250] - The duration below which the button is considered as being just released.
  36108. * @return {boolean} True if the button is just released otherwise false.
  36109. */
  36110. justReleased: function (buttonCode, duration) {
  36111. if (this._buttons[buttonCode])
  36112. {
  36113. return this._buttons[buttonCode].justReleased(duration);
  36114. }
  36115. },
  36116. /**
  36117. * Returns the "just pressed" state of a button from this gamepad. Just pressed is considered true if the button was pressed down within the duration given (default 250ms).
  36118. *
  36119. * @method Phaser.SinglePad#justPressed
  36120. * @param {number} buttonCode - The buttonCode of the button to check for.
  36121. * @param {number} [duration=250] - The duration below which the button is considered as being just pressed.
  36122. * @return {boolean} True if the button is just pressed otherwise false.
  36123. */
  36124. justPressed: function (buttonCode, duration) {
  36125. if (this._buttons[buttonCode])
  36126. {
  36127. return this._buttons[buttonCode].justPressed(duration);
  36128. }
  36129. },
  36130. /**
  36131. * Returns the value of a gamepad button. Intended mainly for cases when you have floating button values, for example
  36132. * analog trigger buttons on the XBOX 360 controller.
  36133. *
  36134. * @method Phaser.SinglePad#buttonValue
  36135. * @param {number} buttonCode - The buttonCode of the button to check.
  36136. * @return {number} Button value if available otherwise null. Be careful as this can incorrectly evaluate to 0.
  36137. */
  36138. buttonValue: function (buttonCode) {
  36139. if (this._buttons[buttonCode])
  36140. {
  36141. return this._buttons[buttonCode].value;
  36142. }
  36143. return null;
  36144. },
  36145. /**
  36146. * Reset all buttons/axes of this gamepad.
  36147. *
  36148. * @method Phaser.SinglePad#reset
  36149. */
  36150. reset: function () {
  36151. for (var j = 0; j < this._axes.length; j++)
  36152. {
  36153. this._axes[j] = 0;
  36154. }
  36155. }
  36156. };
  36157. Phaser.SinglePad.prototype.constructor = Phaser.SinglePad;
  36158. /**
  36159. * @author Richard Davey <rich@photonstorm.com>
  36160. * @copyright 2016 Photon Storm Ltd.
  36161. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  36162. */
  36163. /**
  36164. * If you need more fine-grained control over the handling of specific keys you can create and use Phaser.Key objects.
  36165. *
  36166. * @class Phaser.Key
  36167. * @constructor
  36168. * @param {Phaser.Game} game - Current game instance.
  36169. * @param {integer} keycode - The key code this Key is responsible for. See {@link Phaser.KeyCode}.
  36170. */
  36171. Phaser.Key = function (game, keycode) {
  36172. /**
  36173. * @property {Phaser.Game} game - A reference to the currently running game.
  36174. */
  36175. this.game = game;
  36176. /**
  36177. * The enabled state of the key - see `enabled`.
  36178. * @property {boolean} _enabled
  36179. * @private
  36180. */
  36181. this._enabled = true;
  36182. /**
  36183. * @property {object} event - Stores the most recent DOM event.
  36184. * @readonly
  36185. */
  36186. this.event = null;
  36187. /**
  36188. * @property {boolean} isDown - The "down" state of the key. This will remain `true` for as long as the keyboard thinks this key is held down.
  36189. * @default
  36190. */
  36191. this.isDown = false;
  36192. /**
  36193. * @property {boolean} isUp - The "up" state of the key. This will remain `true` for as long as the keyboard thinks this key is up.
  36194. * @default
  36195. */
  36196. this.isUp = true;
  36197. /**
  36198. * @property {boolean} altKey - The down state of the ALT key, if pressed at the same time as this key.
  36199. * @default
  36200. */
  36201. this.altKey = false;
  36202. /**
  36203. * @property {boolean} ctrlKey - The down state of the CTRL key, if pressed at the same time as this key.
  36204. * @default
  36205. */
  36206. this.ctrlKey = false;
  36207. /**
  36208. * @property {boolean} shiftKey - The down state of the SHIFT key, if pressed at the same time as this key.
  36209. * @default
  36210. */
  36211. this.shiftKey = false;
  36212. /**
  36213. * @property {number} timeDown - The timestamp when the key was last pressed down. This is based on Game.time.now.
  36214. */
  36215. this.timeDown = 0;
  36216. /**
  36217. * If the key is down this value holds the duration of that key press and is constantly updated.
  36218. * If the key is up it holds the duration of the previous down session.
  36219. * @property {number} duration - The number of milliseconds this key has been held down for.
  36220. * @default
  36221. */
  36222. this.duration = 0;
  36223. /**
  36224. * @property {number} timeUp - The timestamp when the key was last released. This is based on Game.time.now.
  36225. * @default
  36226. */
  36227. this.timeUp = -2500;
  36228. /**
  36229. * If the key is up this value holds the duration of that key release and is constantly updated.
  36230. * If the key is down it holds the duration of the previous up session.
  36231. * @property {number} duration - The number of milliseconds this key has been up for.
  36232. * @default
  36233. */
  36234. this.durationUp = -2500;
  36235. /**
  36236. * @property {number} repeats - If a key is held down this holds down the number of times the key has 'repeated'.
  36237. * @default
  36238. */
  36239. this.repeats = 0;
  36240. /**
  36241. * @property {number} keyCode - The keycode of this key.
  36242. */
  36243. this.keyCode = keycode;
  36244. /**
  36245. * @property {Phaser.Signal} onDown - This Signal is dispatched every time this Key is pressed down. It is only dispatched once (until the key is released again).
  36246. */
  36247. this.onDown = new Phaser.Signal();
  36248. /**
  36249. * @property {function} onHoldCallback - A callback that is called while this Key is held down. Warning: Depending on refresh rate that could be 60+ times per second.
  36250. */
  36251. this.onHoldCallback = null;
  36252. /**
  36253. * @property {object} onHoldContext - The context under which the onHoldCallback will be called.
  36254. */
  36255. this.onHoldContext = null;
  36256. /**
  36257. * @property {Phaser.Signal} onUp - This Signal is dispatched every time this Key is released. It is only dispatched once (until the key is pressed and released again).
  36258. */
  36259. this.onUp = new Phaser.Signal();
  36260. /**
  36261. * @property {boolean} _justDown - True if the key has just been pressed (NOTE: requires to be reset, see justDown getter)
  36262. * @private
  36263. */
  36264. this._justDown = false;
  36265. /**
  36266. * @property {boolean} _justUp - True if the key has just been pressed (NOTE: requires to be reset, see justDown getter)
  36267. * @private
  36268. */
  36269. this._justUp = false;
  36270. };
  36271. Phaser.Key.prototype = {
  36272. /**
  36273. * Called automatically by Phaser.Keyboard.
  36274. *
  36275. * @method Phaser.Key#update
  36276. * @protected
  36277. */
  36278. update: function () {
  36279. if (!this._enabled) { return; }
  36280. if (this.isDown)
  36281. {
  36282. this.duration = this.game.time.time - this.timeDown;
  36283. this.repeats++;
  36284. if (this.onHoldCallback)
  36285. {
  36286. this.onHoldCallback.call(this.onHoldContext, this);
  36287. }
  36288. }
  36289. else
  36290. {
  36291. this.durationUp = this.game.time.time - this.timeUp;
  36292. }
  36293. },
  36294. /**
  36295. * Called automatically by Phaser.Keyboard.
  36296. *
  36297. * @method Phaser.Key#processKeyDown
  36298. * @param {KeyboardEvent} event - The DOM event that triggered this.
  36299. * @protected
  36300. */
  36301. processKeyDown: function (event) {
  36302. if (!this._enabled) { return; }
  36303. this.event = event;
  36304. // exit if this key down is from auto-repeat
  36305. if (this.isDown)
  36306. {
  36307. return;
  36308. }
  36309. this.altKey = event.altKey;
  36310. this.ctrlKey = event.ctrlKey;
  36311. this.shiftKey = event.shiftKey;
  36312. this.isDown = true;
  36313. this.isUp = false;
  36314. this.timeDown = this.game.time.time;
  36315. this.duration = 0;
  36316. this.durationUp = this.game.time.time - this.timeUp;
  36317. this.repeats = 0;
  36318. // _justDown will remain true until it is read via the justDown Getter
  36319. // this enables the game to poll for past presses, or reset it at the start of a new game state
  36320. this._justDown = true;
  36321. this.onDown.dispatch(this);
  36322. },
  36323. /**
  36324. * Called automatically by Phaser.Keyboard.
  36325. *
  36326. * @method Phaser.Key#processKeyUp
  36327. * @param {KeyboardEvent} event - The DOM event that triggered this.
  36328. * @protected
  36329. */
  36330. processKeyUp: function (event) {
  36331. if (!this._enabled) { return; }
  36332. this.event = event;
  36333. if (this.isUp)
  36334. {
  36335. return;
  36336. }
  36337. this.isDown = false;
  36338. this.isUp = true;
  36339. this.timeUp = this.game.time.time;
  36340. this.duration = this.game.time.time - this.timeDown;
  36341. this.durationUp = 0;
  36342. // _justUp will remain true until it is read via the justUp Getter
  36343. // this enables the game to poll for past presses, or reset it at the start of a new game state
  36344. this._justUp = true;
  36345. this.onUp.dispatch(this);
  36346. },
  36347. /**
  36348. * Resets the state of this Key.
  36349. *
  36350. * This sets isDown to false, isUp to true, resets the time to be the current time, and _enables_ the key.
  36351. * In addition, if it is a "hard reset", it clears clears any callbacks associated with the onDown and onUp events and removes the onHoldCallback.
  36352. *
  36353. * @method Phaser.Key#reset
  36354. * @param {boolean} [hard=true] - A soft reset won't reset any events or callbacks; a hard reset will.
  36355. */
  36356. reset: function (hard) {
  36357. if (hard === undefined) { hard = true; }
  36358. this.isDown = false;
  36359. this.isUp = true;
  36360. this.timeUp = this.game.time.time;
  36361. this.duration = 0;
  36362. this.durationUp = -2500;
  36363. this._enabled = true; // .enabled causes reset(false)
  36364. this._justDown = false;
  36365. this._justUp = false;
  36366. if (hard)
  36367. {
  36368. this.onDown.removeAll();
  36369. this.onUp.removeAll();
  36370. this.onHoldCallback = null;
  36371. this.onHoldContext = null;
  36372. }
  36373. },
  36374. /**
  36375. * Returns `true` if the Key was pressed down within the `duration` value given, or `false` if it either isn't down,
  36376. * or was pressed down longer ago than then given duration.
  36377. *
  36378. * @method Phaser.Key#downDuration
  36379. * @param {number} [duration=50] - The duration within which the key is considered as being just pressed. Given in ms.
  36380. * @return {boolean} True if the key was pressed down within the given duration.
  36381. */
  36382. downDuration: function (duration) {
  36383. if (duration === undefined) { duration = 50; }
  36384. return (this.isDown && this.duration < duration);
  36385. },
  36386. /**
  36387. * Returns `true` if the Key was pressed down within the `duration` value given, or `false` if it either isn't down,
  36388. * or was pressed down longer ago than then given duration.
  36389. *
  36390. * @method Phaser.Key#upDuration
  36391. * @param {number} [duration=50] - The duration within which the key is considered as being just released. Given in ms.
  36392. * @return {boolean} True if the key was released within the given duration.
  36393. */
  36394. upDuration: function (duration) {
  36395. if (duration === undefined) { duration = 50; }
  36396. return (!this.isDown && ((this.game.time.time - this.timeUp) < duration));
  36397. },
  36398. /**
  36399. * Returns `true` if the Key was just pressed down this update tick, or `false` if it either isn't down,
  36400. * or was pressed down on a previous update tick.
  36401. *
  36402. * @method Phaser.Key#justPressed
  36403. * @return {boolean} True if the key was just pressed down this update tick.
  36404. */
  36405. justPressed: function () {
  36406. return (this.isDown && this.duration === 0);
  36407. },
  36408. /**
  36409. * Returns `true` if the Key was just released this update tick, or `false` if it either isn't up,
  36410. * or was released on a previous update tick.
  36411. *
  36412. * @method Phaser.Key#justReleased
  36413. * @return {boolean} True if the key was just released this update tick.
  36414. */
  36415. justReleased: function () {
  36416. return (!this.isDown && this.durationUp === 0);
  36417. }
  36418. };
  36419. /**
  36420. * The justDown value allows you to test if this Key has just been pressed down or not.
  36421. * When you check this value it will return `true` if the Key is down, otherwise `false`.
  36422. * You can only call justDown once per key press. It will only return `true` once, until the Key is released and pressed down again.
  36423. * This allows you to use it in situations where you want to check if this key is down without using a Signal, such as in a core game loop.
  36424. *
  36425. * @name Phaser.Key#justDown
  36426. * @property {boolean} justDown
  36427. * @memberof Phaser.Key
  36428. * @default false
  36429. */
  36430. Object.defineProperty(Phaser.Key.prototype, "justDown", {
  36431. get: function () {
  36432. var current = this._justDown;
  36433. this._justDown = false;
  36434. return current;
  36435. }
  36436. });
  36437. /**
  36438. * The justUp value allows you to test if this Key has just been released or not.
  36439. * When you check this value it will return `true` if the Key is up, otherwise `false`.
  36440. * You can only call justUp once per key release. It will only return `true` once, until the Key is pressed down and released again.
  36441. * This allows you to use it in situations where you want to check if this key is up without using a Signal, such as in a core game loop.
  36442. *
  36443. * @name Phaser.Key#justUp
  36444. * @property {boolean} justUp
  36445. * @memberof Phaser.Key
  36446. * @default false
  36447. */
  36448. Object.defineProperty(Phaser.Key.prototype, "justUp", {
  36449. get: function () {
  36450. var current = this._justUp;
  36451. this._justUp = false;
  36452. return current;
  36453. }
  36454. });
  36455. /**
  36456. * An enabled key processes its update and dispatches events.
  36457. * A key can be disabled momentarily at runtime instead of deleting it.
  36458. * @name Phaser.Key#enabled
  36459. * @property {boolean} enabled
  36460. * @memberof Phaser.Key
  36461. * @default true
  36462. */
  36463. Object.defineProperty(Phaser.Key.prototype, "enabled", {
  36464. get: function () {
  36465. return this._enabled;
  36466. },
  36467. set: function (value) {
  36468. value = !!value;
  36469. if (value !== this._enabled)
  36470. {
  36471. if (!value)
  36472. {
  36473. this.reset(false);
  36474. }
  36475. this._enabled = value;
  36476. }
  36477. }
  36478. });
  36479. Phaser.Key.prototype.constructor = Phaser.Key;
  36480. /**
  36481. * @author Richard Davey <rich@photonstorm.com>
  36482. * @copyright 2016 Photon Storm Ltd.
  36483. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  36484. */
  36485. /**
  36486. * The Keyboard class monitors keyboard input and dispatches keyboard events.
  36487. *
  36488. * _Note_: many keyboards are unable to process certain combinations of keys due to hardware limitations known as ghosting.
  36489. * See http://www.html5gamedevs.com/topic/4876-impossible-to-use-more-than-2-keyboard-input-buttons-at-the-same-time/ for more details.
  36490. *
  36491. * Also please be aware that certain browser extensions can disable or override Phaser keyboard handling.
  36492. * For example the Chrome extension vimium is known to disable Phaser from using the D key. And there are others.
  36493. * So please check your extensions before opening Phaser issues.
  36494. *
  36495. * @class Phaser.Keyboard
  36496. * @constructor
  36497. * @param {Phaser.Game} game - A reference to the currently running game.
  36498. */
  36499. Phaser.Keyboard = function (game) {
  36500. /**
  36501. * @property {Phaser.Game} game - Local reference to game.
  36502. */
  36503. this.game = game;
  36504. /**
  36505. * Keyboard input will only be processed if enabled.
  36506. * @property {boolean} enabled
  36507. * @default
  36508. */
  36509. this.enabled = true;
  36510. /**
  36511. * @property {object} event - The most recent DOM event from keydown or keyup. This is updated every time a new key is pressed or released.
  36512. */
  36513. this.event = null;
  36514. /**
  36515. * @property {object} pressEvent - The most recent DOM event from keypress.
  36516. */
  36517. this.pressEvent = null;
  36518. /**
  36519. * @property {object} callbackContext - The context under which the callbacks are run.
  36520. */
  36521. this.callbackContext = this;
  36522. /**
  36523. * @property {function} onDownCallback - This callback is invoked every time a key is pressed down, including key repeats when a key is held down.
  36524. */
  36525. this.onDownCallback = null;
  36526. /**
  36527. * @property {function} onPressCallback - This callback is invoked every time a DOM onkeypress event is raised, which is only for printable keys.
  36528. */
  36529. this.onPressCallback = null;
  36530. /**
  36531. * @property {function} onUpCallback - This callback is invoked every time a key is released.
  36532. */
  36533. this.onUpCallback = null;
  36534. /**
  36535. * @property {array<Phaser.Key>} _keys - The array the Phaser.Key objects are stored in.
  36536. * @private
  36537. */
  36538. this._keys = [];
  36539. /**
  36540. * @property {array} _capture - The array the key capture values are stored in.
  36541. * @private
  36542. */
  36543. this._capture = [];
  36544. /**
  36545. * @property {function} _onKeyDown
  36546. * @private
  36547. * @default
  36548. */
  36549. this._onKeyDown = null;
  36550. /**
  36551. * @property {function} _onKeyPress
  36552. * @private
  36553. * @default
  36554. */
  36555. this._onKeyPress = null;
  36556. /**
  36557. * @property {function} _onKeyUp
  36558. * @private
  36559. * @default
  36560. */
  36561. this._onKeyUp = null;
  36562. /**
  36563. * @property {number} _i - Internal cache var
  36564. * @private
  36565. */
  36566. this._i = 0;
  36567. /**
  36568. * @property {number} _k - Internal cache var
  36569. * @private
  36570. */
  36571. this._k = 0;
  36572. };
  36573. Phaser.Keyboard.prototype = {
  36574. /**
  36575. * Add callbacks to the Keyboard handler so that each time a key is pressed down or released the callbacks are activated.
  36576. *
  36577. * @method Phaser.Keyboard#addCallbacks
  36578. * @param {object} context - The context under which the callbacks are run.
  36579. * @param {function} [onDown=null] - This callback is invoked every time a key is pressed down.
  36580. * @param {function} [onUp=null] - This callback is invoked every time a key is released.
  36581. * @param {function} [onPress=null] - This callback is invoked every time the onkeypress event is raised.
  36582. */
  36583. addCallbacks: function (context, onDown, onUp, onPress) {
  36584. this.callbackContext = context;
  36585. if (onDown !== undefined && onDown !== null)
  36586. {
  36587. this.onDownCallback = onDown;
  36588. }
  36589. if (onUp !== undefined && onUp !== null)
  36590. {
  36591. this.onUpCallback = onUp;
  36592. }
  36593. if (onPress !== undefined && onPress !== null)
  36594. {
  36595. this.onPressCallback = onPress;
  36596. }
  36597. },
  36598. /**
  36599. * If you need more fine-grained control over a Key you can create a new Phaser.Key object via this method.
  36600. * The Key object can then be polled, have events attached to it, etc.
  36601. *
  36602. * @method Phaser.Keyboard#addKey
  36603. * @param {integer} keycode - The {@link Phaser.KeyCode keycode} of the key.
  36604. * @return {Phaser.Key} The Key object which you can store locally and reference directly.
  36605. */
  36606. addKey: function (keycode) {
  36607. if (!this._keys[keycode])
  36608. {
  36609. this._keys[keycode] = new Phaser.Key(this.game, keycode);
  36610. this.addKeyCapture(keycode);
  36611. }
  36612. return this._keys[keycode];
  36613. },
  36614. /**
  36615. * A practical way to create an object containing user selected hotkeys.
  36616. *
  36617. * For example,
  36618. *
  36619. * addKeys( { 'up': Phaser.KeyCode.W, 'down': Phaser.KeyCode.S, 'left': Phaser.KeyCode.A, 'right': Phaser.KeyCode.D } );
  36620. *
  36621. * would return an object containing properties (`up`, `down`, `left` and `right`) referring to {@link Phaser.Key} object.
  36622. *
  36623. * @method Phaser.Keyboard#addKeys
  36624. * @param {object} keys - A key mapping object, i.e. `{ 'up': Phaser.KeyCode.W, 'down': Phaser.KeyCode.S }` or `{ 'up': 52, 'down': 53 }`.
  36625. * @return {object} An object containing the properties mapped to {@link Phaser.Key} values.
  36626. */
  36627. addKeys: function (keys) {
  36628. var output = {};
  36629. for (var key in keys)
  36630. {
  36631. output[key] = this.addKey(keys[key]);
  36632. }
  36633. return output;
  36634. },
  36635. /**
  36636. * Removes a Key object from the Keyboard manager.
  36637. *
  36638. * @method Phaser.Keyboard#removeKey
  36639. * @param {integer} keycode - The {@link Phaser.KeyCode keycode} of the key to remove.
  36640. */
  36641. removeKey: function (keycode) {
  36642. if (this._keys[keycode])
  36643. {
  36644. this._keys[keycode] = null;
  36645. this.removeKeyCapture(keycode);
  36646. }
  36647. },
  36648. /**
  36649. * Creates and returns an object containing 4 hotkeys for Up, Down, Left and Right.
  36650. *
  36651. * @method Phaser.Keyboard#createCursorKeys
  36652. * @return {object} An object containing properties: `up`, `down`, `left` and `right` of {@link Phaser.Key} objects.
  36653. */
  36654. createCursorKeys: function () {
  36655. return this.addKeys({ 'up': Phaser.KeyCode.UP, 'down': Phaser.KeyCode.DOWN, 'left': Phaser.KeyCode.LEFT, 'right': Phaser.KeyCode.RIGHT });
  36656. },
  36657. /**
  36658. * Starts the Keyboard event listeners running (keydown, keyup and keypress). They are attached to the window.
  36659. * This is called automatically by Phaser.Input and should not normally be invoked directly.
  36660. *
  36661. * @method Phaser.Keyboard#start
  36662. * @protected
  36663. */
  36664. start: function () {
  36665. if (this.game.device.cocoonJS)
  36666. {
  36667. return;
  36668. }
  36669. if (this._onKeyDown !== null)
  36670. {
  36671. // Avoid setting multiple listeners
  36672. return;
  36673. }
  36674. var _this = this;
  36675. this._onKeyDown = function (event) {
  36676. return _this.processKeyDown(event);
  36677. };
  36678. this._onKeyUp = function (event) {
  36679. return _this.processKeyUp(event);
  36680. };
  36681. this._onKeyPress = function (event) {
  36682. return _this.processKeyPress(event);
  36683. };
  36684. window.addEventListener('keydown', this._onKeyDown, false);
  36685. window.addEventListener('keyup', this._onKeyUp, false);
  36686. window.addEventListener('keypress', this._onKeyPress, false);
  36687. },
  36688. /**
  36689. * Stops the Keyboard event listeners from running (keydown, keyup and keypress). They are removed from the window.
  36690. *
  36691. * @method Phaser.Keyboard#stop
  36692. */
  36693. stop: function () {
  36694. window.removeEventListener('keydown', this._onKeyDown);
  36695. window.removeEventListener('keyup', this._onKeyUp);
  36696. window.removeEventListener('keypress', this._onKeyPress);
  36697. this._onKeyDown = null;
  36698. this._onKeyUp = null;
  36699. this._onKeyPress = null;
  36700. },
  36701. /**
  36702. * Stops the Keyboard event listeners from running (keydown and keyup). They are removed from the window.
  36703. * Also clears all key captures and currently created Key objects.
  36704. *
  36705. * @method Phaser.Keyboard#destroy
  36706. */
  36707. destroy: function () {
  36708. this.stop();
  36709. this.clearCaptures();
  36710. this._keys.length = 0;
  36711. this._i = 0;
  36712. },
  36713. /**
  36714. * By default when a key is pressed Phaser will not stop the event from propagating up to the browser.
  36715. * There are some keys this can be annoying for, like the arrow keys or space bar, which make the browser window scroll.
  36716. *
  36717. * The `addKeyCapture` method enables consuming keyboard event for specific keys so it doesn't bubble up to the the browser
  36718. * and cause the default browser behavior.
  36719. *
  36720. * Pass in either a single keycode or an array/hash of keycodes.
  36721. *
  36722. * @method Phaser.Keyboard#addKeyCapture
  36723. * @param {integer|integer[]|object} keycode - Either a single {@link Phaser.KeyCode keycode} or an array/hash of keycodes such as `[65, 67, 68]`.
  36724. */
  36725. addKeyCapture: function (keycode) {
  36726. if (typeof keycode === 'object')
  36727. {
  36728. for (var key in keycode)
  36729. {
  36730. this._capture[keycode[key]] = true;
  36731. }
  36732. }
  36733. else
  36734. {
  36735. this._capture[keycode] = true;
  36736. }
  36737. },
  36738. /**
  36739. * Removes an existing key capture.
  36740. *
  36741. * @method Phaser.Keyboard#removeKeyCapture
  36742. * @param {integer} keycode - The {@link Phaser.KeyCode keycode} to remove capturing of.
  36743. */
  36744. removeKeyCapture: function (keycode) {
  36745. delete this._capture[keycode];
  36746. },
  36747. /**
  36748. * Clear all set key captures.
  36749. *
  36750. * @method Phaser.Keyboard#clearCaptures
  36751. */
  36752. clearCaptures: function () {
  36753. this._capture = {};
  36754. },
  36755. /**
  36756. * Updates all currently defined keys.
  36757. *
  36758. * @method Phaser.Keyboard#update
  36759. */
  36760. update: function () {
  36761. this._i = this._keys.length;
  36762. while (this._i--)
  36763. {
  36764. if (this._keys[this._i])
  36765. {
  36766. this._keys[this._i].update();
  36767. }
  36768. }
  36769. },
  36770. /**
  36771. * Process the keydown event.
  36772. *
  36773. * @method Phaser.Keyboard#processKeyDown
  36774. * @param {KeyboardEvent} event
  36775. * @protected
  36776. */
  36777. processKeyDown: function (event) {
  36778. this.event = event;
  36779. if (!this.game.input.enabled || !this.enabled)
  36780. {
  36781. return;
  36782. }
  36783. var key = event.keyCode;
  36784. // The event is being captured but another hotkey may need it
  36785. if (this._capture[key])
  36786. {
  36787. event.preventDefault();
  36788. }
  36789. if (!this._keys[key])
  36790. {
  36791. this._keys[key] = new Phaser.Key(this.game, key);
  36792. }
  36793. this._keys[key].processKeyDown(event);
  36794. this._k = key;
  36795. if (this.onDownCallback)
  36796. {
  36797. this.onDownCallback.call(this.callbackContext, event);
  36798. }
  36799. },
  36800. /**
  36801. * Process the keypress event.
  36802. *
  36803. * @method Phaser.Keyboard#processKeyPress
  36804. * @param {KeyboardEvent} event
  36805. * @protected
  36806. */
  36807. processKeyPress: function (event) {
  36808. this.pressEvent = event;
  36809. if (!this.game.input.enabled || !this.enabled)
  36810. {
  36811. return;
  36812. }
  36813. if (this.onPressCallback)
  36814. {
  36815. this.onPressCallback.call(this.callbackContext, String.fromCharCode(event.charCode), event);
  36816. }
  36817. },
  36818. /**
  36819. * Process the keyup event.
  36820. *
  36821. * @method Phaser.Keyboard#processKeyUp
  36822. * @param {KeyboardEvent} event
  36823. * @protected
  36824. */
  36825. processKeyUp: function (event) {
  36826. this.event = event;
  36827. if (!this.game.input.enabled || !this.enabled)
  36828. {
  36829. return;
  36830. }
  36831. var key = event.keyCode;
  36832. if (this._capture[key])
  36833. {
  36834. event.preventDefault();
  36835. }
  36836. if (!this._keys[key])
  36837. {
  36838. this._keys[key] = new Phaser.Key(this.game, key);
  36839. }
  36840. this._keys[key].processKeyUp(event);
  36841. if (this.onUpCallback)
  36842. {
  36843. this.onUpCallback.call(this.callbackContext, event);
  36844. }
  36845. },
  36846. /**
  36847. * Resets all Keys.
  36848. *
  36849. * @method Phaser.Keyboard#reset
  36850. * @param {boolean} [hard=true] - A soft reset won't reset any events or callbacks that are bound to the Keys. A hard reset will.
  36851. */
  36852. reset: function (hard) {
  36853. if (hard === undefined) { hard = true; }
  36854. this.event = null;
  36855. var i = this._keys.length;
  36856. while (i--)
  36857. {
  36858. if (this._keys[i])
  36859. {
  36860. this._keys[i].reset(hard);
  36861. }
  36862. }
  36863. },
  36864. /**
  36865. * Returns `true` if the Key was pressed down within the `duration` value given, or `false` if it either isn't down,
  36866. * or was pressed down longer ago than then given duration.
  36867. *
  36868. * @method Phaser.Keyboard#downDuration
  36869. * @param {integer} keycode - The {@link Phaser.KeyCode keycode} of the key to check: i.e. Phaser.KeyCode.UP or Phaser.KeyCode.SPACEBAR.
  36870. * @param {number} [duration=50] - The duration within which the key is considered as being just pressed. Given in ms.
  36871. * @return {boolean} True if the key was pressed down within the given duration, false if not or null if the Key wasn't found.
  36872. */
  36873. downDuration: function (keycode, duration) {
  36874. if (this._keys[keycode])
  36875. {
  36876. return this._keys[keycode].downDuration(duration);
  36877. }
  36878. else
  36879. {
  36880. return null;
  36881. }
  36882. },
  36883. /**
  36884. * Returns `true` if the Key was pressed down within the `duration` value given, or `false` if it either isn't down,
  36885. * or was pressed down longer ago than then given duration.
  36886. *
  36887. * @method Phaser.Keyboard#upDuration
  36888. * @param {Phaser.KeyCode|integer} keycode - The keycode of the key to check, i.e. Phaser.KeyCode.UP or Phaser.KeyCode.SPACEBAR.
  36889. * @param {number} [duration=50] - The duration within which the key is considered as being just released. Given in ms.
  36890. * @return {boolean} True if the key was released within the given duration, false if not or null if the Key wasn't found.
  36891. */
  36892. upDuration: function (keycode, duration) {
  36893. if (this._keys[keycode])
  36894. {
  36895. return this._keys[keycode].upDuration(duration);
  36896. }
  36897. else
  36898. {
  36899. return null;
  36900. }
  36901. },
  36902. justPressed: function (keycode) {
  36903. if (this._keys[keycode])
  36904. {
  36905. return this._keys[keycode].justPressed();
  36906. }
  36907. else
  36908. {
  36909. return null;
  36910. }
  36911. },
  36912. justReleased: function (keycode) {
  36913. if (this._keys[keycode])
  36914. {
  36915. return this._keys[keycode].justReleased();
  36916. }
  36917. else
  36918. {
  36919. return null;
  36920. }
  36921. },
  36922. /**
  36923. * Returns true of the key is currently pressed down. Note that it can only detect key presses on the web browser.
  36924. *
  36925. * @method Phaser.Keyboard#isDown
  36926. * @param {integer} keycode - The {@link Phaser.KeyCode keycode} of the key to check: i.e. Phaser.KeyCode.UP or Phaser.KeyCode.SPACEBAR.
  36927. * @return {boolean} True if the key is currently down, false if not or null if the Key wasn't found.
  36928. */
  36929. isDown: function (keycode) {
  36930. if (this._keys[keycode])
  36931. {
  36932. return this._keys[keycode].isDown;
  36933. }
  36934. else
  36935. {
  36936. return null;
  36937. }
  36938. }
  36939. };
  36940. /**
  36941. * Returns the string value of the most recently pressed key.
  36942. * @name Phaser.Keyboard#lastChar
  36943. * @property {string} lastChar - The string value of the most recently pressed key.
  36944. * @readonly
  36945. */
  36946. Object.defineProperty(Phaser.Keyboard.prototype, "lastChar", {
  36947. get: function () {
  36948. if (this.event && this.event.charCode === 32)
  36949. {
  36950. return '';
  36951. }
  36952. else if (this.pressEvent)
  36953. {
  36954. return String.fromCharCode(this.pressEvent.charCode);
  36955. }
  36956. else
  36957. {
  36958. return null;
  36959. }
  36960. }
  36961. });
  36962. /**
  36963. * Returns the most recently pressed Key. This is a Phaser.Key object and it changes every time a key is pressed.
  36964. * @name Phaser.Keyboard#lastKey
  36965. * @property {Phaser.Key} lastKey - The most recently pressed Key.
  36966. * @readonly
  36967. */
  36968. Object.defineProperty(Phaser.Keyboard.prototype, "lastKey", {
  36969. get: function () {
  36970. return this._keys[this._k];
  36971. }
  36972. });
  36973. Phaser.Keyboard.prototype.constructor = Phaser.Keyboard;
  36974. /**
  36975. * A key code represents a physical key on a keyboard.
  36976. *
  36977. * The KeyCode class contains commonly supported keyboard key codes which can be used
  36978. * as keycode`-parameters in several {@link Phaser.Keyboard} and {@link Phaser.Key} methods.
  36979. *
  36980. * _Note_: These values should only be used indirectly, eg. as `Phaser.KeyCode.KEY`.
  36981. * Future versions may replace the actual values, such that they remain compatible with `keycode`-parameters.
  36982. * The current implementation maps to the {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode KeyboardEvent.keyCode} property.
  36983. *
  36984. * _Note_: Use `Phaser.KeyCode.KEY` instead of `Phaser.Keyboard.KEY` to refer to a key code;
  36985. * the latter approach is supported for compatibility.
  36986. *
  36987. * @class Phaser.KeyCode
  36988. */
  36989. Phaser.KeyCode = {
  36990. /** @static */
  36991. A: "A".charCodeAt(0),
  36992. /** @static */
  36993. B: "B".charCodeAt(0),
  36994. /** @static */
  36995. C: "C".charCodeAt(0),
  36996. /** @static */
  36997. D: "D".charCodeAt(0),
  36998. /** @static */
  36999. E: "E".charCodeAt(0),
  37000. /** @static */
  37001. F: "F".charCodeAt(0),
  37002. /** @static */
  37003. G: "G".charCodeAt(0),
  37004. /** @static */
  37005. H: "H".charCodeAt(0),
  37006. /** @static */
  37007. I: "I".charCodeAt(0),
  37008. /** @static */
  37009. J: "J".charCodeAt(0),
  37010. /** @static */
  37011. K: "K".charCodeAt(0),
  37012. /** @static */
  37013. L: "L".charCodeAt(0),
  37014. /** @static */
  37015. M: "M".charCodeAt(0),
  37016. /** @static */
  37017. N: "N".charCodeAt(0),
  37018. /** @static */
  37019. O: "O".charCodeAt(0),
  37020. /** @static */
  37021. P: "P".charCodeAt(0),
  37022. /** @static */
  37023. Q: "Q".charCodeAt(0),
  37024. /** @static */
  37025. R: "R".charCodeAt(0),
  37026. /** @static */
  37027. S: "S".charCodeAt(0),
  37028. /** @static */
  37029. T: "T".charCodeAt(0),
  37030. /** @static */
  37031. U: "U".charCodeAt(0),
  37032. /** @static */
  37033. V: "V".charCodeAt(0),
  37034. /** @static */
  37035. W: "W".charCodeAt(0),
  37036. /** @static */
  37037. X: "X".charCodeAt(0),
  37038. /** @static */
  37039. Y: "Y".charCodeAt(0),
  37040. /** @static */
  37041. Z: "Z".charCodeAt(0),
  37042. /** @static */
  37043. ZERO: "0".charCodeAt(0),
  37044. /** @static */
  37045. ONE: "1".charCodeAt(0),
  37046. /** @static */
  37047. TWO: "2".charCodeAt(0),
  37048. /** @static */
  37049. THREE: "3".charCodeAt(0),
  37050. /** @static */
  37051. FOUR: "4".charCodeAt(0),
  37052. /** @static */
  37053. FIVE: "5".charCodeAt(0),
  37054. /** @static */
  37055. SIX: "6".charCodeAt(0),
  37056. /** @static */
  37057. SEVEN: "7".charCodeAt(0),
  37058. /** @static */
  37059. EIGHT: "8".charCodeAt(0),
  37060. /** @static */
  37061. NINE: "9".charCodeAt(0),
  37062. /** @static */
  37063. NUMPAD_0: 96,
  37064. /** @static */
  37065. NUMPAD_1: 97,
  37066. /** @static */
  37067. NUMPAD_2: 98,
  37068. /** @static */
  37069. NUMPAD_3: 99,
  37070. /** @static */
  37071. NUMPAD_4: 100,
  37072. /** @static */
  37073. NUMPAD_5: 101,
  37074. /** @static */
  37075. NUMPAD_6: 102,
  37076. /** @static */
  37077. NUMPAD_7: 103,
  37078. /** @static */
  37079. NUMPAD_8: 104,
  37080. /** @static */
  37081. NUMPAD_9: 105,
  37082. /** @static */
  37083. NUMPAD_MULTIPLY: 106,
  37084. /** @static */
  37085. NUMPAD_ADD: 107,
  37086. /** @static */
  37087. NUMPAD_ENTER: 108,
  37088. /** @static */
  37089. NUMPAD_SUBTRACT: 109,
  37090. /** @static */
  37091. NUMPAD_DECIMAL: 110,
  37092. /** @static */
  37093. NUMPAD_DIVIDE: 111,
  37094. /** @static */
  37095. F1: 112,
  37096. /** @static */
  37097. F2: 113,
  37098. /** @static */
  37099. F3: 114,
  37100. /** @static */
  37101. F4: 115,
  37102. /** @static */
  37103. F5: 116,
  37104. /** @static */
  37105. F6: 117,
  37106. /** @static */
  37107. F7: 118,
  37108. /** @static */
  37109. F8: 119,
  37110. /** @static */
  37111. F9: 120,
  37112. /** @static */
  37113. F10: 121,
  37114. /** @static */
  37115. F11: 122,
  37116. /** @static */
  37117. F12: 123,
  37118. /** @static */
  37119. F13: 124,
  37120. /** @static */
  37121. F14: 125,
  37122. /** @static */
  37123. F15: 126,
  37124. /** @static */
  37125. COLON: 186,
  37126. /** @static */
  37127. EQUALS: 187,
  37128. /** @static */
  37129. COMMA: 188,
  37130. /** @static */
  37131. UNDERSCORE: 189,
  37132. /** @static */
  37133. PERIOD: 190,
  37134. /** @static */
  37135. QUESTION_MARK: 191,
  37136. /** @static */
  37137. TILDE: 192,
  37138. /** @static */
  37139. OPEN_BRACKET: 219,
  37140. /** @static */
  37141. BACKWARD_SLASH: 220,
  37142. /** @static */
  37143. CLOSED_BRACKET: 221,
  37144. /** @static */
  37145. QUOTES: 222,
  37146. /** @static */
  37147. BACKSPACE: 8,
  37148. /** @static */
  37149. TAB: 9,
  37150. /** @static */
  37151. CLEAR: 12,
  37152. /** @static */
  37153. ENTER: 13,
  37154. /** @static */
  37155. SHIFT: 16,
  37156. /** @static */
  37157. CONTROL: 17,
  37158. /** @static */
  37159. ALT: 18,
  37160. /** @static */
  37161. CAPS_LOCK: 20,
  37162. /** @static */
  37163. ESC: 27,
  37164. /** @static */
  37165. SPACEBAR: 32,
  37166. /** @static */
  37167. PAGE_UP: 33,
  37168. /** @static */
  37169. PAGE_DOWN: 34,
  37170. /** @static */
  37171. END: 35,
  37172. /** @static */
  37173. HOME: 36,
  37174. /** @static */
  37175. LEFT: 37,
  37176. /** @static */
  37177. UP: 38,
  37178. /** @static */
  37179. RIGHT: 39,
  37180. /** @static */
  37181. DOWN: 40,
  37182. /** @static */
  37183. PLUS: 43,
  37184. /** @static */
  37185. MINUS: 44,
  37186. /** @static */
  37187. INSERT: 45,
  37188. /** @static */
  37189. DELETE: 46,
  37190. /** @static */
  37191. HELP: 47,
  37192. /** @static */
  37193. NUM_LOCK: 144
  37194. };
  37195. // Duplicate Phaser.KeyCode values in Phaser.Keyboard for compatibility
  37196. for (var key in Phaser.KeyCode)
  37197. {
  37198. if (Phaser.KeyCode.hasOwnProperty(key) && !key.match(/[a-z]/))
  37199. {
  37200. Phaser.Keyboard[key] = Phaser.KeyCode[key];
  37201. }
  37202. }
  37203. /**
  37204. * @author Richard Davey <rich@photonstorm.com>
  37205. * @copyright 2016 Photon Storm Ltd.
  37206. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  37207. */
  37208. Phaser.Component = function () {};
  37209. /**
  37210. * @author Richard Davey <rich@photonstorm.com>
  37211. * @copyright 2016 Photon Storm Ltd.
  37212. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  37213. */
  37214. /**
  37215. * The Angle Component provides access to an `angle` property; the rotation of a Game Object in degrees.
  37216. *
  37217. * @class
  37218. */
  37219. Phaser.Component.Angle = function () {};
  37220. Phaser.Component.Angle.prototype = {
  37221. /**
  37222. * The angle property is the rotation of the Game Object in *degrees* from its original orientation.
  37223. *
  37224. * Values from 0 to 180 represent clockwise rotation; values from 0 to -180 represent counterclockwise rotation.
  37225. *
  37226. * Values outside this range are added to or subtracted from 360 to obtain a value within the range.
  37227. * For example, the statement player.angle = 450 is the same as player.angle = 90.
  37228. *
  37229. * If you wish to work in radians instead of degrees you can use the property `rotation` instead.
  37230. * Working in radians is slightly faster as it doesn't have to perform any calculations.
  37231. *
  37232. * @property {number} angle
  37233. */
  37234. angle: {
  37235. get: function() {
  37236. return Phaser.Math.wrapAngle(Phaser.Math.radToDeg(this.rotation));
  37237. },
  37238. set: function(value) {
  37239. this.rotation = Phaser.Math.degToRad(Phaser.Math.wrapAngle(value));
  37240. }
  37241. }
  37242. };
  37243. /**
  37244. * @author Richard Davey <rich@photonstorm.com>
  37245. * @copyright 2016 Photon Storm Ltd.
  37246. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  37247. */
  37248. /**
  37249. * The Animation Component provides a `play` method, which is a proxy to the `AnimationManager.play` method.
  37250. *
  37251. * @class
  37252. */
  37253. Phaser.Component.Animation = function () {};
  37254. Phaser.Component.Animation.prototype = {
  37255. /**
  37256. * Plays an Animation.
  37257. *
  37258. * The animation should have previously been created via `animations.add`.
  37259. *
  37260. * If the animation is already playing calling this again won't do anything.
  37261. * If you need to reset an already running animation do so directly on the Animation object itself or via `AnimationManager.stop`.
  37262. *
  37263. * @method
  37264. * @param {string} name - The name of the animation to be played, e.g. "fire", "walk", "jump". Must have been previously created via 'AnimationManager.add'.
  37265. * @param {number} [frameRate=null] - The framerate to play the animation at. The speed is given in frames per second. If not provided the previously set frameRate of the Animation is used.
  37266. * @param {boolean} [loop=false] - Should the animation be looped after playback. If not provided the previously set loop value of the Animation is used.
  37267. * @param {boolean} [killOnComplete=false] - If set to true when the animation completes (only happens if loop=false) the parent Sprite will be killed.
  37268. * @return {Phaser.Animation} A reference to playing Animation.
  37269. */
  37270. play: function (name, frameRate, loop, killOnComplete) {
  37271. if (this.animations)
  37272. {
  37273. return this.animations.play(name, frameRate, loop, killOnComplete);
  37274. }
  37275. }
  37276. };
  37277. /**
  37278. * @author Richard Davey <rich@photonstorm.com>
  37279. * @copyright 2016 Photon Storm Ltd.
  37280. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  37281. */
  37282. /**
  37283. * The AutoCull Component is responsible for providing methods that check if a Game Object is within the bounds of the World Camera.
  37284. * It is used by the InWorld component.
  37285. *
  37286. * @class
  37287. */
  37288. Phaser.Component.AutoCull = function () {};
  37289. Phaser.Component.AutoCull.prototype = {
  37290. /**
  37291. * A Game Object with `autoCull` set to true will check its bounds against the World Camera every frame.
  37292. * If it is not intersecting the Camera bounds at any point then it has its `renderable` property set to `false`.
  37293. * This keeps the Game Object alive and still processing updates, but forces it to skip the render step entirely.
  37294. *
  37295. * This is a relatively expensive operation, especially if enabled on hundreds of Game Objects. So enable it only if you know it's required,
  37296. * or you have tested performance and find it acceptable.
  37297. *
  37298. * @property {boolean} autoCull
  37299. * @default
  37300. */
  37301. autoCull: false,
  37302. /**
  37303. * Checks if the Game Objects bounds intersect with the Game Camera bounds.
  37304. * Returns `true` if they do, otherwise `false` if fully outside of the Cameras bounds.
  37305. *
  37306. * @property {boolean} inCamera
  37307. * @readonly
  37308. */
  37309. inCamera: {
  37310. get: function() {
  37311. if (!this.autoCull && !this.checkWorldBounds)
  37312. {
  37313. this._bounds.copyFrom(this.getBounds());
  37314. this._bounds.x += this.game.camera.view.x;
  37315. this._bounds.y += this.game.camera.view.y;
  37316. }
  37317. return this.game.world.camera.view.intersects(this._bounds);
  37318. }
  37319. }
  37320. };
  37321. /**
  37322. * @author Richard Davey <rich@photonstorm.com>
  37323. * @copyright 2016 Photon Storm Ltd.
  37324. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  37325. */
  37326. /**
  37327. * The Bounds component contains properties related to the bounds of the Game Object.
  37328. *
  37329. * @class
  37330. */
  37331. Phaser.Component.Bounds = function () {};
  37332. Phaser.Component.Bounds.prototype = {
  37333. /**
  37334. * The amount the Game Object is visually offset from its x coordinate.
  37335. * This is the same as `width * anchor.x`.
  37336. * It will only be > 0 if anchor.x is not equal to zero.
  37337. *
  37338. * @property {number} offsetX
  37339. * @readOnly
  37340. */
  37341. offsetX: {
  37342. get: function () {
  37343. return this.anchor.x * this.width;
  37344. }
  37345. },
  37346. /**
  37347. * The amount the Game Object is visually offset from its y coordinate.
  37348. * This is the same as `height * anchor.y`.
  37349. * It will only be > 0 if anchor.y is not equal to zero.
  37350. *
  37351. * @property {number} offsetY
  37352. * @readOnly
  37353. */
  37354. offsetY: {
  37355. get: function () {
  37356. return this.anchor.y * this.height;
  37357. }
  37358. },
  37359. /**
  37360. * The center x coordinate of the Game Object.
  37361. * This is the same as `(x - offsetX) + (width / 2)`.
  37362. *
  37363. * @property {number} centerX
  37364. */
  37365. centerX: {
  37366. get: function () {
  37367. return (this.x - this.offsetX) + (this.width * 0.5);
  37368. },
  37369. set: function (value) {
  37370. this.x = (value + this.offsetX) - (this.width * 0.5);
  37371. }
  37372. },
  37373. /**
  37374. * The center y coordinate of the Game Object.
  37375. * This is the same as `(y - offsetY) + (height / 2)`.
  37376. *
  37377. * @property {number} centerY
  37378. */
  37379. centerY: {
  37380. get: function () {
  37381. return (this.y - this.offsetY) + (this.height * 0.5);
  37382. },
  37383. set: function (value) {
  37384. this.y = (value + this.offsetY) - (this.height * 0.5);
  37385. }
  37386. },
  37387. /**
  37388. * The left coordinate of the Game Object.
  37389. * This is the same as `x - offsetX`.
  37390. *
  37391. * @property {number} left
  37392. */
  37393. left: {
  37394. get: function () {
  37395. return this.x - this.offsetX;
  37396. },
  37397. set: function (value) {
  37398. this.x = value + this.offsetX;
  37399. }
  37400. },
  37401. /**
  37402. * The right coordinate of the Game Object.
  37403. * This is the same as `x + width - offsetX`.
  37404. *
  37405. * @property {number} right
  37406. */
  37407. right: {
  37408. get: function () {
  37409. return (this.x + this.width) - this.offsetX;
  37410. },
  37411. set: function (value) {
  37412. this.x = value - (this.width) + this.offsetX;
  37413. }
  37414. },
  37415. /**
  37416. * The y coordinate of the Game Object.
  37417. * This is the same as `y - offsetY`.
  37418. *
  37419. * @property {number} top
  37420. */
  37421. top: {
  37422. get: function () {
  37423. return this.y - this.offsetY;
  37424. },
  37425. set: function (value) {
  37426. this.y = value + this.offsetY;
  37427. }
  37428. },
  37429. /**
  37430. * The sum of the y and height properties.
  37431. * This is the same as `y + height - offsetY`.
  37432. *
  37433. * @property {number} bottom
  37434. */
  37435. bottom: {
  37436. get: function () {
  37437. return (this.y + this.height) - this.offsetY;
  37438. },
  37439. set: function (value) {
  37440. this.y = value - (this.height) + this.offsetY;
  37441. }
  37442. },
  37443. /**
  37444. * Aligns this Game Object within another Game Object, or Rectangle, known as the
  37445. * 'container', to one of 9 possible positions.
  37446. *
  37447. * The container must be a Game Object, or Phaser.Rectangle object. This can include properties
  37448. * such as `World.bounds` or `Camera.view`, for aligning Game Objects within the world
  37449. * and camera bounds. Or it can include other Sprites, Images, Text objects, BitmapText,
  37450. * TileSprites or Buttons.
  37451. *
  37452. * Please note that aligning a Sprite to another Game Object does **not** make it a child of
  37453. * the container. It simply modifies its position coordinates so it aligns with it.
  37454. *
  37455. * The position constants you can use are:
  37456. *
  37457. * `Phaser.TOP_LEFT`, `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`,
  37458. * `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`,
  37459. * `Phaser.BOTTOM_CENTER` and `Phaser.BOTTOM_RIGHT`.
  37460. *
  37461. * The Game Objects are placed in such a way that their _bounds_ align with the
  37462. * container, taking into consideration rotation, scale and the anchor property.
  37463. * This allows you to neatly align Game Objects, irrespective of their position value.
  37464. *
  37465. * The optional `offsetX` and `offsetY` arguments allow you to apply extra spacing to the final
  37466. * aligned position of the Game Object. For example:
  37467. *
  37468. * `sprite.alignIn(background, Phaser.BOTTOM_RIGHT, -20, -20)`
  37469. *
  37470. * Would align the `sprite` to the bottom-right, but moved 20 pixels in from the corner.
  37471. * Think of the offsets as applying an adjustment to the containers bounds before the alignment takes place.
  37472. * So providing a negative offset will 'shrink' the container bounds by that amount, and providing a positive
  37473. * one expands it.
  37474. *
  37475. * @method
  37476. * @param {Phaser.Rectangle|Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Button|Phaser.Graphics|Phaser.TileSprite} container - The Game Object or Rectangle with which to align this Game Object to. Can also include properties such as `World.bounds` or `Camera.view`.
  37477. * @param {integer} [position] - The position constant. One of `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`, `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`.
  37478. * @param {integer} [offsetX=0] - A horizontal adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  37479. * @param {integer} [offsetY=0] - A vertical adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  37480. * @return {Object} This Game Object.
  37481. */
  37482. alignIn: function (container, position, offsetX, offsetY) {
  37483. if (offsetX === undefined) { offsetX = 0; }
  37484. if (offsetY === undefined) { offsetY = 0; }
  37485. switch (position)
  37486. {
  37487. default:
  37488. case Phaser.TOP_LEFT:
  37489. this.left = container.left - offsetX;
  37490. this.top = container.top - offsetY;
  37491. break;
  37492. case Phaser.TOP_CENTER:
  37493. this.centerX = container.centerX + offsetX;
  37494. this.top = container.top - offsetY;
  37495. break;
  37496. case Phaser.TOP_RIGHT:
  37497. this.right = container.right + offsetX;
  37498. this.top = container.top - offsetY;
  37499. break;
  37500. case Phaser.LEFT_CENTER:
  37501. this.left = container.left - offsetX;
  37502. this.centerY = container.centerY + offsetY;
  37503. break;
  37504. case Phaser.CENTER:
  37505. this.centerX = container.centerX + offsetX;
  37506. this.centerY = container.centerY + offsetY;
  37507. break;
  37508. case Phaser.RIGHT_CENTER:
  37509. this.right = container.right + offsetX;
  37510. this.centerY = container.centerY + offsetY;
  37511. break;
  37512. case Phaser.BOTTOM_LEFT:
  37513. this.left = container.left - offsetX;
  37514. this.bottom = container.bottom + offsetY;
  37515. break;
  37516. case Phaser.BOTTOM_CENTER:
  37517. this.centerX = container.centerX + offsetX;
  37518. this.bottom = container.bottom + offsetY;
  37519. break;
  37520. case Phaser.BOTTOM_RIGHT:
  37521. this.right = container.right + offsetX;
  37522. this.bottom = container.bottom + offsetY;
  37523. break;
  37524. }
  37525. return this;
  37526. },
  37527. /**
  37528. * Aligns this Game Object to the side of another Game Object, or Rectangle, known as the
  37529. * 'parent', in one of 11 possible positions.
  37530. *
  37531. * The parent must be a Game Object, or Phaser.Rectangle object. This can include properties
  37532. * such as `World.bounds` or `Camera.view`, for aligning Game Objects within the world
  37533. * and camera bounds. Or it can include other Sprites, Images, Text objects, BitmapText,
  37534. * TileSprites or Buttons.
  37535. *
  37536. * Please note that aligning a Sprite to another Game Object does **not** make it a child of
  37537. * the parent. It simply modifies its position coordinates so it aligns with it.
  37538. *
  37539. * The position constants you can use are:
  37540. *
  37541. * `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_TOP`,
  37542. * `Phaser.LEFT_CENTER`, `Phaser.LEFT_BOTTOM`, `Phaser.RIGHT_TOP`, `Phaser.RIGHT_CENTER`,
  37543. * `Phaser.RIGHT_BOTTOM`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER`
  37544. * and `Phaser.BOTTOM_RIGHT`.
  37545. *
  37546. * The Game Objects are placed in such a way that their _bounds_ align with the
  37547. * parent, taking into consideration rotation, scale and the anchor property.
  37548. * This allows you to neatly align Game Objects, irrespective of their position value.
  37549. *
  37550. * The optional `offsetX` and `offsetY` arguments allow you to apply extra spacing to the final
  37551. * aligned position of the Game Object. For example:
  37552. *
  37553. * `sprite.alignTo(background, Phaser.BOTTOM_RIGHT, -20, -20)`
  37554. *
  37555. * Would align the `sprite` to the bottom-right, but moved 20 pixels in from the corner.
  37556. * Think of the offsets as applying an adjustment to the parents bounds before the alignment takes place.
  37557. * So providing a negative offset will 'shrink' the parent bounds by that amount, and providing a positive
  37558. * one expands it.
  37559. *
  37560. * @method
  37561. * @param {Phaser.Rectangle|Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Button|Phaser.Graphics|Phaser.TileSprite} parent - The Game Object or Rectangle with which to align this Game Object to. Can also include properties such as `World.bounds` or `Camera.view`.
  37562. * @param {integer} [position] - The position constant. One of `Phaser.TOP_LEFT`, `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_TOP`, `Phaser.LEFT_CENTER`, `Phaser.LEFT_BOTTOM`, `Phaser.RIGHT_TOP`, `Phaser.RIGHT_CENTER`, `Phaser.RIGHT_BOTTOM`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`.
  37563. * @param {integer} [offsetX=0] - A horizontal adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  37564. * @param {integer} [offsetY=0] - A vertical adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it.
  37565. * @return {Object} This Game Object.
  37566. */
  37567. alignTo: function (parent, position, offsetX, offsetY) {
  37568. if (offsetX === undefined) { offsetX = 0; }
  37569. if (offsetY === undefined) { offsetY = 0; }
  37570. switch (position)
  37571. {
  37572. default:
  37573. case Phaser.TOP_LEFT:
  37574. this.left = parent.left - offsetX;
  37575. this.bottom = parent.top - offsetY;
  37576. break;
  37577. case Phaser.TOP_CENTER:
  37578. this.centerX = parent.centerX + offsetX;
  37579. this.bottom = parent.top - offsetY;
  37580. break;
  37581. case Phaser.TOP_RIGHT:
  37582. this.right = parent.right + offsetX;
  37583. this.bottom = parent.top - offsetY;
  37584. break;
  37585. case Phaser.LEFT_TOP:
  37586. this.right = parent.left - offsetX;
  37587. this.top = parent.top - offsetY;
  37588. break;
  37589. case Phaser.LEFT_CENTER:
  37590. this.right = parent.left - offsetX;
  37591. this.centerY = parent.centerY + offsetY;
  37592. break;
  37593. case Phaser.LEFT_BOTTOM:
  37594. this.right = parent.left - offsetX;
  37595. this.bottom = parent.bottom + offsetY;
  37596. break;
  37597. case Phaser.RIGHT_TOP:
  37598. this.left = parent.right + offsetX;
  37599. this.top = parent.top - offsetY;
  37600. break;
  37601. case Phaser.RIGHT_CENTER:
  37602. this.left = parent.right + offsetX;
  37603. this.centerY = parent.centerY + offsetY;
  37604. break;
  37605. case Phaser.RIGHT_BOTTOM:
  37606. this.left = parent.right + offsetX;
  37607. this.bottom = parent.bottom + offsetY;
  37608. break;
  37609. case Phaser.BOTTOM_LEFT:
  37610. this.left = parent.left - offsetX;
  37611. this.top = parent.bottom + offsetY;
  37612. break;
  37613. case Phaser.BOTTOM_CENTER:
  37614. this.centerX = parent.centerX + offsetX;
  37615. this.top = parent.bottom + offsetY;
  37616. break;
  37617. case Phaser.BOTTOM_RIGHT:
  37618. this.right = parent.right + offsetX;
  37619. this.top = parent.bottom + offsetY;
  37620. break;
  37621. }
  37622. return this;
  37623. }
  37624. };
  37625. // Phaser.Group extensions
  37626. Phaser.Group.prototype.alignIn = Phaser.Component.Bounds.prototype.alignIn;
  37627. Phaser.Group.prototype.alignTo = Phaser.Component.Bounds.prototype.alignTo;
  37628. /**
  37629. * @author Richard Davey <rich@photonstorm.com>
  37630. * @copyright 2016 Photon Storm Ltd.
  37631. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  37632. */
  37633. /**
  37634. * The BringToTop Component features quick access to Group sorting related methods.
  37635. *
  37636. * @class
  37637. */
  37638. Phaser.Component.BringToTop = function () {};
  37639. /**
  37640. * Brings this Game Object to the top of its parents display list.
  37641. * Visually this means it will render over the top of any old child in the same Group.
  37642. *
  37643. * If this Game Object hasn't been added to a custom Group then this method will bring it to the top of the Game World,
  37644. * because the World is the root Group from which all Game Objects descend.
  37645. *
  37646. * @method
  37647. * @return {PIXI.DisplayObject} This instance.
  37648. */
  37649. Phaser.Component.BringToTop.prototype.bringToTop = function() {
  37650. if (this.parent)
  37651. {
  37652. this.parent.bringToTop(this);
  37653. }
  37654. return this;
  37655. };
  37656. /**
  37657. * Sends this Game Object to the bottom of its parents display list.
  37658. * Visually this means it will render below all other children in the same Group.
  37659. *
  37660. * If this Game Object hasn't been added to a custom Group then this method will send it to the bottom of the Game World,
  37661. * because the World is the root Group from which all Game Objects descend.
  37662. *
  37663. * @method
  37664. * @return {PIXI.DisplayObject} This instance.
  37665. */
  37666. Phaser.Component.BringToTop.prototype.sendToBack = function() {
  37667. if (this.parent)
  37668. {
  37669. this.parent.sendToBack(this);
  37670. }
  37671. return this;
  37672. };
  37673. /**
  37674. * Moves this Game Object up one place in its parents display list.
  37675. * This call has no effect if the Game Object is already at the top of the display list.
  37676. *
  37677. * If this Game Object hasn't been added to a custom Group then this method will move it one object up within the Game World,
  37678. * because the World is the root Group from which all Game Objects descend.
  37679. *
  37680. * @method
  37681. * @return {PIXI.DisplayObject} This instance.
  37682. */
  37683. Phaser.Component.BringToTop.prototype.moveUp = function () {
  37684. if (this.parent)
  37685. {
  37686. this.parent.moveUp(this);
  37687. }
  37688. return this;
  37689. };
  37690. /**
  37691. * Moves this Game Object down one place in its parents display list.
  37692. * This call has no effect if the Game Object is already at the bottom of the display list.
  37693. *
  37694. * If this Game Object hasn't been added to a custom Group then this method will move it one object down within the Game World,
  37695. * because the World is the root Group from which all Game Objects descend.
  37696. *
  37697. * @method
  37698. * @return {PIXI.DisplayObject} This instance.
  37699. */
  37700. Phaser.Component.BringToTop.prototype.moveDown = function () {
  37701. if (this.parent)
  37702. {
  37703. this.parent.moveDown(this);
  37704. }
  37705. return this;
  37706. };
  37707. /**
  37708. * @author Richard Davey <rich@photonstorm.com>
  37709. * @copyright 2016 Photon Storm Ltd.
  37710. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  37711. */
  37712. /**
  37713. * Core Component Features.
  37714. *
  37715. * @class
  37716. */
  37717. Phaser.Component.Core = function () {};
  37718. /**
  37719. * @property {boolean} skipTypeChecks - Skip type checks in {@link #init}.
  37720. * @static
  37721. * @default
  37722. */
  37723. Phaser.Component.Core.skipTypeChecks = false;
  37724. /**
  37725. * Installs / registers mixin components.
  37726. *
  37727. * The `this` context should be that of the applicable object instance or prototype.
  37728. *
  37729. * @method
  37730. * @protected
  37731. */
  37732. Phaser.Component.Core.install = function (components) {
  37733. // Always install 'Core' first
  37734. Phaser.Utils.mixinPrototype(this, Phaser.Component.Core.prototype);
  37735. this.components = {};
  37736. for (var i = 0; i < components.length; i++)
  37737. {
  37738. var id = components[i];
  37739. var replace = false;
  37740. if (id === 'Destroy')
  37741. {
  37742. replace = true;
  37743. }
  37744. Phaser.Utils.mixinPrototype(this, Phaser.Component[id].prototype, replace);
  37745. this.components[id] = true;
  37746. }
  37747. };
  37748. /**
  37749. * Initializes the mixin components.
  37750. *
  37751. * The `this` context should be an instance of the component mixin target.
  37752. *
  37753. * @method
  37754. * @protected
  37755. */
  37756. Phaser.Component.Core.init = function (game, x, y, key, frame) {
  37757. if (!Phaser.Component.Core.skipTypeChecks)
  37758. {
  37759. if (!(game instanceof Phaser.Game))
  37760. {
  37761. throw new Error('The value passed as the `game` argument (' + game + ') is not an instance of Phaser.Game.');
  37762. }
  37763. if (typeof x !== 'number')
  37764. {
  37765. console.warn('The `x` argument value (%s) should be a number.', x);
  37766. x = 0; // This would be done implicitly in position.set().
  37767. }
  37768. if (typeof y !== 'number')
  37769. {
  37770. console.warn('The `y` argument value (%s) should be a number.', y);
  37771. y = 0; // This would be done implicitly in position.set().
  37772. }
  37773. }
  37774. this.game = game;
  37775. this.key = key;
  37776. this.data = {};
  37777. this.position.set(x, y);
  37778. this.world = new Phaser.Point(x, y);
  37779. this.previousPosition = new Phaser.Point(x, y);
  37780. this.events = new Phaser.Events(this);
  37781. this._bounds = new Phaser.Rectangle();
  37782. if (this.components.PhysicsBody)
  37783. {
  37784. // Enable-body checks for hasOwnProperty; makes sure to lift property from prototype.
  37785. this.body = this.body;
  37786. }
  37787. if (this.components.Animation)
  37788. {
  37789. this.animations = new Phaser.AnimationManager(this);
  37790. }
  37791. if (this.components.LoadTexture && key !== null)
  37792. {
  37793. this.loadTexture(key, frame);
  37794. }
  37795. if (this.components.FixedToCamera)
  37796. {
  37797. this.cameraOffset = new Phaser.Point(x, y);
  37798. }
  37799. };
  37800. Phaser.Component.Core.preUpdate = function () {
  37801. if (this.pendingDestroy)
  37802. {
  37803. this.destroy();
  37804. return;
  37805. }
  37806. this.previousPosition.set(this.world.x, this.world.y);
  37807. this.previousRotation = this.rotation;
  37808. if (!this.exists || !this.parent.exists)
  37809. {
  37810. this.renderOrderID = -1;
  37811. return false;
  37812. }
  37813. this.world.setTo(this.game.camera.x + this.worldTransform.tx, this.game.camera.y + this.worldTransform.ty);
  37814. if (this.visible)
  37815. {
  37816. this.renderOrderID = this.game.stage.currentRenderOrderID++;
  37817. }
  37818. if (this.animations)
  37819. {
  37820. this.animations.update();
  37821. }
  37822. if (this.body)
  37823. {
  37824. this.body.preUpdate();
  37825. }
  37826. this.preUpdateChildren();
  37827. return true;
  37828. };
  37829. Phaser.Component.Core.prototype = {
  37830. /**
  37831. * A reference to the currently running Game.
  37832. * @property {Phaser.Game} game
  37833. */
  37834. game: null,
  37835. /**
  37836. * A user defined name given to this Game Object.
  37837. * This value isn't ever used internally by Phaser, it is meant as a game level property.
  37838. * @property {string} name
  37839. * @default
  37840. */
  37841. name: '',
  37842. /**
  37843. * An empty Object that belongs to this Game Object.
  37844. * This value isn't ever used internally by Phaser, but may be used by your own code, or
  37845. * by Phaser Plugins, to store data that needs to be associated with the Game Object,
  37846. * without polluting the Game Object directly.
  37847. * @property {Object} data
  37848. * @default
  37849. */
  37850. data: {},
  37851. /**
  37852. * The components this Game Object has installed.
  37853. * @property {object} components
  37854. * @protected
  37855. */
  37856. components: {},
  37857. /**
  37858. * The z depth of this Game Object within its parent Group.
  37859. * No two objects in a Group can have the same z value.
  37860. * This value is adjusted automatically whenever the Group hierarchy changes.
  37861. * If you wish to re-order the layering of a Game Object then see methods like Group.moveUp or Group.bringToTop.
  37862. * @property {number} z
  37863. * @readOnly
  37864. */
  37865. z: 0,
  37866. /**
  37867. * All Phaser Game Objects have an Events class which contains all of the events that are dispatched when certain things happen to this
  37868. * Game Object, or any of its components.
  37869. * @see Phaser.Events
  37870. * @property {Phaser.Events} events
  37871. */
  37872. events: undefined,
  37873. /**
  37874. * If the Game Object is enabled for animation (such as a Phaser.Sprite) this is a reference to its AnimationManager instance.
  37875. * Through it you can create, play, pause and stop animations.
  37876. * @see Phaser.AnimationManager
  37877. * @property {Phaser.AnimationManager} animations
  37878. */
  37879. animations: undefined,
  37880. /**
  37881. * The key of the image or texture used by this Game Object during rendering.
  37882. * If it is a string it's the string used to retrieve the texture from the Phaser Image Cache.
  37883. * It can also be an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  37884. * If a Game Object is created without a key it is automatically assigned the key `__default` which is a 32x32 transparent PNG stored within the Cache.
  37885. * If a Game Object is given a key which doesn't exist in the Image Cache it is re-assigned the key `__missing` which is a 32x32 PNG of a green box with a line through it.
  37886. * @property {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} key
  37887. */
  37888. key: '',
  37889. /**
  37890. * The world coordinates of this Game Object in pixels.
  37891. * Depending on where in the display list this Game Object is placed this value can differ from `position`,
  37892. * which contains the x/y coordinates relative to the Game Objects parent.
  37893. * @property {Phaser.Point} world
  37894. */
  37895. world: null,
  37896. /**
  37897. * A debug flag designed for use with `Game.enableStep`.
  37898. * @property {boolean} debug
  37899. * @default
  37900. */
  37901. debug: false,
  37902. /**
  37903. * The position the Game Object was located in the previous frame.
  37904. * @property {Phaser.Point} previousPosition
  37905. * @readOnly
  37906. */
  37907. previousPosition: null,
  37908. /**
  37909. * The rotation the Game Object was in set to in the previous frame. Value is in radians.
  37910. * @property {number} previousRotation
  37911. * @readOnly
  37912. */
  37913. previousRotation: 0,
  37914. /**
  37915. * The render order ID is used internally by the renderer and Input Manager and should not be modified.
  37916. * This property is mostly used internally by the renderers, but is exposed for the use of plugins.
  37917. * @property {number} renderOrderID
  37918. * @readOnly
  37919. */
  37920. renderOrderID: 0,
  37921. /**
  37922. * A Game Object is considered `fresh` if it has just been created or reset and is yet to receive a renderer transform update.
  37923. * This property is mostly used internally by the physics systems, but is exposed for the use of plugins.
  37924. * @property {boolean} fresh
  37925. * @readOnly
  37926. */
  37927. fresh: true,
  37928. /**
  37929. * A Game Object is that is pendingDestroy is flagged to have its destroy method called on the next logic update.
  37930. * You can set it directly to allow you to flag an object to be destroyed on its next update.
  37931. *
  37932. * This is extremely useful if you wish to destroy an object from within one of its own callbacks
  37933. * such as with Buttons or other Input events.
  37934. *
  37935. * @property {boolean} pendingDestroy
  37936. */
  37937. pendingDestroy: false,
  37938. /**
  37939. * @property {Phaser.Rectangle} _bounds - Internal cache var.
  37940. * @private
  37941. */
  37942. _bounds: null,
  37943. /**
  37944. * @property {boolean} _exists - Internal cache var.
  37945. * @private
  37946. */
  37947. _exists: true,
  37948. /**
  37949. * Controls if this Game Object is processed by the core game loop.
  37950. * If this Game Object has a physics body it also controls if its physics body is updated or not.
  37951. * When `exists` is set to `false` it will remove its physics body from the physics world if it has one.
  37952. * It also toggles the `visible` property to false as well.
  37953. *
  37954. * Setting `exists` to true will add its physics body back in to the physics world, if it has one.
  37955. * It will also set the `visible` property to `true`.
  37956. *
  37957. * @property {boolean} exists
  37958. */
  37959. exists: {
  37960. get: function () {
  37961. return this._exists;
  37962. },
  37963. set: function (value) {
  37964. if (value)
  37965. {
  37966. this._exists = true;
  37967. if (this.body && this.body.type === Phaser.Physics.P2JS)
  37968. {
  37969. this.body.addToWorld();
  37970. }
  37971. this.visible = true;
  37972. }
  37973. else
  37974. {
  37975. this._exists = false;
  37976. if (this.body && this.body.type === Phaser.Physics.P2JS)
  37977. {
  37978. this.body.removeFromWorld();
  37979. }
  37980. this.visible = false;
  37981. }
  37982. }
  37983. },
  37984. /**
  37985. * Internal method called by preUpdate.
  37986. *
  37987. * @method
  37988. * @protected
  37989. */
  37990. preUpdateChildren: function() {
  37991. // This can't loop in reverse, we need the renderOrderID to be in sequence
  37992. var i = 0;
  37993. while (i < this.children.length)
  37994. {
  37995. var child = this.children[i];
  37996. child.preUpdate();
  37997. if (this === child.parent)
  37998. {
  37999. i++;
  38000. }
  38001. }
  38002. },
  38003. /**
  38004. * Override this method in your own custom objects to handle any update requirements.
  38005. * It is called immediately after `preUpdate` and before `postUpdate`.
  38006. * Remember if this Game Object has any children you should call update on those too.
  38007. *
  38008. * @method
  38009. */
  38010. update: function() {
  38011. },
  38012. /**
  38013. * Internal method called by the World postUpdate cycle.
  38014. *
  38015. * @method
  38016. * @protected
  38017. */
  38018. postUpdate: function() {
  38019. if (this.customRender)
  38020. {
  38021. this.key.render();
  38022. }
  38023. if (this.components.PhysicsBody)
  38024. {
  38025. Phaser.Component.PhysicsBody.postUpdate.call(this);
  38026. }
  38027. if (this.components.FixedToCamera)
  38028. {
  38029. Phaser.Component.FixedToCamera.postUpdate.call(this);
  38030. }
  38031. for (var i = 0; i < this.children.length; i++)
  38032. {
  38033. this.children[i].postUpdate();
  38034. }
  38035. }
  38036. };
  38037. /**
  38038. * @author Richard Davey <rich@photonstorm.com>
  38039. * @copyright 2016 Photon Storm Ltd.
  38040. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38041. */
  38042. /**
  38043. * The Crop component provides the ability to crop a texture based Game Object to a defined rectangle,
  38044. * which can be updated in real-time.
  38045. *
  38046. * @class
  38047. */
  38048. Phaser.Component.Crop = function () {};
  38049. Phaser.Component.Crop.prototype = {
  38050. /**
  38051. * The Rectangle used to crop the texture this Game Object uses.
  38052. * Set this property via `crop`.
  38053. * If you modify this property directly you must call `updateCrop` in order to have the change take effect.
  38054. * @property {Phaser.Rectangle} cropRect
  38055. * @default
  38056. */
  38057. cropRect: null,
  38058. /**
  38059. * @property {Phaser.Rectangle} _crop - Internal cache var.
  38060. * @private
  38061. */
  38062. _crop: null,
  38063. /**
  38064. * Crop allows you to crop the texture being used to display this Game Object.
  38065. * Setting a crop rectangle modifies the core texture frame. The Game Object width and height properties will be adjusted accordingly.
  38066. *
  38067. * Cropping takes place from the top-left and can be modified in real-time either by providing an updated rectangle object to this method,
  38068. * or by modifying `cropRect` property directly and then calling `updateCrop`.
  38069. *
  38070. * The rectangle object given to this method can be either a `Phaser.Rectangle` or any other object
  38071. * so long as it has public `x`, `y`, `width`, `height`, `right` and `bottom` properties.
  38072. *
  38073. * A reference to the rectangle is stored in `cropRect` unless the `copy` parameter is `true`,
  38074. * in which case the values are duplicated to a local object.
  38075. *
  38076. * @method
  38077. * @param {Phaser.Rectangle} rect - The Rectangle used during cropping. Pass null or no parameters to clear a previously set crop rectangle.
  38078. * @param {boolean} [copy=false] - If false `cropRect` will be stored as a reference to the given rect. If true it will copy the rect values into a local Phaser Rectangle object stored in cropRect.
  38079. */
  38080. crop: function (rect, copy) {
  38081. if (copy === undefined) { copy = false; }
  38082. if (rect)
  38083. {
  38084. if (copy && this.cropRect !== null)
  38085. {
  38086. this.cropRect.setTo(rect.x, rect.y, rect.width, rect.height);
  38087. }
  38088. else if (copy && this.cropRect === null)
  38089. {
  38090. this.cropRect = new Phaser.Rectangle(rect.x, rect.y, rect.width, rect.height);
  38091. }
  38092. else
  38093. {
  38094. this.cropRect = rect;
  38095. }
  38096. this.updateCrop();
  38097. }
  38098. else
  38099. {
  38100. this._crop = null;
  38101. this.cropRect = null;
  38102. this.resetFrame();
  38103. }
  38104. },
  38105. /**
  38106. * If you have set a crop rectangle on this Game Object via `crop` and since modified the `cropRect` property,
  38107. * or the rectangle it references, then you need to update the crop frame by calling this method.
  38108. *
  38109. * @method
  38110. */
  38111. updateCrop: function () {
  38112. if (!this.cropRect)
  38113. {
  38114. return;
  38115. }
  38116. var oldX = this.texture.crop.x;
  38117. var oldY = this.texture.crop.y;
  38118. var oldW = this.texture.crop.width;
  38119. var oldH = this.texture.crop.height;
  38120. this._crop = Phaser.Rectangle.clone(this.cropRect, this._crop);
  38121. this._crop.x += this._frame.x;
  38122. this._crop.y += this._frame.y;
  38123. var cx = Math.max(this._frame.x, this._crop.x);
  38124. var cy = Math.max(this._frame.y, this._crop.y);
  38125. var cw = Math.min(this._frame.right, this._crop.right) - cx;
  38126. var ch = Math.min(this._frame.bottom, this._crop.bottom) - cy;
  38127. this.texture.crop.x = cx;
  38128. this.texture.crop.y = cy;
  38129. this.texture.crop.width = cw;
  38130. this.texture.crop.height = ch;
  38131. this.texture.frame.width = Math.min(cw, this.cropRect.width);
  38132. this.texture.frame.height = Math.min(ch, this.cropRect.height);
  38133. this.texture.width = this.texture.frame.width;
  38134. this.texture.height = this.texture.frame.height;
  38135. this.texture._updateUvs();
  38136. if (this.tint !== 0xffffff && (oldX !== cx || oldY !== cy || oldW !== cw || oldH !== ch))
  38137. {
  38138. this.texture.requiresReTint = true;
  38139. }
  38140. }
  38141. };
  38142. /**
  38143. * @author Richard Davey <rich@photonstorm.com>
  38144. * @copyright 2016 Photon Storm Ltd.
  38145. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38146. */
  38147. /**
  38148. * The Delta component provides access to delta values between the Game Objects current and previous position.
  38149. *
  38150. * @class
  38151. */
  38152. Phaser.Component.Delta = function () {};
  38153. Phaser.Component.Delta.prototype = {
  38154. /**
  38155. * Returns the delta x value. The difference between world.x now and in the previous frame.
  38156. *
  38157. * The value will be positive if the Game Object has moved to the right or negative if to the left.
  38158. *
  38159. * @property {number} deltaX
  38160. * @readonly
  38161. */
  38162. deltaX: {
  38163. get: function() {
  38164. return this.world.x - this.previousPosition.x;
  38165. }
  38166. },
  38167. /**
  38168. * Returns the delta y value. The difference between world.y now and in the previous frame.
  38169. *
  38170. * The value will be positive if the Game Object has moved down or negative if up.
  38171. *
  38172. * @property {number} deltaY
  38173. * @readonly
  38174. */
  38175. deltaY: {
  38176. get: function() {
  38177. return this.world.y - this.previousPosition.y;
  38178. }
  38179. },
  38180. /**
  38181. * Returns the delta z value. The difference between rotation now and in the previous frame.
  38182. *
  38183. * @property {number} deltaZ - The delta value.
  38184. * @readonly
  38185. */
  38186. deltaZ: {
  38187. get: function() {
  38188. return this.rotation - this.previousRotation;
  38189. }
  38190. }
  38191. };
  38192. /**
  38193. * @author Richard Davey <rich@photonstorm.com>
  38194. * @copyright 2016 Photon Storm Ltd.
  38195. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38196. */
  38197. /**
  38198. * The Destroy component is responsible for destroying a Game Object.
  38199. *
  38200. * @class
  38201. */
  38202. Phaser.Component.Destroy = function () {};
  38203. Phaser.Component.Destroy.prototype = {
  38204. /**
  38205. * As a Game Object runs through its destroy method this flag is set to true,
  38206. * and can be checked in any sub-systems or plugins it is being destroyed from.
  38207. * @property {boolean} destroyPhase
  38208. * @readOnly
  38209. */
  38210. destroyPhase: false,
  38211. /**
  38212. * Destroys the Game Object. This removes it from its parent group, destroys the input, event and animation handlers if present
  38213. * and nulls its reference to `game`, freeing it up for garbage collection.
  38214. *
  38215. * If this Game Object has the Events component it will also dispatch the `onDestroy` event.
  38216. *
  38217. * You can optionally also destroy the BaseTexture this Game Object is using. Be careful if you've
  38218. * more than one Game Object sharing the same BaseTexture.
  38219. *
  38220. * @method
  38221. * @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called as well?
  38222. * @param {boolean} [destroyTexture=false] - Destroy the BaseTexture this Game Object is using? Note that if another Game Object is sharing the same BaseTexture it will invalidate it.
  38223. */
  38224. destroy: function (destroyChildren, destroyTexture) {
  38225. if (this.game === null || this.destroyPhase) { return; }
  38226. if (destroyChildren === undefined) { destroyChildren = true; }
  38227. if (destroyTexture === undefined) { destroyTexture = false; }
  38228. this.destroyPhase = true;
  38229. if (this.events)
  38230. {
  38231. this.events.onDestroy$dispatch(this);
  38232. }
  38233. if (this.parent)
  38234. {
  38235. if (this.parent instanceof Phaser.Group)
  38236. {
  38237. this.parent.remove(this);
  38238. }
  38239. else
  38240. {
  38241. this.parent.removeChild(this);
  38242. }
  38243. }
  38244. if (this.input)
  38245. {
  38246. this.input.destroy();
  38247. }
  38248. if (this.animations)
  38249. {
  38250. this.animations.destroy();
  38251. }
  38252. if (this.body)
  38253. {
  38254. this.body.destroy();
  38255. }
  38256. if (this.events)
  38257. {
  38258. this.events.destroy();
  38259. }
  38260. this.game.tweens.removeFrom(this);
  38261. var i = this.children.length;
  38262. if (destroyChildren)
  38263. {
  38264. while (i--)
  38265. {
  38266. this.children[i].destroy(destroyChildren);
  38267. }
  38268. }
  38269. else
  38270. {
  38271. while (i--)
  38272. {
  38273. this.removeChild(this.children[i]);
  38274. }
  38275. }
  38276. if (this._crop)
  38277. {
  38278. this._crop = null;
  38279. this.cropRect = null;
  38280. }
  38281. if (this._frame)
  38282. {
  38283. this._frame = null;
  38284. }
  38285. if (Phaser.Video && this.key instanceof Phaser.Video)
  38286. {
  38287. this.key.onChangeSource.remove(this.resizeFrame, this);
  38288. }
  38289. if (Phaser.BitmapText && this._glyphs)
  38290. {
  38291. this._glyphs = [];
  38292. }
  38293. this.alive = false;
  38294. this.exists = false;
  38295. this.visible = false;
  38296. this.filters = null;
  38297. this.mask = null;
  38298. this.game = null;
  38299. this.data = {};
  38300. // In case Pixi is still going to try and render it even though destroyed
  38301. this.renderable = false;
  38302. if (this.transformCallback)
  38303. {
  38304. this.transformCallback = null;
  38305. this.transformCallbackContext = null;
  38306. }
  38307. // Pixi level DisplayObject destroy
  38308. this.hitArea = null;
  38309. this.parent = null;
  38310. this.stage = null;
  38311. this.worldTransform = null;
  38312. this.filterArea = null;
  38313. this._bounds = null;
  38314. this._currentBounds = null;
  38315. this._mask = null;
  38316. this._destroyCachedSprite();
  38317. // Texture?
  38318. if (destroyTexture)
  38319. {
  38320. this.texture.destroy(true);
  38321. }
  38322. this.destroyPhase = false;
  38323. this.pendingDestroy = false;
  38324. }
  38325. };
  38326. /**
  38327. * @author Richard Davey <rich@photonstorm.com>
  38328. * @copyright 2016 Photon Storm Ltd.
  38329. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38330. */
  38331. /**
  38332. * The Events component is a collection of events fired by the parent Game Object.
  38333. *
  38334. * Phaser uses what are known as 'Signals' for all event handling. All of the events in
  38335. * this class are signals you can subscribe to, much in the same way you'd "listen" for
  38336. * an event.
  38337. *
  38338. * For example to tell when a Sprite has been added to a new group, you can bind a function
  38339. * to the {@link #onAddedToGroup} signal:
  38340. *
  38341. * `sprite.events.onAddedToGroup.add(yourFunction, this);`
  38342. *
  38343. * Where `yourFunction` is the function you want called when this event occurs.
  38344. *
  38345. * For more details about how signals work please see the {@link Phaser.Signal} class.
  38346. *
  38347. * The Input-related events will only be dispatched if the Sprite has had {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} set to `true`
  38348. * and the Animation-related events only apply to game objects with animations like {@link Phaser.Sprite}.
  38349. *
  38350. * @class Phaser.Events
  38351. * @constructor
  38352. * @param {Phaser.Sprite} sprite - A reference to the game object / Sprite that owns this Events object.
  38353. */
  38354. Phaser.Events = function (sprite) {
  38355. /**
  38356. * @property {Phaser.Sprite} parent - The Sprite that owns these events.
  38357. */
  38358. this.parent = sprite;
  38359. // The signals are automatically added by the corresponding proxy properties
  38360. };
  38361. Phaser.Events.prototype = {
  38362. /**
  38363. * Removes all events.
  38364. *
  38365. * @method Phaser.Events#destroy
  38366. */
  38367. destroy: function () {
  38368. this._parent = null;
  38369. if (this._onDestroy) { this._onDestroy.dispose(); }
  38370. if (this._onAddedToGroup) { this._onAddedToGroup.dispose(); }
  38371. if (this._onRemovedFromGroup) { this._onRemovedFromGroup.dispose(); }
  38372. if (this._onKilled) { this._onKilled.dispose(); }
  38373. if (this._onRevived) { this._onRevived.dispose(); }
  38374. if (this._onEnterBounds) { this._onEnterBounds.dispose(); }
  38375. if (this._onOutOfBounds) { this._onOutOfBounds.dispose(); }
  38376. if (this._onInputOver) { this._onInputOver.dispose(); }
  38377. if (this._onInputOut) { this._onInputOut.dispose(); }
  38378. if (this._onInputDown) { this._onInputDown.dispose(); }
  38379. if (this._onInputUp) { this._onInputUp.dispose(); }
  38380. if (this._onDragStart) { this._onDragStart.dispose(); }
  38381. if (this._onDragUpdate) { this._onDragUpdate.dispose(); }
  38382. if (this._onDragStop) { this._onDragStop.dispose(); }
  38383. if (this._onAnimationStart) { this._onAnimationStart.dispose(); }
  38384. if (this._onAnimationComplete) { this._onAnimationComplete.dispose(); }
  38385. if (this._onAnimationLoop) { this._onAnimationLoop.dispose(); }
  38386. },
  38387. // The following properties are sentinels that will be replaced with getters
  38388. /**
  38389. * This signal is dispatched when this Game Object is added to a new {@link Phaser.Group Group}.
  38390. * It is sent two arguments:
  38391. *
  38392. * - {any} The Game Object that was added to the Group.
  38393. * - {Phaser.Group} The Group it was added to.
  38394. *
  38395. * @property {Phaser.Signal} onAddedToGroup
  38396. */
  38397. onAddedToGroup: null,
  38398. /**
  38399. * This signal is dispatched when the Game Object is removed from a {@link Phaser.Group Group}.
  38400. * It is sent two arguments:
  38401. *
  38402. * - {any} The Game Object that was removed from the Group.
  38403. * - {Phaser.Group} The Group it was removed from.
  38404. *
  38405. * @property {Phaser.Signal} onRemovedFromGroup
  38406. */
  38407. onRemovedFromGroup: null,
  38408. /**
  38409. * This signal is dispatched when the Game Object is destroyed.
  38410. * This happens when {@link Phaser.Sprite#destroy Sprite.destroy()} is called, or {@link Phaser.Group#destroy Group.destroy()} with `destroyChildren` set to true.
  38411. * It is sent one argument:
  38412. *
  38413. * - {any} The Game Object that was destroyed.
  38414. *
  38415. * @property {Phaser.Signal} onDestroy
  38416. */
  38417. onDestroy: null,
  38418. /**
  38419. * This signal is dispatched when the Game Object is killed.
  38420. * This happens when {@link Phaser.Sprite#kill Sprite.kill()} is called.
  38421. * Please understand the difference between {@link Phaser.Sprite#kill kill} and {@link Phaser.Sprite#destroy destroy} by looking at their respective methods.
  38422. * It is sent one argument:
  38423. *
  38424. * - {any} The Game Object that was killed.
  38425. *
  38426. * @property {Phaser.Signal} onKilled
  38427. */
  38428. onKilled: null,
  38429. /**
  38430. * This signal is dispatched when the Game Object is revived from a previously killed state.
  38431. * This happens when {@link Phaser.Sprite#revive Sprite.revive()} is called.
  38432. * It is sent one argument:
  38433. *
  38434. * - {any} The Game Object that was revived.
  38435. *
  38436. * @property {Phaser.Signal} onRevived
  38437. */
  38438. onRevived: null,
  38439. /**
  38440. * This signal is dispatched when the Game Object leaves the Phaser.World {@link Phaser.World#bounds bounds}.
  38441. * This signal is only if {@link Phaser.Sprite#checkWorldBounds Sprite.checkWorldBounds} is set to `true`.
  38442. * It is sent one argument:
  38443. *
  38444. * - {any} The Game Object that left the World bounds.
  38445. *
  38446. * @property {Phaser.Signal} onOutOfBounds
  38447. */
  38448. onOutOfBounds: null,
  38449. /**
  38450. * This signal is dispatched when the Game Object returns within the Phaser.World {@link Phaser.World#bounds bounds}, having previously been outside of them.
  38451. * This signal is only if {@link Phaser.Sprite#checkWorldBounds Sprite.checkWorldBounds} is set to `true`.
  38452. * It is sent one argument:
  38453. *
  38454. * - {any} The Game Object that entered the World bounds.
  38455. *
  38456. * @property {Phaser.Signal} onEnterBounds
  38457. */
  38458. onEnterBounds: null,
  38459. /**
  38460. * This signal is dispatched if the Game Object has {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} set to `true`,
  38461. * and receives an over event from a {@link Phaser.Pointer}.
  38462. * It is sent two arguments:
  38463. *
  38464. * - {any} The Game Object that received the event.
  38465. * - {Phaser.Pointer} The Phaser.Pointer object that caused the event.
  38466. *
  38467. * @property {Phaser.Signal} onInputOver
  38468. */
  38469. onInputOver: null,
  38470. /**
  38471. * This signal is dispatched if the Game Object has {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} set to `true`,
  38472. * and receives an out event from a {@link Phaser.Pointer}, which was previously over it.
  38473. * It is sent two arguments:
  38474. *
  38475. * - {any} The Game Object that received the event.
  38476. * - {Phaser.Pointer} The Phaser.Pointer object that caused the event.
  38477. *
  38478. * @property {Phaser.Signal} onInputOut
  38479. */
  38480. onInputOut: null,
  38481. /**
  38482. * This signal is dispatched if the Game Object has {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} set to `true`,
  38483. * and receives a down event from a {@link Phaser.Pointer}. This effectively means the Pointer has been
  38484. * pressed down (but not yet released) on the Game Object.
  38485. * It is sent two arguments:
  38486. *
  38487. * - {any} The Game Object that received the event.
  38488. * - {Phaser.Pointer} The Phaser.Pointer object that caused the event.
  38489. *
  38490. * @property {Phaser.Signal} onInputDown
  38491. */
  38492. onInputDown: null,
  38493. /**
  38494. * This signal is dispatched if the Game Object has {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} set to `true`,
  38495. * and receives an up event from a {@link Phaser.Pointer}. This effectively means the Pointer had been
  38496. * pressed down, and was then released on the Game Object.
  38497. * It is sent three arguments:
  38498. *
  38499. * - {any} The Game Object that received the event.
  38500. * - {Phaser.Pointer} The Phaser.Pointer object that caused the event.
  38501. * - {boolean} isOver - Is the Pointer still over the Game Object?
  38502. *
  38503. * @property {Phaser.Signal} onInputUp
  38504. */
  38505. onInputUp: null,
  38506. /**
  38507. * This signal is dispatched if the Game Object has been {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} and {@link Phaser.InputHandler#enableDrag enableDrag} has been set.
  38508. * It is sent when a {@link Phaser.Pointer} starts to drag the Game Object, taking into consideration the various
  38509. * drag limitations that may be set.
  38510. * It is sent four arguments:
  38511. *
  38512. * - {any} The Game Object that received the event.
  38513. * - {Phaser.Pointer} The Phaser.Pointer object that caused the event.
  38514. * - {number} The x coordinate that the drag started from.
  38515. * - {number} The y coordinate that the drag started from.
  38516. *
  38517. * @property {Phaser.Signal} onDragStart
  38518. */
  38519. onDragStart: null,
  38520. /**
  38521. * This signal is dispatched if the Game Object has been {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} and {@link Phaser.InputHandler#enableDrag enableDrag} has been set.
  38522. * It is sent when a {@link Phaser.Pointer} is actively dragging the Game Object.
  38523. * Be warned: This is a high volume Signal. Be careful what you bind to it.
  38524. * It is sent six arguments:
  38525. *
  38526. * - {any} The Game Object that received the event.
  38527. * - {Phaser.Pointer} The Phaser.Pointer object that caused the event.
  38528. * - {number} The new x coordinate of the Game Object.
  38529. * - {number} The new y coordinate of the Game Object.
  38530. * - {Phaser.Point} A Point object that contains the point the Game Object was snapped to, if `snapOnDrag` has been enabled.
  38531. * - {boolean} The `fromStart` boolean, indicates if this is the first update immediately after the drag has started.
  38532. *
  38533. * @property {Phaser.Signal} onDragUpdate
  38534. */
  38535. onDragUpdate: null,
  38536. /**
  38537. * This signal is dispatched if the Game Object has been {@link Phaser.Component.InputEnabled#inputEnabled inputEnabled} and {@link Phaser.InputHandler#enableDrag enableDrag} has been set.
  38538. * It is sent when a {@link Phaser.Pointer} stops dragging the Game Object.
  38539. * It is sent two arguments:
  38540. *
  38541. * - {any} The Game Object that received the event.
  38542. * - {Phaser.Pointer} The Phaser.Pointer object that caused the event.
  38543. *
  38544. * @property {Phaser.Signal} onDragStop
  38545. */
  38546. onDragStop: null,
  38547. /**
  38548. * This signal is dispatched if the Game Object has the {@link Phaser.AnimationManager AnimationManager} component,
  38549. * and an Animation has been played.
  38550. * You can also listen to {@link Phaser.Animation#onStart} rather than via the Game Objects events.
  38551. * It is sent two arguments:
  38552. *
  38553. * - {any} The Game Object that received the event.
  38554. * - {Phaser.Animation} The Phaser.Animation that was started.
  38555. *
  38556. * @property {Phaser.Signal} onAnimationStart
  38557. */
  38558. onAnimationStart: null,
  38559. /**
  38560. * This signal is dispatched if the Game Object has the {@link Phaser.AnimationManager AnimationManager} component,
  38561. * and an Animation has been stopped (via {@link Phaser.AnimationManager#stop animation.stop()} and the `dispatchComplete` argument has been set.
  38562. * You can also listen to {@link Phaser.Animation#onComplete} rather than via the Game Objects events.
  38563. * It is sent two arguments:
  38564. *
  38565. * - {any} The Game Object that received the event.
  38566. * - {Phaser.Animation} The Phaser.Animation that was stopped.
  38567. *
  38568. * @property {Phaser.Signal} onAnimationComplete
  38569. */
  38570. onAnimationComplete: null,
  38571. /**
  38572. * This signal is dispatched if the Game Object has the {@link Phaser.AnimationManager AnimationManager} component,
  38573. * and an Animation has looped playback.
  38574. * You can also listen to {@link Phaser.Animation#onLoop} rather than via the Game Objects events.
  38575. * It is sent two arguments:
  38576. *
  38577. * - {any} The Game Object that received the event.
  38578. * - {Phaser.Animation} The Phaser.Animation that looped.
  38579. *
  38580. * @property {Phaser.Signal} onAnimationLoop
  38581. */
  38582. onAnimationLoop: null
  38583. };
  38584. Phaser.Events.prototype.constructor = Phaser.Events;
  38585. // Create an auto-create proxy getter and dispatch method for all events.
  38586. // The backing property is the same as the event name, prefixed with '_'
  38587. // and the dispatch method is the same as the event name postfixed with '$dispatch'.
  38588. for (var prop in Phaser.Events.prototype)
  38589. {
  38590. if (!Phaser.Events.prototype.hasOwnProperty(prop) ||
  38591. prop.indexOf('on') !== 0 ||
  38592. Phaser.Events.prototype[prop] !== null)
  38593. {
  38594. continue;
  38595. }
  38596. (function (prop, backing) {
  38597. 'use strict';
  38598. // The accessor creates a new Signal; and so it should only be used from user-code.
  38599. Object.defineProperty(Phaser.Events.prototype, prop, {
  38600. get: function () {
  38601. return this[backing] || (this[backing] = new Phaser.Signal());
  38602. }
  38603. });
  38604. // The dispatcher will only broadcast on an already-created signal; call this internally.
  38605. Phaser.Events.prototype[prop + '$dispatch'] = function () {
  38606. return this[backing] ? this[backing].dispatch.apply(this[backing], arguments) : null;
  38607. };
  38608. })(prop, '_' + prop);
  38609. }
  38610. /**
  38611. * @author Richard Davey <rich@photonstorm.com>
  38612. * @copyright 2016 Photon Storm Ltd.
  38613. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38614. */
  38615. /**
  38616. * The FixedToCamera component enables a Game Object to be rendered relative to the game camera coordinates, regardless
  38617. * of where in the world the camera is. This is used for things like sticking game UI to the camera that scrolls as it moves around the world.
  38618. *
  38619. * @class
  38620. */
  38621. Phaser.Component.FixedToCamera = function () {};
  38622. /**
  38623. * The FixedToCamera component postUpdate handler.
  38624. * Called automatically by the Game Object.
  38625. *
  38626. * @method
  38627. */
  38628. Phaser.Component.FixedToCamera.postUpdate = function () {
  38629. if (this.fixedToCamera)
  38630. {
  38631. this.position.x = (this.game.camera.view.x + this.cameraOffset.x) / this.game.camera.scale.x;
  38632. this.position.y = (this.game.camera.view.y + this.cameraOffset.y) / this.game.camera.scale.y;
  38633. }
  38634. };
  38635. Phaser.Component.FixedToCamera.prototype = {
  38636. /**
  38637. * @property {boolean} _fixedToCamera
  38638. * @private
  38639. */
  38640. _fixedToCamera: false,
  38641. /**
  38642. * A Game Object that is "fixed" to the camera is rendered at a given x/y offsets from the top left of the camera. The offsets
  38643. * are stored in the `cameraOffset` property, which is initialized with the current object coordinates.
  38644. *
  38645. * The values are adjusted at the rendering stage, overriding the Game Objects actual world position.
  38646. *
  38647. * The end result is that the Game Object will appear to be 'fixed' to the camera, regardless of where in the game world
  38648. * the camera is viewing. This is useful if for example this Game Object is a UI item that you wish to be visible at all times
  38649. * regardless where in the world the camera is.
  38650. *
  38651. * Note that the `cameraOffset` values are in addition to any parent of this Game Object on the display list.
  38652. *
  38653. * Be careful not to set `fixedToCamera` on Game Objects which are in Groups that already have `fixedToCamera` enabled on them.
  38654. *
  38655. * @property {boolean} fixedToCamera
  38656. */
  38657. fixedToCamera: {
  38658. get: function () {
  38659. return this._fixedToCamera;
  38660. },
  38661. set: function (value) {
  38662. if (value)
  38663. {
  38664. this._fixedToCamera = true;
  38665. this.cameraOffset.set(this.x, this.y);
  38666. }
  38667. else
  38668. {
  38669. this._fixedToCamera = false;
  38670. }
  38671. }
  38672. },
  38673. /**
  38674. * The x/y coordinate offset applied to the top-left of the camera that this Game Object will be drawn at if `fixedToCamera` is true.
  38675. *
  38676. * The values are relative to the top-left of the camera view and in addition to any parent of the Game Object on the display list.
  38677. * @property {Phaser.Point} cameraOffset
  38678. */
  38679. cameraOffset: new Phaser.Point()
  38680. };
  38681. /**
  38682. * @author Richard Davey <rich@photonstorm.com>
  38683. * @copyright 2016 Photon Storm Ltd.
  38684. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38685. */
  38686. /**
  38687. * The Health component provides the ability for Game Objects to have a `health` property
  38688. * that can be damaged and reset through game code.
  38689. * Requires the LifeSpan component.
  38690. *
  38691. * @class
  38692. */
  38693. Phaser.Component.Health = function () {};
  38694. Phaser.Component.Health.prototype = {
  38695. /**
  38696. * The Game Objects health value. This is a handy property for setting and manipulating health on a Game Object.
  38697. *
  38698. * It can be used in combination with the `damage` method or modified directly.
  38699. *
  38700. * @property {number} health
  38701. * @default
  38702. */
  38703. health: 1,
  38704. /**
  38705. * The Game Objects maximum health value. This works in combination with the `heal` method to ensure
  38706. * the health value never exceeds the maximum.
  38707. *
  38708. * @property {number} maxHealth
  38709. * @default
  38710. */
  38711. maxHealth: 100,
  38712. /**
  38713. * Damages the Game Object. This removes the given amount of health from the `health` property.
  38714. *
  38715. * If health is taken below or is equal to zero then the `kill` method is called.
  38716. *
  38717. * @method
  38718. * @param {number} amount - The amount to subtract from the current `health` value.
  38719. * @return {Phaser.Sprite} This instance.
  38720. */
  38721. damage: function (amount) {
  38722. if (this.alive)
  38723. {
  38724. this.health -= amount;
  38725. if (this.health <= 0)
  38726. {
  38727. this.kill();
  38728. }
  38729. }
  38730. return this;
  38731. },
  38732. /**
  38733. * Sets the health property of the Game Object to the given amount.
  38734. * Will never exceed the `maxHealth` value.
  38735. *
  38736. * @method
  38737. * @param {number} amount - The amount to set the `health` value to. The total will never exceed `maxHealth`.
  38738. * @return {Phaser.Sprite} This instance.
  38739. */
  38740. setHealth: function (amount) {
  38741. this.health = amount;
  38742. if (this.health > this.maxHealth)
  38743. {
  38744. this.health = this.maxHealth;
  38745. }
  38746. return this;
  38747. },
  38748. /**
  38749. * Heal the Game Object. This adds the given amount of health to the `health` property.
  38750. *
  38751. * @method
  38752. * @param {number} amount - The amount to add to the current `health` value. The total will never exceed `maxHealth`.
  38753. * @return {Phaser.Sprite} This instance.
  38754. */
  38755. heal: function (amount) {
  38756. if (this.alive)
  38757. {
  38758. this.health += amount;
  38759. if (this.health > this.maxHealth)
  38760. {
  38761. this.health = this.maxHealth;
  38762. }
  38763. }
  38764. return this;
  38765. }
  38766. };
  38767. /**
  38768. * @author Richard Davey <rich@photonstorm.com>
  38769. * @copyright 2016 Photon Storm Ltd.
  38770. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38771. */
  38772. /**
  38773. * The InCamera component checks if the Game Object intersects with the Game Camera.
  38774. *
  38775. * @class
  38776. */
  38777. Phaser.Component.InCamera = function () {};
  38778. Phaser.Component.InCamera.prototype = {
  38779. /**
  38780. * Checks if this Game Objects bounds intersects with the Game Cameras bounds.
  38781. *
  38782. * It will be `true` if they intersect, or `false` if the Game Object is fully outside of the Cameras bounds.
  38783. *
  38784. * An object outside the bounds can be considered for camera culling if it has the AutoCull component.
  38785. *
  38786. * @property {boolean} inCamera
  38787. * @readonly
  38788. */
  38789. inCamera: {
  38790. get: function() {
  38791. return this.game.world.camera.view.intersects(this._bounds);
  38792. }
  38793. }
  38794. };
  38795. /**
  38796. * @author Richard Davey <rich@photonstorm.com>
  38797. * @copyright 2016 Photon Storm Ltd.
  38798. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38799. */
  38800. /**
  38801. * The InputEnabled component allows a Game Object to have its own InputHandler and process input related events.
  38802. *
  38803. * @class
  38804. */
  38805. Phaser.Component.InputEnabled = function () {};
  38806. Phaser.Component.InputEnabled.prototype = {
  38807. /**
  38808. * The Input Handler for this Game Object.
  38809. *
  38810. * By default it is disabled. If you wish this Game Object to process input events you should enable it with: `inputEnabled = true`.
  38811. *
  38812. * After you have done this, this property will be a reference to the Phaser InputHandler.
  38813. * @property {Phaser.InputHandler|null} input
  38814. */
  38815. input: null,
  38816. /**
  38817. * By default a Game Object won't process any input events. By setting `inputEnabled` to true a Phaser.InputHandler is created
  38818. * for this Game Object and it will then start to process click / touch events and more.
  38819. *
  38820. * You can then access the Input Handler via `this.input`.
  38821. *
  38822. * Note that Input related events are dispatched from `this.events`, i.e.: `events.onInputDown`.
  38823. *
  38824. * If you set this property to false it will stop the Input Handler from processing any more input events.
  38825. *
  38826. * If you want to _temporarily_ disable input for a Game Object, then it's better to set
  38827. * `input.enabled = false`, as it won't reset any of the Input Handlers internal properties.
  38828. * You can then toggle this back on as needed.
  38829. *
  38830. * @property {boolean} inputEnabled
  38831. */
  38832. inputEnabled: {
  38833. get: function () {
  38834. return (this.input && this.input.enabled);
  38835. },
  38836. set: function (value) {
  38837. if (value)
  38838. {
  38839. if (this.input === null)
  38840. {
  38841. this.input = new Phaser.InputHandler(this);
  38842. this.input.start();
  38843. }
  38844. else if (this.input && !this.input.enabled)
  38845. {
  38846. this.input.start();
  38847. }
  38848. }
  38849. else
  38850. {
  38851. if (this.input && this.input.enabled)
  38852. {
  38853. this.input.stop();
  38854. }
  38855. }
  38856. }
  38857. }
  38858. };
  38859. /**
  38860. * @author Richard Davey <rich@photonstorm.com>
  38861. * @copyright 2016 Photon Storm Ltd.
  38862. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38863. */
  38864. /**
  38865. * The InWorld component checks if a Game Object is within the Game World Bounds.
  38866. * An object is considered as being "in bounds" so long as its own bounds intersects at any point with the World bounds.
  38867. * If the AutoCull component is enabled on the Game Object then it will check the Game Object against the Camera bounds as well.
  38868. *
  38869. * @class
  38870. */
  38871. Phaser.Component.InWorld = function () {};
  38872. /**
  38873. * The InWorld component preUpdate handler.
  38874. * Called automatically by the Game Object.
  38875. *
  38876. * @method
  38877. */
  38878. Phaser.Component.InWorld.preUpdate = function () {
  38879. // Cache the bounds if we need it
  38880. if (this.autoCull || this.checkWorldBounds)
  38881. {
  38882. this._bounds.copyFrom(this.getBounds());
  38883. this._bounds.x += this.game.camera.view.x;
  38884. this._bounds.y += this.game.camera.view.y;
  38885. if (this.autoCull)
  38886. {
  38887. // Won't get rendered but will still get its transform updated
  38888. if (this.game.world.camera.view.intersects(this._bounds))
  38889. {
  38890. this.renderable = true;
  38891. this.game.world.camera.totalInView++;
  38892. }
  38893. else
  38894. {
  38895. this.renderable = false;
  38896. if (this.outOfCameraBoundsKill)
  38897. {
  38898. this.kill();
  38899. return false;
  38900. }
  38901. }
  38902. }
  38903. if (this.checkWorldBounds)
  38904. {
  38905. // The Sprite is already out of the world bounds, so let's check to see if it has come back again
  38906. if (this._outOfBoundsFired && this.game.world.bounds.intersects(this._bounds))
  38907. {
  38908. this._outOfBoundsFired = false;
  38909. this.events.onEnterBounds$dispatch(this);
  38910. }
  38911. else if (!this._outOfBoundsFired && !this.game.world.bounds.intersects(this._bounds))
  38912. {
  38913. // The Sprite WAS in the screen, but has now left.
  38914. this._outOfBoundsFired = true;
  38915. this.events.onOutOfBounds$dispatch(this);
  38916. if (this.outOfBoundsKill)
  38917. {
  38918. this.kill();
  38919. return false;
  38920. }
  38921. }
  38922. }
  38923. }
  38924. return true;
  38925. };
  38926. Phaser.Component.InWorld.prototype = {
  38927. /**
  38928. * If this is set to `true` the Game Object checks if it is within the World bounds each frame.
  38929. *
  38930. * When it is no longer intersecting the world bounds it dispatches the `onOutOfBounds` event.
  38931. *
  38932. * If it was *previously* out of bounds but is now intersecting the world bounds again it dispatches the `onEnterBounds` event.
  38933. *
  38934. * It also optionally kills the Game Object if `outOfBoundsKill` is `true`.
  38935. *
  38936. * When `checkWorldBounds` is enabled it forces the Game Object to calculate its full bounds every frame.
  38937. *
  38938. * This is a relatively expensive operation, especially if enabled on hundreds of Game Objects. So enable it only if you know it's required,
  38939. * or you have tested performance and find it acceptable.
  38940. *
  38941. * @property {boolean} checkWorldBounds
  38942. * @default
  38943. */
  38944. checkWorldBounds: false,
  38945. /**
  38946. * If this and the `checkWorldBounds` property are both set to `true` then the `kill` method is called as soon as `inWorld` returns false.
  38947. *
  38948. * @property {boolean} outOfBoundsKill
  38949. * @default
  38950. */
  38951. outOfBoundsKill: false,
  38952. /**
  38953. * If this and the `autoCull` property are both set to `true`, then the `kill` method
  38954. * is called as soon as the Game Object leaves the camera bounds.
  38955. *
  38956. * @property {boolean} outOfCameraBoundsKill
  38957. * @default
  38958. */
  38959. outOfCameraBoundsKill: false,
  38960. /**
  38961. * @property {boolean} _outOfBoundsFired - Internal state var.
  38962. * @private
  38963. */
  38964. _outOfBoundsFired: false,
  38965. /**
  38966. * Checks if the Game Objects bounds are within, or intersect at any point with the Game World bounds.
  38967. *
  38968. * @property {boolean} inWorld
  38969. * @readonly
  38970. */
  38971. inWorld: {
  38972. get: function () {
  38973. return this.game.world.bounds.intersects(this.getBounds());
  38974. }
  38975. }
  38976. };
  38977. /**
  38978. * @author Richard Davey <rich@photonstorm.com>
  38979. * @copyright 2016 Photon Storm Ltd.
  38980. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  38981. */
  38982. /**
  38983. * LifeSpan Component Features.
  38984. *
  38985. * @class
  38986. */
  38987. Phaser.Component.LifeSpan = function () {};
  38988. /**
  38989. * The LifeSpan component preUpdate handler.
  38990. * Called automatically by the Game Object.
  38991. *
  38992. * @method
  38993. */
  38994. Phaser.Component.LifeSpan.preUpdate = function () {
  38995. if (this.lifespan > 0)
  38996. {
  38997. this.lifespan -= this.game.time.physicsElapsedMS;
  38998. if (this.lifespan <= 0)
  38999. {
  39000. this.kill();
  39001. return false;
  39002. }
  39003. }
  39004. return true;
  39005. };
  39006. Phaser.Component.LifeSpan.prototype = {
  39007. /**
  39008. * A useful flag to control if the Game Object is alive or dead.
  39009. *
  39010. * This is set automatically by the Health components `damage` method should the object run out of health.
  39011. * Or you can toggle it via your game code.
  39012. *
  39013. * This property is mostly just provided to be used by your game - it doesn't effect rendering or logic updates.
  39014. * However you can use `Group.getFirstAlive` in conjunction with this property for fast object pooling and recycling.
  39015. * @property {boolean} alive
  39016. * @default
  39017. */
  39018. alive: true,
  39019. /**
  39020. * The lifespan allows you to give a Game Object a lifespan in milliseconds.
  39021. *
  39022. * Once the Game Object is 'born' you can set this to a positive value.
  39023. *
  39024. * It is automatically decremented by the millisecond equivalent of `game.time.physicsElapsed` each frame.
  39025. * When it reaches zero it will call the `kill` method.
  39026. *
  39027. * Very handy for particles, bullets, collectibles, or any other short-lived entity.
  39028. *
  39029. * @property {number} lifespan
  39030. * @default
  39031. */
  39032. lifespan: 0,
  39033. /**
  39034. * Brings a 'dead' Game Object back to life, optionally resetting its health value in the process.
  39035. *
  39036. * A resurrected Game Object has its `alive`, `exists` and `visible` properties all set to true.
  39037. *
  39038. * It will dispatch the `onRevived` event. Listen to `events.onRevived` for the signal.
  39039. *
  39040. * @method
  39041. * @param {number} [health=100] - The health to give the Game Object. Only set if the GameObject has the Health component.
  39042. * @return {PIXI.DisplayObject} This instance.
  39043. */
  39044. revive: function (health) {
  39045. if (health === undefined) { health = 100; }
  39046. this.alive = true;
  39047. this.exists = true;
  39048. this.visible = true;
  39049. if (typeof this.setHealth === 'function')
  39050. {
  39051. this.setHealth(health);
  39052. }
  39053. if (this.events)
  39054. {
  39055. this.events.onRevived$dispatch(this);
  39056. }
  39057. return this;
  39058. },
  39059. /**
  39060. * Kills a Game Object. A killed Game Object has its `alive`, `exists` and `visible` properties all set to false.
  39061. *
  39062. * It will dispatch the `onKilled` event. You can listen to `events.onKilled` for the signal.
  39063. *
  39064. * Note that killing a Game Object is a way for you to quickly recycle it in an object pool,
  39065. * it doesn't destroy the object or free it up from memory.
  39066. *
  39067. * If you don't need this Game Object any more you should call `destroy` instead.
  39068. *
  39069. * @method
  39070. * @return {PIXI.DisplayObject} This instance.
  39071. */
  39072. kill: function () {
  39073. this.alive = false;
  39074. this.exists = false;
  39075. this.visible = false;
  39076. if (this.events)
  39077. {
  39078. this.events.onKilled$dispatch(this);
  39079. }
  39080. return this;
  39081. }
  39082. };
  39083. /**
  39084. * @author Richard Davey <rich@photonstorm.com>
  39085. * @copyright 2016 Photon Storm Ltd.
  39086. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  39087. */
  39088. /**
  39089. * The LoadTexture component manages the loading of a texture into the Game Object and the changing of frames.
  39090. *
  39091. * @class
  39092. */
  39093. Phaser.Component.LoadTexture = function () {};
  39094. Phaser.Component.LoadTexture.prototype = {
  39095. /**
  39096. * @property {boolean} customRender - Does this texture require a custom render call? (as set by BitmapData, Video, etc)
  39097. * @private
  39098. */
  39099. customRender: false,
  39100. /**
  39101. * @property {Phaser.Rectangle} _frame - Internal cache var.
  39102. * @private
  39103. */
  39104. _frame: null,
  39105. /**
  39106. * Changes the base texture the Game Object is using. The old texture is removed and the new one is referenced or fetched from the Cache.
  39107. *
  39108. * If your Game Object is using a frame from a texture atlas and you just wish to change to another frame, then see the `frame` or `frameName` properties instead.
  39109. *
  39110. * You should only use `loadTexture` if you want to replace the base texture entirely.
  39111. *
  39112. * Calling this method causes a WebGL texture update, so use sparingly or in low-intensity portions of your game, or if you know the new texture is already on the GPU.
  39113. *
  39114. * You can use the new const `Phaser.PENDING_ATLAS` as the texture key for any sprite.
  39115. * Doing this then sets the key to be the `frame` argument (the frame is set to zero).
  39116. *
  39117. * This allows you to create sprites using `load.image` during development, and then change them
  39118. * to use a Texture Atlas later in development by simply searching your code for 'PENDING_ATLAS'
  39119. * and swapping it to be the key of the atlas data.
  39120. *
  39121. * Note: You cannot use a RenderTexture as a texture for a TileSprite.
  39122. *
  39123. * @method
  39124. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache Image entry, or an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  39125. * @param {string|number} [frame] - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  39126. * @param {boolean} [stopAnimation=true] - If an animation is already playing on this Sprite you can choose to stop it or let it carry on playing.
  39127. */
  39128. loadTexture: function (key, frame, stopAnimation) {
  39129. if (key === Phaser.PENDING_ATLAS)
  39130. {
  39131. key = frame;
  39132. frame = 0;
  39133. }
  39134. else
  39135. {
  39136. frame = frame || 0;
  39137. }
  39138. if ((stopAnimation || stopAnimation === undefined) && this.animations)
  39139. {
  39140. this.animations.stop();
  39141. }
  39142. this.key = key;
  39143. this.customRender = false;
  39144. var cache = this.game.cache;
  39145. var setFrame = true;
  39146. var smoothed = !this.texture.baseTexture.scaleMode;
  39147. if (Phaser.RenderTexture && key instanceof Phaser.RenderTexture)
  39148. {
  39149. this.key = key.key;
  39150. this.setTexture(key);
  39151. }
  39152. else if (Phaser.BitmapData && key instanceof Phaser.BitmapData)
  39153. {
  39154. this.customRender = true;
  39155. this.setTexture(key.texture);
  39156. if (cache.hasFrameData(key.key, Phaser.Cache.BITMAPDATA))
  39157. {
  39158. setFrame = !this.animations.loadFrameData(cache.getFrameData(key.key, Phaser.Cache.BITMAPDATA), frame);
  39159. }
  39160. else
  39161. {
  39162. setFrame = !this.animations.loadFrameData(key.frameData, 0);
  39163. }
  39164. }
  39165. else if (Phaser.Video && key instanceof Phaser.Video)
  39166. {
  39167. this.customRender = true;
  39168. // This works from a reference, which probably isn't what we need here
  39169. var valid = key.texture.valid;
  39170. this.setTexture(key.texture);
  39171. this.setFrame(key.texture.frame.clone());
  39172. key.onChangeSource.add(this.resizeFrame, this);
  39173. this.texture.valid = valid;
  39174. }
  39175. else if (Phaser.Tilemap && key instanceof Phaser.TilemapLayer)
  39176. {
  39177. // this.customRender = true;
  39178. this.setTexture(PIXI.Texture.fromCanvas(key.canvas));
  39179. }
  39180. else if (key instanceof PIXI.Texture)
  39181. {
  39182. this.setTexture(key);
  39183. }
  39184. else
  39185. {
  39186. var img = cache.getImage(key, true);
  39187. this.key = img.key;
  39188. this.setTexture(new PIXI.Texture(img.base));
  39189. if (key === '__default')
  39190. {
  39191. this.texture.baseTexture.skipRender = true;
  39192. }
  39193. else
  39194. {
  39195. this.texture.baseTexture.skipRender = false;
  39196. }
  39197. setFrame = !this.animations.loadFrameData(img.frameData, frame);
  39198. }
  39199. if (setFrame)
  39200. {
  39201. this._frame = Phaser.Rectangle.clone(this.texture.frame);
  39202. }
  39203. if (!smoothed)
  39204. {
  39205. this.texture.baseTexture.scaleMode = 1;
  39206. }
  39207. },
  39208. /**
  39209. * Sets the texture frame the Game Object uses for rendering.
  39210. *
  39211. * This is primarily an internal method used by `loadTexture`, but is exposed for the use of plugins and custom classes.
  39212. *
  39213. * @method
  39214. * @param {Phaser.Frame} frame - The Frame to be used by the texture.
  39215. */
  39216. setFrame: function (frame) {
  39217. this._frame = frame;
  39218. this.texture.frame.x = frame.x;
  39219. this.texture.frame.y = frame.y;
  39220. this.texture.frame.width = frame.width;
  39221. this.texture.frame.height = frame.height;
  39222. this.texture.crop.x = frame.x;
  39223. this.texture.crop.y = frame.y;
  39224. this.texture.crop.width = frame.width;
  39225. this.texture.crop.height = frame.height;
  39226. if (frame.trimmed)
  39227. {
  39228. if (this.texture.trim)
  39229. {
  39230. this.texture.trim.x = frame.spriteSourceSizeX;
  39231. this.texture.trim.y = frame.spriteSourceSizeY;
  39232. this.texture.trim.width = frame.sourceSizeW;
  39233. this.texture.trim.height = frame.sourceSizeH;
  39234. }
  39235. else
  39236. {
  39237. this.texture.trim = { x: frame.spriteSourceSizeX, y: frame.spriteSourceSizeY, width: frame.sourceSizeW, height: frame.sourceSizeH };
  39238. }
  39239. this.texture.width = frame.sourceSizeW;
  39240. this.texture.height = frame.sourceSizeH;
  39241. this.texture.frame.width = frame.sourceSizeW;
  39242. this.texture.frame.height = frame.sourceSizeH;
  39243. }
  39244. else if (!frame.trimmed && this.texture.trim)
  39245. {
  39246. this.texture.trim = null;
  39247. }
  39248. if (frame.rotated)
  39249. {
  39250. this.texture.rotated = true;
  39251. }
  39252. if (this.cropRect)
  39253. {
  39254. this.updateCrop();
  39255. }
  39256. this.texture.requiresReTint = true;
  39257. this.texture._updateUvs();
  39258. if (this.tilingTexture)
  39259. {
  39260. this.refreshTexture = true;
  39261. }
  39262. },
  39263. /**
  39264. * Resizes the Frame dimensions that the Game Object uses for rendering.
  39265. *
  39266. * You shouldn't normally need to ever call this, but in the case of special texture types such as Video or BitmapData
  39267. * it can be useful to adjust the dimensions directly in this way.
  39268. *
  39269. * @method
  39270. * @param {object} parent - The parent texture object that caused the resize, i.e. a Phaser.Video object.
  39271. * @param {integer} width - The new width of the texture.
  39272. * @param {integer} height - The new height of the texture.
  39273. */
  39274. resizeFrame: function (parent, width, height) {
  39275. this.texture.frame.resize(width, height);
  39276. this.texture.setFrame(this.texture.frame);
  39277. },
  39278. /**
  39279. * Resets the texture frame dimensions that the Game Object uses for rendering.
  39280. *
  39281. * @method
  39282. */
  39283. resetFrame: function () {
  39284. if (this._frame)
  39285. {
  39286. this.setFrame(this._frame);
  39287. }
  39288. },
  39289. /**
  39290. * Gets or sets the current frame index of the texture being used to render this Game Object.
  39291. *
  39292. * To change the frame set `frame` to the index of the new frame in the sprite sheet you wish this Game Object to use,
  39293. * for example: `player.frame = 4`.
  39294. *
  39295. * If the frame index given doesn't exist it will revert to the first frame found in the texture.
  39296. *
  39297. * If you are using a texture atlas then you should use the `frameName` property instead.
  39298. *
  39299. * If you wish to fully replace the texture being used see `loadTexture`.
  39300. * @property {integer} frame
  39301. */
  39302. frame: {
  39303. get: function () {
  39304. return this.animations.frame;
  39305. },
  39306. set: function (value) {
  39307. this.animations.frame = value;
  39308. }
  39309. },
  39310. /**
  39311. * Gets or sets the current frame name of the texture being used to render this Game Object.
  39312. *
  39313. * To change the frame set `frameName` to the name of the new frame in the texture atlas you wish this Game Object to use,
  39314. * for example: `player.frameName = "idle"`.
  39315. *
  39316. * If the frame name given doesn't exist it will revert to the first frame found in the texture and throw a console warning.
  39317. *
  39318. * If you are using a sprite sheet then you should use the `frame` property instead.
  39319. *
  39320. * If you wish to fully replace the texture being used see `loadTexture`.
  39321. * @property {string} frameName
  39322. */
  39323. frameName: {
  39324. get: function () {
  39325. return this.animations.frameName;
  39326. },
  39327. set: function (value) {
  39328. this.animations.frameName = value;
  39329. }
  39330. }
  39331. };
  39332. /**
  39333. * @author Richard Davey <rich@photonstorm.com>
  39334. * @copyright 2016 Photon Storm Ltd.
  39335. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  39336. */
  39337. /**
  39338. * The Overlap component allows a Game Object to check if it overlaps with the bounds of another Game Object.
  39339. *
  39340. * @class
  39341. */
  39342. Phaser.Component.Overlap = function () {};
  39343. Phaser.Component.Overlap.prototype = {
  39344. /**
  39345. * Checks to see if the bounds of this Game Object overlaps with the bounds of the given Display Object,
  39346. * which can be a Sprite, Image, TileSprite or anything that extends those such as Button or provides a `getBounds` method and result.
  39347. *
  39348. * This check ignores the `hitArea` property if set and runs a `getBounds` comparison on both objects to determine the result.
  39349. *
  39350. * Therefore it's relatively expensive to use in large quantities, i.e. with lots of Sprites at a high frequency.
  39351. * It should be fine for low-volume testing where physics isn't required.
  39352. *
  39353. * @method
  39354. * @param {Phaser.Sprite|Phaser.Image|Phaser.TileSprite|Phaser.Button|PIXI.DisplayObject} displayObject - The display object to check against.
  39355. * @return {boolean} True if the bounds of this Game Object intersects at any point with the bounds of the given display object.
  39356. */
  39357. overlap: function (displayObject) {
  39358. return Phaser.Rectangle.intersects(this.getBounds(), displayObject.getBounds());
  39359. }
  39360. };
  39361. /**
  39362. * @author Richard Davey <rich@photonstorm.com>
  39363. * @copyright 2016 Photon Storm Ltd.
  39364. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  39365. */
  39366. /**
  39367. * The PhysicsBody component manages the Game Objects physics body and physics enabling.
  39368. * It also overrides the x and y properties, ensuring that any manual adjustment of them is reflected in the physics body itself.
  39369. *
  39370. * @class
  39371. */
  39372. Phaser.Component.PhysicsBody = function () {};
  39373. /**
  39374. * The PhysicsBody component preUpdate handler.
  39375. * Called automatically by the Game Object.
  39376. *
  39377. * @method
  39378. */
  39379. Phaser.Component.PhysicsBody.preUpdate = function () {
  39380. if (this.fresh && this.exists)
  39381. {
  39382. this.world.setTo(this.parent.position.x + this.position.x, this.parent.position.y + this.position.y);
  39383. this.worldTransform.tx = this.world.x;
  39384. this.worldTransform.ty = this.world.y;
  39385. this.previousPosition.set(this.world.x, this.world.y);
  39386. this.previousRotation = this.rotation;
  39387. if (this.body)
  39388. {
  39389. this.body.preUpdate();
  39390. }
  39391. this.fresh = false;
  39392. this.preUpdateChildren();
  39393. return false;
  39394. }
  39395. this.previousPosition.set(this.world.x, this.world.y);
  39396. this.previousRotation = this.rotation;
  39397. if (!this._exists || !this.parent.exists)
  39398. {
  39399. this.renderOrderID = -1;
  39400. return false;
  39401. }
  39402. return true;
  39403. };
  39404. /**
  39405. * The PhysicsBody component postUpdate handler.
  39406. * Called automatically by the Game Object.
  39407. *
  39408. * @method
  39409. */
  39410. Phaser.Component.PhysicsBody.postUpdate = function () {
  39411. if (this.exists && this.body)
  39412. {
  39413. this.body.postUpdate();
  39414. }
  39415. };
  39416. Phaser.Component.PhysicsBody.prototype = {
  39417. /**
  39418. * `body` is the Game Objects physics body. Once a Game Object is enabled for physics you access all associated
  39419. * properties and methods via it.
  39420. *
  39421. * By default Game Objects won't add themselves to any physics system and their `body` property will be `null`.
  39422. *
  39423. * To enable this Game Object for physics you need to call `game.physics.enable(object, system)` where `object` is this object
  39424. * and `system` is the Physics system you are using. If none is given it defaults to `Phaser.Physics.Arcade`.
  39425. *
  39426. * You can alternatively call `game.physics.arcade.enable(object)`, or add this Game Object to a physics enabled Group.
  39427. *
  39428. * Important: Enabling a Game Object for P2 or Ninja physics will automatically set its `anchor` property to 0.5,
  39429. * so the physics body is centered on the Game Object.
  39430. *
  39431. * If you need a different result then adjust or re-create the Body shape offsets manually or reset the anchor after enabling physics.
  39432. *
  39433. * @property {Phaser.Physics.Arcade.Body|Phaser.Physics.P2.Body|Phaser.Physics.Ninja.Body|null} body
  39434. * @default
  39435. */
  39436. body: null,
  39437. /**
  39438. * The position of the Game Object on the x axis relative to the local coordinates of the parent.
  39439. *
  39440. * @property {number} x
  39441. */
  39442. x: {
  39443. get: function () {
  39444. return this.position.x;
  39445. },
  39446. set: function (value) {
  39447. this.position.x = value;
  39448. if (this.body && !this.body.dirty)
  39449. {
  39450. this.body._reset = true;
  39451. }
  39452. }
  39453. },
  39454. /**
  39455. * The position of the Game Object on the y axis relative to the local coordinates of the parent.
  39456. *
  39457. * @property {number} y
  39458. */
  39459. y: {
  39460. get: function () {
  39461. return this.position.y;
  39462. },
  39463. set: function (value) {
  39464. this.position.y = value;
  39465. if (this.body && !this.body.dirty)
  39466. {
  39467. this.body._reset = true;
  39468. }
  39469. }
  39470. }
  39471. };
  39472. /**
  39473. * @author Richard Davey <rich@photonstorm.com>
  39474. * @copyright 2016 Photon Storm Ltd.
  39475. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  39476. */
  39477. /**
  39478. * The Reset component allows a Game Object to be reset and repositioned to a new location.
  39479. *
  39480. * @class
  39481. */
  39482. Phaser.Component.Reset = function () {};
  39483. /**
  39484. * Resets the Game Object.
  39485. *
  39486. * This moves the Game Object to the given x/y world coordinates and sets `fresh`, `exists`,
  39487. * `visible` and `renderable` to true.
  39488. *
  39489. * If this Game Object has the LifeSpan component it will also set `alive` to true and `health` to the given value.
  39490. *
  39491. * If this Game Object has a Physics Body it will reset the Body.
  39492. *
  39493. * @method
  39494. * @param {number} x - The x coordinate (in world space) to position the Game Object at.
  39495. * @param {number} y - The y coordinate (in world space) to position the Game Object at.
  39496. * @param {number} [health=1] - The health to give the Game Object if it has the Health component.
  39497. * @return {PIXI.DisplayObject} This instance.
  39498. */
  39499. Phaser.Component.Reset.prototype.reset = function (x, y, health) {
  39500. if (health === undefined) { health = 1; }
  39501. this.world.set(x, y);
  39502. this.position.set(x, y);
  39503. this.fresh = true;
  39504. this.exists = true;
  39505. this.visible = true;
  39506. this.renderable = true;
  39507. if (this.components.InWorld)
  39508. {
  39509. this._outOfBoundsFired = false;
  39510. }
  39511. if (this.components.LifeSpan)
  39512. {
  39513. this.alive = true;
  39514. this.health = health;
  39515. }
  39516. if (this.components.PhysicsBody)
  39517. {
  39518. if (this.body)
  39519. {
  39520. this.body.reset(x, y, false, false);
  39521. }
  39522. }
  39523. return this;
  39524. };
  39525. /**
  39526. * @author Richard Davey <rich@photonstorm.com>
  39527. * @copyright 2016 Photon Storm Ltd.
  39528. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  39529. */
  39530. /**
  39531. * The ScaleMinMax component allows a Game Object to limit how far it can be scaled by its parent.
  39532. *
  39533. * @class
  39534. */
  39535. Phaser.Component.ScaleMinMax = function () {};
  39536. Phaser.Component.ScaleMinMax.prototype = {
  39537. /**
  39538. * The callback that will apply any scale limiting to the worldTransform.
  39539. * @property {function} transformCallback
  39540. */
  39541. transformCallback: null,
  39542. /**
  39543. * The context under which `transformCallback` is called.
  39544. * @property {object} transformCallbackContext
  39545. */
  39546. transformCallbackContext: this,
  39547. /**
  39548. * The minimum scale this Game Object will scale down to.
  39549. *
  39550. * It allows you to prevent a parent from scaling this Game Object lower than the given value.
  39551. *
  39552. * Set it to `null` to remove the limit.
  39553. * @property {Phaser.Point} scaleMin
  39554. */
  39555. scaleMin: null,
  39556. /**
  39557. * The maximum scale this Game Object will scale up to.
  39558. *
  39559. * It allows you to prevent a parent from scaling this Game Object higher than the given value.
  39560. *
  39561. * Set it to `null` to remove the limit.
  39562. * @property {Phaser.Point} scaleMax
  39563. */
  39564. scaleMax: null,
  39565. /**
  39566. * Adjust scaling limits, if set, to this Game Object.
  39567. *
  39568. * @method
  39569. * @private
  39570. * @param {Phaser.Matrix} wt - The updated worldTransform matrix.
  39571. */
  39572. checkTransform: function (wt) {
  39573. if (this.scaleMin)
  39574. {
  39575. if (wt.a < this.scaleMin.x)
  39576. {
  39577. wt.a = this.scaleMin.x;
  39578. }
  39579. if (wt.d < this.scaleMin.y)
  39580. {
  39581. wt.d = this.scaleMin.y;
  39582. }
  39583. }
  39584. if (this.scaleMax)
  39585. {
  39586. if (wt.a > this.scaleMax.x)
  39587. {
  39588. wt.a = this.scaleMax.x;
  39589. }
  39590. if (wt.d > this.scaleMax.y)
  39591. {
  39592. wt.d = this.scaleMax.y;
  39593. }
  39594. }
  39595. },
  39596. /**
  39597. * Sets the scaleMin and scaleMax values. These values are used to limit how far this Game Object will scale based on its parent.
  39598. *
  39599. * For example if this Game Object has a `minScale` value of 1 and its parent has a `scale` value of 0.5, the 0.5 will be ignored
  39600. * and the scale value of 1 will be used, as the parents scale is lower than the minimum scale this Game Object should adhere to.
  39601. *
  39602. * By setting these values you can carefully control how Game Objects deal with responsive scaling.
  39603. *
  39604. * If only one parameter is given then that value will be used for both scaleMin and scaleMax:
  39605. * `setScaleMinMax(1)` = scaleMin.x, scaleMin.y, scaleMax.x and scaleMax.y all = 1
  39606. *
  39607. * If only two parameters are given the first is set as scaleMin.x and y and the second as scaleMax.x and y:
  39608. * `setScaleMinMax(0.5, 2)` = scaleMin.x and y = 0.5 and scaleMax.x and y = 2
  39609. *
  39610. * If you wish to set `scaleMin` with different values for x and y then either modify Game Object.scaleMin directly,
  39611. * or pass `null` for the `maxX` and `maxY` parameters.
  39612. *
  39613. * Call `setScaleMinMax(null)` to clear all previously set values.
  39614. *
  39615. * @method
  39616. * @param {number|null} minX - The minimum horizontal scale value this Game Object can scale down to.
  39617. * @param {number|null} minY - The minimum vertical scale value this Game Object can scale down to.
  39618. * @param {number|null} maxX - The maximum horizontal scale value this Game Object can scale up to.
  39619. * @param {number|null} maxY - The maximum vertical scale value this Game Object can scale up to.
  39620. */
  39621. setScaleMinMax: function (minX, minY, maxX, maxY) {
  39622. if (minY === undefined)
  39623. {
  39624. // 1 parameter, set all to it
  39625. minY = maxX = maxY = minX;
  39626. }
  39627. else if (maxX === undefined)
  39628. {
  39629. // 2 parameters, the first is min, the second max
  39630. maxX = maxY = minY;
  39631. minY = minX;
  39632. }
  39633. if (minX === null)
  39634. {
  39635. this.scaleMin = null;
  39636. }
  39637. else
  39638. {
  39639. if (this.scaleMin)
  39640. {
  39641. this.scaleMin.set(minX, minY);
  39642. }
  39643. else
  39644. {
  39645. this.scaleMin = new Phaser.Point(minX, minY);
  39646. }
  39647. }
  39648. if (maxX === null)
  39649. {
  39650. this.scaleMax = null;
  39651. }
  39652. else
  39653. {
  39654. if (this.scaleMax)
  39655. {
  39656. this.scaleMax.set(maxX, maxY);
  39657. }
  39658. else
  39659. {
  39660. this.scaleMax = new Phaser.Point(maxX, maxY);
  39661. }
  39662. }
  39663. if (this.scaleMin === null)
  39664. {
  39665. this.transformCallback = null;
  39666. }
  39667. else
  39668. {
  39669. this.transformCallback = this.checkTransform;
  39670. this.transformCallbackContext = this;
  39671. }
  39672. }
  39673. };
  39674. /**
  39675. * @author Richard Davey <rich@photonstorm.com>
  39676. * @copyright 2016 Photon Storm Ltd.
  39677. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  39678. */
  39679. /**
  39680. * The Smoothed component allows a Game Object to control anti-aliasing of an image based texture.
  39681. *
  39682. * @class
  39683. */
  39684. Phaser.Component.Smoothed = function () {};
  39685. Phaser.Component.Smoothed.prototype = {
  39686. /**
  39687. * Enable or disable texture smoothing for this Game Object.
  39688. *
  39689. * It only takes effect if the Game Object is using an image based texture.
  39690. *
  39691. * Smoothing is enabled by default.
  39692. *
  39693. * @property {boolean} smoothed
  39694. */
  39695. smoothed: {
  39696. get: function () {
  39697. return !this.texture.baseTexture.scaleMode;
  39698. },
  39699. set: function (value) {
  39700. if (value)
  39701. {
  39702. if (this.texture)
  39703. {
  39704. this.texture.baseTexture.scaleMode = 0;
  39705. }
  39706. }
  39707. else
  39708. {
  39709. if (this.texture)
  39710. {
  39711. this.texture.baseTexture.scaleMode = 1;
  39712. }
  39713. }
  39714. }
  39715. }
  39716. };
  39717. /**
  39718. * @author Richard Davey <rich@photonstorm.com>
  39719. * @copyright 2016 Photon Storm Ltd.
  39720. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  39721. */
  39722. /**
  39723. * The GameObjectFactory is a quick way to create many common game objects
  39724. * using {@linkcode Phaser.Game#add `game.add`}.
  39725. *
  39726. * Created objects are _automatically added_ to the appropriate Manager, World, or manually specified parent Group.
  39727. *
  39728. * @class Phaser.GameObjectFactory
  39729. * @constructor
  39730. * @param {Phaser.Game} game - A reference to the currently running game.
  39731. */
  39732. Phaser.GameObjectFactory = function (game) {
  39733. /**
  39734. * @property {Phaser.Game} game - A reference to the currently running Game.
  39735. * @protected
  39736. */
  39737. this.game = game;
  39738. /**
  39739. * @property {Phaser.World} world - A reference to the game world.
  39740. * @protected
  39741. */
  39742. this.world = this.game.world;
  39743. };
  39744. Phaser.GameObjectFactory.prototype = {
  39745. /**
  39746. * Adds an existing display object to the game world.
  39747. *
  39748. * @method Phaser.GameObjectFactory#existing
  39749. * @param {any} object - An instance of Phaser.Sprite, Phaser.Button or any other display object.
  39750. * @return {any} The child that was added to the World.
  39751. */
  39752. existing: function (object) {
  39753. return this.world.add(object);
  39754. },
  39755. /**
  39756. * Weapons provide the ability to easily create a bullet pool and manager.
  39757. *
  39758. * Weapons fire Phaser.Bullet objects, which are essentially Sprites with a few extra properties.
  39759. * The Bullets are enabled for Arcade Physics. They do not currently work with P2 Physics.
  39760. *
  39761. * The Bullets are created inside of `Weapon.bullets`, which is a Phaser.Group instance. Anything you
  39762. * can usually do with a Group, such as move it around the display list, iterate it, etc can be done
  39763. * to the bullets Group too.
  39764. *
  39765. * Bullets can have textures and even animations. You can control the speed at which they are fired,
  39766. * the firing rate, the firing angle, and even set things like gravity for them.
  39767. *
  39768. * @method Phaser.GameObjectFactory#weapon
  39769. * @param {integer} [quantity=1] - The quantity of bullets to seed the Weapon with. If -1 it will set the pool to automatically expand.
  39770. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - The image used as a texture by the bullets during rendering. If a string Phaser will get for an entry in the Image Cache. Or it can be an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  39771. * @param {string|number} [frame] - If a Texture Atlas or Sprite Sheet is used this allows you to specify the frame to be used by the bullets. Use either an integer for a Frame ID or a string for a frame name.
  39772. * @param {Phaser.Group} [group] - Optional Group to add the Weapon to. If not specified it will be added to the World group.
  39773. * @param {function} [bulletClass] - The Class of the bullets that are launched by this Weapon. See {@link Phaser.Weapon#bulletClass}
  39774. * @returns {Phaser.Weapon} A Weapon instance.
  39775. */
  39776. weapon: function (quantity, key, frame, group, bulletClass) {
  39777. var weapon = this.game.plugins.add(Phaser.Weapon);
  39778. if (bulletClass)
  39779. {
  39780. weapon.bulletClass = bulletClass;
  39781. }
  39782. weapon.createBullets(quantity, key, frame, group);
  39783. return weapon;
  39784. },
  39785. /**
  39786. * Create a new `Image` object.
  39787. *
  39788. * An Image is a light-weight object you can use to display anything that doesn't need physics or animation.
  39789. *
  39790. * It can still rotate, scale, crop and receive input events.
  39791. * This makes it perfect for logos, backgrounds, simple buttons and other non-Sprite graphics.
  39792. *
  39793. * @method Phaser.GameObjectFactory#image
  39794. * @param {number} [x=0] - The x coordinate of the Image. The coordinate is relative to any parent container this Image may be in.
  39795. * @param {number} [y=0] - The y coordinate of the Image. The coordinate is relative to any parent container this Image may be in.
  39796. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - The image used as a texture by this display object during rendering. If a string Phaser will get for an entry in the Image Cache. Or it can be an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  39797. * @param {string|number} [frame] - If a Texture Atlas or Sprite Sheet is used this allows you to specify the frame to be used. Use either an integer for a Frame ID or a string for a frame name.
  39798. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  39799. * @returns {Phaser.Image} The newly created Image object.
  39800. */
  39801. image: function (x, y, key, frame, group) {
  39802. if (group === undefined) { group = this.world; }
  39803. return group.add(new Phaser.Image(this.game, x, y, key, frame));
  39804. },
  39805. /**
  39806. * Create a new Sprite with specific position and sprite sheet key.
  39807. *
  39808. * At its most basic a Sprite consists of a set of coordinates and a texture that is used when rendered.
  39809. * They also contain additional properties allowing for physics motion (via Sprite.body), input handling (via Sprite.input),
  39810. * events (via Sprite.events), animation (via Sprite.animations), camera culling and more. Please see the Examples for use cases.
  39811. *
  39812. * @method Phaser.GameObjectFactory#sprite
  39813. * @param {number} [x=0] - The x coordinate of the sprite. The coordinate is relative to any parent container this sprite may be in.
  39814. * @param {number} [y=0] - The y coordinate of the sprite. The coordinate is relative to any parent container this sprite may be in.
  39815. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - The image used as a texture by this display object during rendering. If a string Phaser will get for an entry in the Image Cache. Or it can be an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  39816. * @param {string|number} [frame] - If a Texture Atlas or Sprite Sheet is used this allows you to specify the frame to be used. Use either an integer for a Frame ID or a string for a frame name.
  39817. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  39818. * @returns {Phaser.Sprite} The newly created Sprite object.
  39819. */
  39820. sprite: function (x, y, key, frame, group) {
  39821. if (group === undefined) { group = this.world; }
  39822. return group.create(x, y, key, frame);
  39823. },
  39824. /**
  39825. * Create a new Creature Animation object.
  39826. *
  39827. * Creature is a custom Game Object used in conjunction with the Creature Runtime libraries by Kestrel Moon Studios.
  39828. *
  39829. * It allows you to display animated Game Objects that were created with the [Creature Automated Animation Tool](http://www.kestrelmoon.com/creature/).
  39830. *
  39831. * Note 1: You can only use Phaser.Creature objects in WebGL enabled games. They do not work in Canvas mode games.
  39832. *
  39833. * Note 2: You must use a build of Phaser that includes the CreatureMeshBone.js runtime and gl-matrix.js, or have them
  39834. * loaded before your Phaser game boots.
  39835. *
  39836. * See the Phaser custom build process for more details.
  39837. *
  39838. * @method Phaser.GameObjectFactory#creature
  39839. * @param {number} [x=0] - The x coordinate of the creature. The coordinate is relative to any parent container this creature may be in.
  39840. * @param {number} [y=0] - The y coordinate of the creature. The coordinate is relative to any parent container this creature may be in.
  39841. * @param {string|PIXI.Texture} [key] - The image used as a texture by this creature object during rendering. If a string Phaser will get for an entry in the Image Cache. Or it can be an instance of a PIXI.Texture.
  39842. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  39843. * @returns {Phaser.Creature} The newly created Creature object.
  39844. */
  39845. creature: function (x, y, key, mesh, group) {
  39846. if (group === undefined) { group = this.world; }
  39847. var obj = new Phaser.Creature(this.game, x, y, key, mesh);
  39848. group.add(obj);
  39849. return obj;
  39850. },
  39851. /**
  39852. * Create a tween on a specific object.
  39853. *
  39854. * The object can be any JavaScript object or Phaser object such as Sprite.
  39855. *
  39856. * @method Phaser.GameObjectFactory#tween
  39857. * @param {object} object - Object the tween will be run on.
  39858. * @return {Phaser.Tween} The newly created Phaser.Tween object.
  39859. */
  39860. tween: function (object) {
  39861. return this.game.tweens.create(object);
  39862. },
  39863. /**
  39864. * A Group is a container for display objects that allows for fast pooling, recycling and collision checks.
  39865. *
  39866. * @method Phaser.GameObjectFactory#group
  39867. * @param {any} [parent] - The parent Group or DisplayObjectContainer that will hold this group, if any. If set to null the Group won't be added to the display list. If undefined it will be added to World by default.
  39868. * @param {string} [name='group'] - A name for this Group. Not used internally but useful for debugging.
  39869. * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World.
  39870. * @param {boolean} [enableBody=false] - If true all Sprites created with `Group.create` or `Group.createMulitple` will have a physics body created on them. Change the body type with physicsBodyType.
  39871. * @param {number} [physicsBodyType=0] - If enableBody is true this is the type of physics body that is created on new Sprites. Phaser.Physics.ARCADE, Phaser.Physics.P2, Phaser.Physics.NINJA, etc.
  39872. * @return {Phaser.Group} The newly created Group.
  39873. */
  39874. group: function (parent, name, addToStage, enableBody, physicsBodyType) {
  39875. return new Phaser.Group(this.game, parent, name, addToStage, enableBody, physicsBodyType);
  39876. },
  39877. /**
  39878. * A Group is a container for display objects that allows for fast pooling, recycling and collision checks.
  39879. *
  39880. * A Physics Group is the same as an ordinary Group except that is has enableBody turned on by default, so any Sprites it creates
  39881. * are automatically given a physics body.
  39882. *
  39883. * @method Phaser.GameObjectFactory#physicsGroup
  39884. * @param {number} [physicsBodyType=Phaser.Physics.ARCADE] - If enableBody is true this is the type of physics body that is created on new Sprites. Phaser.Physics.ARCADE, Phaser.Physics.P2JS, Phaser.Physics.NINJA, etc.
  39885. * @param {any} [parent] - The parent Group or DisplayObjectContainer that will hold this group, if any. If set to null the Group won't be added to the display list. If undefined it will be added to World by default.
  39886. * @param {string} [name='group'] - A name for this Group. Not used internally but useful for debugging.
  39887. * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World.
  39888. * @return {Phaser.Group} The newly created Group.
  39889. */
  39890. physicsGroup: function (physicsBodyType, parent, name, addToStage) {
  39891. return new Phaser.Group(this.game, parent, name, addToStage, true, physicsBodyType);
  39892. },
  39893. /**
  39894. * A SpriteBatch is a really fast version of a Phaser Group built solely for speed.
  39895. * Use when you need a lot of sprites or particles all sharing the same texture.
  39896. * The speed gains are specifically for WebGL. In Canvas mode you won't see any real difference.
  39897. *
  39898. * @method Phaser.GameObjectFactory#spriteBatch
  39899. * @param {Phaser.Group|null} parent - The parent Group that will hold this Sprite Batch. Set to `undefined` or `null` to add directly to game.world.
  39900. * @param {string} [name='group'] - A name for this Sprite Batch. Not used internally but useful for debugging.
  39901. * @param {boolean} [addToStage=false] - If set to true this Sprite Batch will be added directly to the Game.Stage instead of the parent.
  39902. * @return {Phaser.SpriteBatch} The newly created Sprite Batch.
  39903. */
  39904. spriteBatch: function (parent, name, addToStage) {
  39905. if (parent === undefined) { parent = null; }
  39906. if (name === undefined) { name = 'group'; }
  39907. if (addToStage === undefined) { addToStage = false; }
  39908. return new Phaser.SpriteBatch(this.game, parent, name, addToStage);
  39909. },
  39910. /**
  39911. * Creates a new Sound object.
  39912. *
  39913. * @method Phaser.GameObjectFactory#audio
  39914. * @param {string} key - The Game.cache key of the sound that this object will use.
  39915. * @param {number} [volume=1] - The volume at which the sound will be played.
  39916. * @param {boolean} [loop=false] - Whether or not the sound will loop.
  39917. * @param {boolean} [connect=true] - Controls if the created Sound object will connect to the master gainNode of the SoundManager when running under WebAudio.
  39918. * @return {Phaser.Sound} The newly created sound object.
  39919. */
  39920. audio: function (key, volume, loop, connect) {
  39921. return this.game.sound.add(key, volume, loop, connect);
  39922. },
  39923. /**
  39924. * Creates a new Sound object.
  39925. *
  39926. * @method Phaser.GameObjectFactory#sound
  39927. * @param {string} key - The Game.cache key of the sound that this object will use.
  39928. * @param {number} [volume=1] - The volume at which the sound will be played.
  39929. * @param {boolean} [loop=false] - Whether or not the sound will loop.
  39930. * @param {boolean} [connect=true] - Controls if the created Sound object will connect to the master gainNode of the SoundManager when running under WebAudio.
  39931. * @return {Phaser.Sound} The newly created sound object.
  39932. */
  39933. sound: function (key, volume, loop, connect) {
  39934. return this.game.sound.add(key, volume, loop, connect);
  39935. },
  39936. /**
  39937. * Creates a new AudioSprite object.
  39938. *
  39939. * @method Phaser.GameObjectFactory#audioSprite
  39940. * @param {string} key - The Game.cache key of the sound that this object will use.
  39941. * @return {Phaser.AudioSprite} The newly created AudioSprite object.
  39942. */
  39943. audioSprite: function (key) {
  39944. return this.game.sound.addSprite(key);
  39945. },
  39946. /**
  39947. * Creates a new TileSprite object.
  39948. *
  39949. * @method Phaser.GameObjectFactory#tileSprite
  39950. * @param {number} x - The x coordinate of the TileSprite. The coordinate is relative to any parent container this TileSprite may be in.
  39951. * @param {number} y - The y coordinate of the TileSprite. The coordinate is relative to any parent container this TileSprite may be in.
  39952. * @param {number} width - The width of the TileSprite.
  39953. * @param {number} height - The height of the TileSprite.
  39954. * @param {string|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the TileSprite during rendering. It can be a string which is a reference to the Phaser Image Cache entry, or an instance of a PIXI.Texture or BitmapData.
  39955. * @param {string|number} [frame] - If a Texture Atlas or Sprite Sheet is used this allows you to specify the frame to be used. Use either an integer for a Frame ID or a string for a frame name.
  39956. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  39957. * @return {Phaser.TileSprite} The newly created TileSprite object.
  39958. */
  39959. tileSprite: function (x, y, width, height, key, frame, group) {
  39960. if (group === undefined) { group = this.world; }
  39961. return group.add(new Phaser.TileSprite(this.game, x, y, width, height, key, frame));
  39962. },
  39963. /**
  39964. * Creates a new Rope object.
  39965. *
  39966. * Example usage: https://github.com/codevinsky/phaser-rope-demo/blob/master/dist/demo.js
  39967. *
  39968. * @method Phaser.GameObjectFactory#rope
  39969. * @param {number} [x=0] - The x coordinate of the Rope. The coordinate is relative to any parent container this rope may be in.
  39970. * @param {number} [y=0] - The y coordinate of the Rope. The coordinate is relative to any parent container this rope may be in.
  39971. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - The image used as a texture by this display object during rendering. If a string Phaser will get for an entry in the Image Cache. Or it can be an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  39972. * @param {string|number} [frame] - If a Texture Atlas or Sprite Sheet is used this allows you to specify the frame to be used. Use either an integer for a Frame ID or a string for a frame name.
  39973. * @param {Array} points - An array of {Phaser.Point}.
  39974. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  39975. * @return {Phaser.Rope} The newly created Rope object.
  39976. */
  39977. rope: function (x, y, key, frame, points, group) {
  39978. if (group === undefined) { group = this.world; }
  39979. return group.add(new Phaser.Rope(this.game, x, y, key, frame, points));
  39980. },
  39981. /**
  39982. * Creates a new Text object.
  39983. *
  39984. * @method Phaser.GameObjectFactory#text
  39985. * @param {number} [x=0] - The x coordinate of the Text. The coordinate is relative to any parent container this text may be in.
  39986. * @param {number} [y=0] - The y coordinate of the Text. The coordinate is relative to any parent container this text may be in.
  39987. * @param {string} [text=''] - The text string that will be displayed.
  39988. * @param {object} [style] - The style object containing style attributes like font, font size , etc.
  39989. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  39990. * @return {Phaser.Text} The newly created text object.
  39991. */
  39992. text: function (x, y, text, style, group) {
  39993. if (group === undefined) { group = this.world; }
  39994. return group.add(new Phaser.Text(this.game, x, y, text, style));
  39995. },
  39996. /**
  39997. * Creates a new Button object.
  39998. *
  39999. * @method Phaser.GameObjectFactory#button
  40000. * @param {number} [x=0] - The x coordinate of the Button. The coordinate is relative to any parent container this button may be in.
  40001. * @param {number} [y=0] - The y coordinate of the Button. The coordinate is relative to any parent container this button may be in.
  40002. * @param {string} [key] - The image key as defined in the Game.Cache to use as the texture for this button.
  40003. * @param {function} [callback] - The function to call when this button is pressed
  40004. * @param {object} [callbackContext] - The context in which the callback will be called (usually 'this')
  40005. * @param {string|number} [overFrame] - This is the frame or frameName that will be set when this button is in an over state. Give either a number to use a frame ID or a string for a frame name.
  40006. * @param {string|number} [outFrame] - This is the frame or frameName that will be set when this button is in an out state. Give either a number to use a frame ID or a string for a frame name.
  40007. * @param {string|number} [downFrame] - This is the frame or frameName that will be set when this button is in a down state. Give either a number to use a frame ID or a string for a frame name.
  40008. * @param {string|number} [upFrame] - This is the frame or frameName that will be set when this button is in an up state. Give either a number to use a frame ID or a string for a frame name.
  40009. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  40010. * @return {Phaser.Button} The newly created Button object.
  40011. */
  40012. button: function (x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame, group) {
  40013. if (group === undefined) { group = this.world; }
  40014. return group.add(new Phaser.Button(this.game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame));
  40015. },
  40016. /**
  40017. * Creates a new Graphics object.
  40018. *
  40019. * @method Phaser.GameObjectFactory#graphics
  40020. * @param {number} [x=0] - The x coordinate of the Graphic. The coordinate is relative to any parent container this object may be in.
  40021. * @param {number} [y=0] - The y coordinate of the Graphic. The coordinate is relative to any parent container this object may be in.
  40022. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  40023. * @return {Phaser.Graphics} The newly created graphics object.
  40024. */
  40025. graphics: function (x, y, group) {
  40026. if (group === undefined) { group = this.world; }
  40027. return group.add(new Phaser.Graphics(this.game, x, y));
  40028. },
  40029. /**
  40030. * Create a new Emitter.
  40031. *
  40032. * A particle emitter can be used for one-time explosions or for
  40033. * continuous effects like rain and fire. All it really does is launch Particle objects out
  40034. * at set intervals, and fixes their positions and velocities accordingly.
  40035. *
  40036. * @method Phaser.GameObjectFactory#emitter
  40037. * @param {number} [x=0] - The x coordinate within the Emitter that the particles are emitted from.
  40038. * @param {number} [y=0] - The y coordinate within the Emitter that the particles are emitted from.
  40039. * @param {number} [maxParticles=50] - The total number of particles in this emitter.
  40040. * @return {Phaser.Particles.Arcade.Emitter} The newly created emitter object.
  40041. */
  40042. emitter: function (x, y, maxParticles) {
  40043. return this.game.particles.add(new Phaser.Particles.Arcade.Emitter(this.game, x, y, maxParticles));
  40044. },
  40045. /**
  40046. * Create a new RetroFont object.
  40047. *
  40048. * A RetroFont can be used as a texture for an Image or Sprite and optionally add it to the Cache.
  40049. * A RetroFont uses a bitmap which contains fixed with characters for the font set. You use character spacing to define the set.
  40050. * If you need variable width character support then use a BitmapText object instead. The main difference between a RetroFont and a BitmapText
  40051. * is that a RetroFont creates a single texture that you can apply to a game object, where-as a BitmapText creates one Sprite object per letter of text.
  40052. * The texture can be asssigned or one or multiple images/sprites, but note that the text the RetroFont uses will be shared across them all,
  40053. * i.e. if you need each Image to have different text in it, then you need to create multiple RetroFont objects.
  40054. *
  40055. * @method Phaser.GameObjectFactory#retroFont
  40056. * @param {string} font - The key of the image in the Game.Cache that the RetroFont will use.
  40057. * @param {number} characterWidth - The width of each character in the font set.
  40058. * @param {number} characterHeight - The height of each character in the font set.
  40059. * @param {string} chars - The characters used in the font set, in display order. You can use the TEXT_SET consts for common font set arrangements.
  40060. * @param {number} charsPerRow - The number of characters per row in the font set.
  40061. * @param {number} [xSpacing=0] - If the characters in the font set have horizontal spacing between them set the required amount here.
  40062. * @param {number} [ySpacing=0] - If the characters in the font set have vertical spacing between them set the required amount here.
  40063. * @param {number} [xOffset=0] - If the font set doesn't start at the top left of the given image, specify the X coordinate offset here.
  40064. * @param {number} [yOffset=0] - If the font set doesn't start at the top left of the given image, specify the Y coordinate offset here.
  40065. * @return {Phaser.RetroFont} The newly created RetroFont texture which can be applied to an Image or Sprite.
  40066. */
  40067. retroFont: function (font, characterWidth, characterHeight, chars, charsPerRow, xSpacing, ySpacing, xOffset, yOffset) {
  40068. return new Phaser.RetroFont(this.game, font, characterWidth, characterHeight, chars, charsPerRow, xSpacing, ySpacing, xOffset, yOffset);
  40069. },
  40070. /**
  40071. * Create a new BitmapText object.
  40072. *
  40073. * BitmapText objects work by taking a texture file and an XML file that describes the font structure.
  40074. * It then generates a new Sprite object for each letter of the text, proportionally spaced out and aligned to
  40075. * match the font structure.
  40076. *
  40077. * BitmapText objects are less flexible than Text objects, in that they have less features such as shadows, fills and the ability
  40078. * to use Web Fonts. However you trade this flexibility for pure rendering speed. You can also create visually compelling BitmapTexts by
  40079. * processing the font texture in an image editor first, applying fills and any other effects required.
  40080. *
  40081. * To create multi-line text insert \r, \n or \r\n escape codes into the text string.
  40082. *
  40083. * To create a BitmapText data files you can use:
  40084. *
  40085. * BMFont (Windows, free): http://www.angelcode.com/products/bmfont/
  40086. * Glyph Designer (OS X, commercial): http://www.71squared.com/en/glyphdesigner
  40087. * Littera (Web-based, free): http://kvazars.com/littera/
  40088. *
  40089. * @method Phaser.GameObjectFactory#bitmapText
  40090. * @param {number} x - X coordinate to display the BitmapText object at.
  40091. * @param {number} y - Y coordinate to display the BitmapText object at.
  40092. * @param {string} font - The key of the BitmapText as stored in Phaser.Cache.
  40093. * @param {string} [text=''] - The text that will be rendered. This can also be set later via BitmapText.text.
  40094. * @param {number} [size=32] - The size the font will be rendered at in pixels.
  40095. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  40096. * @return {Phaser.BitmapText} The newly created bitmapText object.
  40097. */
  40098. bitmapText: function (x, y, font, text, size, group) {
  40099. if (group === undefined) { group = this.world; }
  40100. return group.add(new Phaser.BitmapText(this.game, x, y, font, text, size));
  40101. },
  40102. /**
  40103. * Creates a new Phaser.Tilemap object.
  40104. *
  40105. * The map can either be populated with data from a Tiled JSON file or from a CSV file.
  40106. * To do this pass the Cache key as the first parameter. When using Tiled data you need only provide the key.
  40107. * When using CSV data you must provide the key and the tileWidth and tileHeight parameters.
  40108. * If creating a blank tilemap to be populated later, you can either specify no parameters at all and then use `Tilemap.create` or pass the map and tile dimensions here.
  40109. * Note that all Tilemaps use a base tile size to calculate dimensions from, but that a TilemapLayer may have its own unique tile size that overrides it.
  40110. *
  40111. * @method Phaser.GameObjectFactory#tilemap
  40112. * @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map either leave this parameter out or pass `null`.
  40113. * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  40114. * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  40115. * @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  40116. * @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  40117. * @return {Phaser.Tilemap} The newly created tilemap object.
  40118. */
  40119. tilemap: function (key, tileWidth, tileHeight, width, height) {
  40120. return new Phaser.Tilemap(this.game, key, tileWidth, tileHeight, width, height);
  40121. },
  40122. /**
  40123. * A dynamic initially blank canvas to which images can be drawn.
  40124. *
  40125. * @method Phaser.GameObjectFactory#renderTexture
  40126. * @param {number} [width=100] - the width of the RenderTexture.
  40127. * @param {number} [height=100] - the height of the RenderTexture.
  40128. * @param {string} [key=''] - Asset key for the RenderTexture when stored in the Cache (see addToCache parameter).
  40129. * @param {boolean} [addToCache=false] - Should this RenderTexture be added to the Game.Cache? If so you can retrieve it with Cache.getTexture(key)
  40130. * @return {Phaser.RenderTexture} The newly created RenderTexture object.
  40131. */
  40132. renderTexture: function (width, height, key, addToCache) {
  40133. if (key === undefined || key === '') { key = this.game.rnd.uuid(); }
  40134. if (addToCache === undefined) { addToCache = false; }
  40135. var texture = new Phaser.RenderTexture(this.game, width, height, key);
  40136. if (addToCache)
  40137. {
  40138. this.game.cache.addRenderTexture(key, texture);
  40139. }
  40140. return texture;
  40141. },
  40142. /**
  40143. * Create a Video object.
  40144. *
  40145. * This will return a Phaser.Video object which you can pass to a Sprite to be used as a texture.
  40146. *
  40147. * @method Phaser.GameObjectFactory#video
  40148. * @param {string|null} [key=null] - The key of the video file in the Phaser.Cache that this Video object will play. Set to `null` or leave undefined if you wish to use a webcam as the source. See `startMediaStream` to start webcam capture.
  40149. * @param {string|null} [url=null] - If the video hasn't been loaded then you can provide a full URL to the file here (make sure to set key to null)
  40150. * @return {Phaser.Video} The newly created Video object.
  40151. */
  40152. video: function (key, url) {
  40153. return new Phaser.Video(this.game, key, url);
  40154. },
  40155. /**
  40156. * Create a BitmapData object.
  40157. *
  40158. * A BitmapData object can be manipulated and drawn to like a traditional Canvas object and used to texture Sprites.
  40159. *
  40160. * @method Phaser.GameObjectFactory#bitmapData
  40161. * @param {number} [width=256] - The width of the BitmapData in pixels.
  40162. * @param {number} [height=256] - The height of the BitmapData in pixels.
  40163. * @param {string} [key=''] - Asset key for the BitmapData when stored in the Cache (see addToCache parameter).
  40164. * @param {boolean} [addToCache=false] - Should this BitmapData be added to the Game.Cache? If so you can retrieve it with Cache.getBitmapData(key)
  40165. * @return {Phaser.BitmapData} The newly created BitmapData object.
  40166. */
  40167. bitmapData: function (width, height, key, addToCache) {
  40168. if (addToCache === undefined) { addToCache = false; }
  40169. if (key === undefined || key === '') { key = this.game.rnd.uuid(); }
  40170. var texture = new Phaser.BitmapData(this.game, key, width, height);
  40171. if (addToCache)
  40172. {
  40173. this.game.cache.addBitmapData(key, texture);
  40174. }
  40175. return texture;
  40176. },
  40177. /**
  40178. * A WebGL shader/filter that can be applied to Sprites.
  40179. *
  40180. * @method Phaser.GameObjectFactory#filter
  40181. * @param {string} filter - The name of the filter you wish to create, for example HueRotate or SineWave.
  40182. * @param {any} - Whatever parameters are needed to be passed to the filter init function.
  40183. * @return {Phaser.Filter} The newly created Phaser.Filter object.
  40184. */
  40185. filter: function (filter) {
  40186. var args = Array.prototype.slice.call(arguments, 1);
  40187. var filter = new Phaser.Filter[filter](this.game);
  40188. filter.init.apply(filter, args);
  40189. return filter;
  40190. },
  40191. /**
  40192. * Add a new Plugin into the PluginManager.
  40193. *
  40194. * The Plugin must have 2 properties: `game` and `parent`. Plugin.game is set to the game reference the PluginManager uses, and parent is set to the PluginManager.
  40195. *
  40196. * @method Phaser.GameObjectFactory#plugin
  40197. * @param {object|Phaser.Plugin} plugin - The Plugin to add into the PluginManager. This can be a function or an existing object.
  40198. * @param {...*} parameter - Additional parameters that will be passed to the Plugin.init method.
  40199. * @return {Phaser.Plugin} The Plugin that was added to the manager.
  40200. */
  40201. plugin: function (plugin) {
  40202. return this.game.plugins.add(plugin);
  40203. }
  40204. };
  40205. Phaser.GameObjectFactory.prototype.constructor = Phaser.GameObjectFactory;
  40206. /**
  40207. * @author Richard Davey <rich@photonstorm.com>
  40208. * @copyright 2016 Photon Storm Ltd.
  40209. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  40210. */
  40211. /**
  40212. * The GameObjectCreator is a quick way to create common game objects _without_ adding them to the game world.
  40213. * The object creator can be accessed with {@linkcode Phaser.Game#make `game.make`}.
  40214. *
  40215. * @class Phaser.GameObjectCreator
  40216. * @constructor
  40217. * @param {Phaser.Game} game - A reference to the currently running game.
  40218. */
  40219. Phaser.GameObjectCreator = function (game) {
  40220. /**
  40221. * @property {Phaser.Game} game - A reference to the currently running Game.
  40222. * @protected
  40223. */
  40224. this.game = game;
  40225. /**
  40226. * @property {Phaser.World} world - A reference to the game world.
  40227. * @protected
  40228. */
  40229. this.world = this.game.world;
  40230. };
  40231. Phaser.GameObjectCreator.prototype = {
  40232. /**
  40233. * Create a new Image object.
  40234. *
  40235. * An Image is a light-weight object you can use to display anything that doesn't need physics or animation.
  40236. * It can still rotate, scale, crop and receive input events. This makes it perfect for logos, backgrounds, simple buttons and other non-Sprite graphics.
  40237. *
  40238. * @method Phaser.GameObjectCreator#image
  40239. * @param {number} x - X position of the image.
  40240. * @param {number} y - Y position of the image.
  40241. * @param {string|Phaser.RenderTexture|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture.
  40242. * @param {string|number} [frame] - If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name.
  40243. * @returns {Phaser.Image} the newly created sprite object.
  40244. */
  40245. image: function (x, y, key, frame) {
  40246. return new Phaser.Image(this.game, x, y, key, frame);
  40247. },
  40248. /**
  40249. * Create a new Sprite with specific position and sprite sheet key.
  40250. *
  40251. * @method Phaser.GameObjectCreator#sprite
  40252. * @param {number} x - X position of the new sprite.
  40253. * @param {number} y - Y position of the new sprite.
  40254. * @param {string|Phaser.RenderTexture|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture.
  40255. * @param {string|number} [frame] - If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name.
  40256. * @returns {Phaser.Sprite} the newly created sprite object.
  40257. */
  40258. sprite: function (x, y, key, frame) {
  40259. return new Phaser.Sprite(this.game, x, y, key, frame);
  40260. },
  40261. /**
  40262. * Create a tween object for a specific object.
  40263. *
  40264. * The object can be any JavaScript object or Phaser object such as Sprite.
  40265. *
  40266. * @method Phaser.GameObjectCreator#tween
  40267. * @param {object} obj - Object the tween will be run on.
  40268. * @return {Phaser.Tween} The Tween object.
  40269. */
  40270. tween: function (obj) {
  40271. return new Phaser.Tween(obj, this.game, this.game.tweens);
  40272. },
  40273. /**
  40274. * A Group is a container for display objects that allows for fast pooling, recycling and collision checks.
  40275. *
  40276. * @method Phaser.GameObjectCreator#group
  40277. * @param {any} parent - The parent Group or DisplayObjectContainer that will hold this group, if any.
  40278. * @param {string} [name='group'] - A name for this Group. Not used internally but useful for debugging.
  40279. * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World.
  40280. * @param {boolean} [enableBody=false] - If true all Sprites created with `Group.create` or `Group.createMulitple` will have a physics body created on them. Change the body type with physicsBodyType.
  40281. * @param {number} [physicsBodyType=0] - If enableBody is true this is the type of physics body that is created on new Sprites. Phaser.Physics.ARCADE, Phaser.Physics.P2, Phaser.Physics.NINJA, etc.
  40282. * @return {Phaser.Group} The newly created Group.
  40283. */
  40284. group: function (parent, name, addToStage, enableBody, physicsBodyType) {
  40285. return new Phaser.Group(this.game, parent, name, addToStage, enableBody, physicsBodyType);
  40286. },
  40287. /**
  40288. * Create a new SpriteBatch.
  40289. *
  40290. * @method Phaser.GameObjectCreator#spriteBatch
  40291. * @param {any} parent - The parent Group or DisplayObjectContainer that will hold this group, if any.
  40292. * @param {string} [name='group'] - A name for this Group. Not used internally but useful for debugging.
  40293. * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World.
  40294. * @return {Phaser.SpriteBatch} The newly created group.
  40295. */
  40296. spriteBatch: function (parent, name, addToStage) {
  40297. if (name === undefined) { name = 'group'; }
  40298. if (addToStage === undefined) { addToStage = false; }
  40299. return new Phaser.SpriteBatch(this.game, parent, name, addToStage);
  40300. },
  40301. /**
  40302. * Creates a new Sound object.
  40303. *
  40304. * @method Phaser.GameObjectCreator#audio
  40305. * @param {string} key - The Game.cache key of the sound that this object will use.
  40306. * @param {number} [volume=1] - The volume at which the sound will be played.
  40307. * @param {boolean} [loop=false] - Whether or not the sound will loop.
  40308. * @param {boolean} [connect=true] - Controls if the created Sound object will connect to the master gainNode of the SoundManager when running under WebAudio.
  40309. * @return {Phaser.Sound} The newly created text object.
  40310. */
  40311. audio: function (key, volume, loop, connect) {
  40312. return this.game.sound.add(key, volume, loop, connect);
  40313. },
  40314. /**
  40315. * Creates a new AudioSprite object.
  40316. *
  40317. * @method Phaser.GameObjectCreator#audioSprite
  40318. * @param {string} key - The Game.cache key of the sound that this object will use.
  40319. * @return {Phaser.AudioSprite} The newly created AudioSprite object.
  40320. */
  40321. audioSprite: function (key) {
  40322. return this.game.sound.addSprite(key);
  40323. },
  40324. /**
  40325. * Creates a new Sound object.
  40326. *
  40327. * @method Phaser.GameObjectCreator#sound
  40328. * @param {string} key - The Game.cache key of the sound that this object will use.
  40329. * @param {number} [volume=1] - The volume at which the sound will be played.
  40330. * @param {boolean} [loop=false] - Whether or not the sound will loop.
  40331. * @param {boolean} [connect=true] - Controls if the created Sound object will connect to the master gainNode of the SoundManager when running under WebAudio.
  40332. * @return {Phaser.Sound} The newly created text object.
  40333. */
  40334. sound: function (key, volume, loop, connect) {
  40335. return this.game.sound.add(key, volume, loop, connect);
  40336. },
  40337. /**
  40338. * Creates a new TileSprite object.
  40339. *
  40340. * @method Phaser.GameObjectCreator#tileSprite
  40341. * @param {number} x - The x coordinate (in world space) to position the TileSprite at.
  40342. * @param {number} y - The y coordinate (in world space) to position the TileSprite at.
  40343. * @param {number} width - The width of the TileSprite.
  40344. * @param {number} height - The height of the TileSprite.
  40345. * @param {string|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the TileSprite during rendering. It can be a string which is a reference to the Phaser Image Cache entry, or an instance of a PIXI.Texture or BitmapData.
  40346. * @param {string|number} frame - If this TileSprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  40347. * @return {Phaser.TileSprite} The newly created tileSprite object.
  40348. */
  40349. tileSprite: function (x, y, width, height, key, frame) {
  40350. return new Phaser.TileSprite(this.game, x, y, width, height, key, frame);
  40351. },
  40352. /**
  40353. * Creates a new Rope object.
  40354. *
  40355. * @method Phaser.GameObjectCreator#rope
  40356. * @param {number} x - The x coordinate (in world space) to position the Rope at.
  40357. * @param {number} y - The y coordinate (in world space) to position the Rope at.
  40358. * @param {number} width - The width of the Rope.
  40359. * @param {number} height - The height of the Rope.
  40360. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the TileSprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture.
  40361. * @param {string|number} frame - If this Rope is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  40362. * @return {Phaser.Rope} The newly created rope object.
  40363. */
  40364. rope: function (x, y, key, frame, points) {
  40365. return new Phaser.Rope(this.game, x, y, key, frame, points);
  40366. },
  40367. /**
  40368. * Creates a new Text object.
  40369. *
  40370. * @method Phaser.GameObjectCreator#text
  40371. * @param {number} x - X position of the new text object.
  40372. * @param {number} y - Y position of the new text object.
  40373. * @param {string} text - The actual text that will be written.
  40374. * @param {object} style - The style object containing style attributes like font, font size , etc.
  40375. * @return {Phaser.Text} The newly created text object.
  40376. */
  40377. text: function (x, y, text, style) {
  40378. return new Phaser.Text(this.game, x, y, text, style);
  40379. },
  40380. /**
  40381. * Creates a new Button object.
  40382. *
  40383. * @method Phaser.GameObjectCreator#button
  40384. * @param {number} [x] X position of the new button object.
  40385. * @param {number} [y] Y position of the new button object.
  40386. * @param {string} [key] The image key as defined in the Game.Cache to use as the texture for this button.
  40387. * @param {function} [callback] The function to call when this button is pressed
  40388. * @param {object} [callbackContext] The context in which the callback will be called (usually 'this')
  40389. * @param {string|number} [overFrame] This is the frame or frameName that will be set when this button is in an over state. Give either a number to use a frame ID or a string for a frame name.
  40390. * @param {string|number} [outFrame] This is the frame or frameName that will be set when this button is in an out state. Give either a number to use a frame ID or a string for a frame name.
  40391. * @param {string|number} [downFrame] This is the frame or frameName that will be set when this button is in a down state. Give either a number to use a frame ID or a string for a frame name.
  40392. * @param {string|number} [upFrame] This is the frame or frameName that will be set when this button is in an up state. Give either a number to use a frame ID or a string for a frame name.
  40393. * @return {Phaser.Button} The newly created button object.
  40394. */
  40395. button: function (x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame) {
  40396. return new Phaser.Button(this.game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame);
  40397. },
  40398. /**
  40399. * Creates a new Graphics object.
  40400. *
  40401. * @method Phaser.GameObjectCreator#graphics
  40402. * @param {number} [x=0] - X position of the new graphics object.
  40403. * @param {number} [y=0] - Y position of the new graphics object.
  40404. * @return {Phaser.Graphics} The newly created graphics object.
  40405. */
  40406. graphics: function (x, y) {
  40407. return new Phaser.Graphics(this.game, x, y);
  40408. },
  40409. /**
  40410. * Creat a new Emitter.
  40411. *
  40412. * An Emitter is a lightweight particle emitter. It can be used for one-time explosions or for
  40413. * continuous effects like rain and fire. All it really does is launch Particle objects out
  40414. * at set intervals, and fixes their positions and velocities accorindgly.
  40415. *
  40416. * @method Phaser.GameObjectCreator#emitter
  40417. * @param {number} [x=0] - The x coordinate within the Emitter that the particles are emitted from.
  40418. * @param {number} [y=0] - The y coordinate within the Emitter that the particles are emitted from.
  40419. * @param {number} [maxParticles=50] - The total number of particles in this emitter.
  40420. * @return {Phaser.Emitter} The newly created emitter object.
  40421. */
  40422. emitter: function (x, y, maxParticles) {
  40423. return new Phaser.Particles.Arcade.Emitter(this.game, x, y, maxParticles);
  40424. },
  40425. /**
  40426. * Create a new RetroFont object.
  40427. *
  40428. * A RetroFont can be used as a texture for an Image or Sprite and optionally add it to the Cache.
  40429. * A RetroFont uses a bitmap which contains fixed with characters for the font set. You use character spacing to define the set.
  40430. * If you need variable width character support then use a BitmapText object instead. The main difference between a RetroFont and a BitmapText
  40431. * is that a RetroFont creates a single texture that you can apply to a game object, where-as a BitmapText creates one Sprite object per letter of text.
  40432. * The texture can be asssigned or one or multiple images/sprites, but note that the text the RetroFont uses will be shared across them all,
  40433. * i.e. if you need each Image to have different text in it, then you need to create multiple RetroFont objects.
  40434. *
  40435. * @method Phaser.GameObjectCreator#retroFont
  40436. * @param {string} font - The key of the image in the Game.Cache that the RetroFont will use.
  40437. * @param {number} characterWidth - The width of each character in the font set.
  40438. * @param {number} characterHeight - The height of each character in the font set.
  40439. * @param {string} chars - The characters used in the font set, in display order. You can use the TEXT_SET consts for common font set arrangements.
  40440. * @param {number} charsPerRow - The number of characters per row in the font set.
  40441. * @param {number} [xSpacing=0] - If the characters in the font set have horizontal spacing between them set the required amount here.
  40442. * @param {number} [ySpacing=0] - If the characters in the font set have vertical spacing between them set the required amount here.
  40443. * @param {number} [xOffset=0] - If the font set doesn't start at the top left of the given image, specify the X coordinate offset here.
  40444. * @param {number} [yOffset=0] - If the font set doesn't start at the top left of the given image, specify the Y coordinate offset here.
  40445. * @return {Phaser.RetroFont} The newly created RetroFont texture which can be applied to an Image or Sprite.
  40446. */
  40447. retroFont: function (font, characterWidth, characterHeight, chars, charsPerRow, xSpacing, ySpacing, xOffset, yOffset) {
  40448. return new Phaser.RetroFont(this.game, font, characterWidth, characterHeight, chars, charsPerRow, xSpacing, ySpacing, xOffset, yOffset);
  40449. },
  40450. /**
  40451. * Create a new BitmapText object.
  40452. *
  40453. * BitmapText objects work by taking a texture file and an XML file that describes the font structure.
  40454. * It then generates a new Sprite object for each letter of the text, proportionally spaced out and aligned to
  40455. * match the font structure.
  40456. *
  40457. * BitmapText objects are less flexible than Text objects, in that they have less features such as shadows, fills and the ability
  40458. * to use Web Fonts. However you trade this flexibility for pure rendering speed. You can also create visually compelling BitmapTexts by
  40459. * processing the font texture in an image editor first, applying fills and any other effects required.
  40460. *
  40461. * To create multi-line text insert \r, \n or \r\n escape codes into the text string.
  40462. *
  40463. * To create a BitmapText data files you can use:
  40464. *
  40465. * BMFont (Windows, free): http://www.angelcode.com/products/bmfont/
  40466. * Glyph Designer (OS X, commercial): http://www.71squared.com/en/glyphdesigner
  40467. * Littera (Web-based, free): http://kvazars.com/littera/
  40468. *
  40469. * @method Phaser.GameObjectCreator#bitmapText
  40470. * @param {number} x - X coordinate to display the BitmapText object at.
  40471. * @param {number} y - Y coordinate to display the BitmapText object at.
  40472. * @param {string} font - The key of the BitmapText as stored in Phaser.Cache.
  40473. * @param {string} [text=''] - The text that will be rendered. This can also be set later via BitmapText.text.
  40474. * @param {number} [size=32] - The size the font will be rendered at in pixels.
  40475. * @param {string} [align='left'] - The alignment of multi-line text. Has no effect if there is only one line of text.
  40476. * @return {Phaser.BitmapText} The newly created bitmapText object.
  40477. */
  40478. bitmapText: function (x, y, font, text, size, align) {
  40479. return new Phaser.BitmapText(this.game, x, y, font, text, size, align);
  40480. },
  40481. /**
  40482. * Creates a new Phaser.Tilemap object.
  40483. *
  40484. * The map can either be populated with data from a Tiled JSON file or from a CSV file.
  40485. * To do this pass the Cache key as the first parameter. When using Tiled data you need only provide the key.
  40486. * When using CSV data you must provide the key and the tileWidth and tileHeight parameters.
  40487. * If creating a blank tilemap to be populated later, you can either specify no parameters at all and then use `Tilemap.create` or pass the map and tile dimensions here.
  40488. * Note that all Tilemaps use a base tile size to calculate dimensions from, but that a TilemapLayer may have its own unique tile size that overrides it.
  40489. *
  40490. * @method Phaser.GameObjectCreator#tilemap
  40491. * @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map either leave this parameter out or pass `null`.
  40492. * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  40493. * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  40494. * @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  40495. * @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  40496. */
  40497. tilemap: function (key, tileWidth, tileHeight, width, height) {
  40498. return new Phaser.Tilemap(this.game, key, tileWidth, tileHeight, width, height);
  40499. },
  40500. /**
  40501. * A dynamic initially blank canvas to which images can be drawn.
  40502. *
  40503. * @method Phaser.GameObjectCreator#renderTexture
  40504. * @param {number} [width=100] - the width of the RenderTexture.
  40505. * @param {number} [height=100] - the height of the RenderTexture.
  40506. * @param {string} [key=''] - Asset key for the RenderTexture when stored in the Cache (see addToCache parameter).
  40507. * @param {boolean} [addToCache=false] - Should this RenderTexture be added to the Game.Cache? If so you can retrieve it with Cache.getTexture(key)
  40508. * @return {Phaser.RenderTexture} The newly created RenderTexture object.
  40509. */
  40510. renderTexture: function (width, height, key, addToCache) {
  40511. if (key === undefined || key === '') { key = this.game.rnd.uuid(); }
  40512. if (addToCache === undefined) { addToCache = false; }
  40513. var texture = new Phaser.RenderTexture(this.game, width, height, key);
  40514. if (addToCache)
  40515. {
  40516. this.game.cache.addRenderTexture(key, texture);
  40517. }
  40518. return texture;
  40519. },
  40520. /**
  40521. * Create a BitmpaData object.
  40522. *
  40523. * A BitmapData object can be manipulated and drawn to like a traditional Canvas object and used to texture Sprites.
  40524. *
  40525. * @method Phaser.GameObjectCreator#bitmapData
  40526. * @param {number} [width=256] - The width of the BitmapData in pixels.
  40527. * @param {number} [height=256] - The height of the BitmapData in pixels.
  40528. * @param {string} [key=''] - Asset key for the BitmapData when stored in the Cache (see addToCache parameter).
  40529. * @param {boolean} [addToCache=false] - Should this BitmapData be added to the Game.Cache? If so you can retrieve it with Cache.getBitmapData(key)
  40530. * @return {Phaser.BitmapData} The newly created BitmapData object.
  40531. */
  40532. bitmapData: function (width, height, key, addToCache) {
  40533. if (addToCache === undefined) { addToCache = false; }
  40534. if (key === undefined || key === '') { key = this.game.rnd.uuid(); }
  40535. var texture = new Phaser.BitmapData(this.game, key, width, height);
  40536. if (addToCache)
  40537. {
  40538. this.game.cache.addBitmapData(key, texture);
  40539. }
  40540. return texture;
  40541. },
  40542. /**
  40543. * A WebGL shader/filter that can be applied to Sprites.
  40544. *
  40545. * @method Phaser.GameObjectCreator#filter
  40546. * @param {string} filter - The name of the filter you wish to create, for example HueRotate or SineWave.
  40547. * @param {any} - Whatever parameters are needed to be passed to the filter init function.
  40548. * @return {Phaser.Filter} The newly created Phaser.Filter object.
  40549. */
  40550. filter: function (filter) {
  40551. var args = Array.prototype.slice.call(arguments, 1);
  40552. var filter = new Phaser.Filter[filter](this.game);
  40553. filter.init.apply(filter, args);
  40554. return filter;
  40555. }
  40556. };
  40557. Phaser.GameObjectCreator.prototype.constructor = Phaser.GameObjectCreator;
  40558. /**
  40559. * @author Richard Davey <rich@photonstorm.com>
  40560. * @copyright 2016 Photon Storm Ltd.
  40561. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  40562. */
  40563. /**
  40564. * Sprites are the lifeblood of your game, used for nearly everything visual.
  40565. *
  40566. * At its most basic a Sprite consists of a set of coordinates and a texture that is rendered to the canvas.
  40567. * They also contain additional properties allowing for physics motion (via Sprite.body), input handling (via Sprite.input),
  40568. * events (via Sprite.events), animation (via Sprite.animations), camera culling and more. Please see the Examples for use cases.
  40569. *
  40570. * @class Phaser.Sprite
  40571. * @constructor
  40572. * @extends PIXI.Sprite
  40573. * @extends Phaser.Component.Core
  40574. * @extends Phaser.Component.Angle
  40575. * @extends Phaser.Component.Animation
  40576. * @extends Phaser.Component.AutoCull
  40577. * @extends Phaser.Component.Bounds
  40578. * @extends Phaser.Component.BringToTop
  40579. * @extends Phaser.Component.Crop
  40580. * @extends Phaser.Component.Delta
  40581. * @extends Phaser.Component.Destroy
  40582. * @extends Phaser.Component.FixedToCamera
  40583. * @extends Phaser.Component.Health
  40584. * @extends Phaser.Component.InCamera
  40585. * @extends Phaser.Component.InputEnabled
  40586. * @extends Phaser.Component.InWorld
  40587. * @extends Phaser.Component.LifeSpan
  40588. * @extends Phaser.Component.LoadTexture
  40589. * @extends Phaser.Component.Overlap
  40590. * @extends Phaser.Component.PhysicsBody
  40591. * @extends Phaser.Component.Reset
  40592. * @extends Phaser.Component.ScaleMinMax
  40593. * @extends Phaser.Component.Smoothed
  40594. * @param {Phaser.Game} game - A reference to the currently running game.
  40595. * @param {number} x - The x coordinate (in world space) to position the Sprite at.
  40596. * @param {number} y - The y coordinate (in world space) to position the Sprite at.
  40597. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture. If this argument is omitted, the sprite will receive {@link Phaser.Cache.DEFAULT the default texture} (as if you had passed '__default'), but its `key` will remain empty.
  40598. * @param {string|number} frame - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  40599. */
  40600. Phaser.Sprite = function (game, x, y, key, frame) {
  40601. x = x || 0;
  40602. y = y || 0;
  40603. key = key || null;
  40604. frame = frame || null;
  40605. /**
  40606. * @property {number} type - The const type of this object.
  40607. * @readonly
  40608. */
  40609. this.type = Phaser.SPRITE;
  40610. /**
  40611. * @property {number} physicsType - The const physics body type of this object.
  40612. * @readonly
  40613. */
  40614. this.physicsType = Phaser.SPRITE;
  40615. PIXI.Sprite.call(this, Phaser.Cache.DEFAULT);
  40616. Phaser.Component.Core.init.call(this, game, x, y, key, frame);
  40617. };
  40618. Phaser.Sprite.prototype = Object.create(PIXI.Sprite.prototype);
  40619. Phaser.Sprite.prototype.constructor = Phaser.Sprite;
  40620. Phaser.Component.Core.install.call(Phaser.Sprite.prototype, [
  40621. 'Angle',
  40622. 'Animation',
  40623. 'AutoCull',
  40624. 'Bounds',
  40625. 'BringToTop',
  40626. 'Crop',
  40627. 'Delta',
  40628. 'Destroy',
  40629. 'FixedToCamera',
  40630. 'Health',
  40631. 'InCamera',
  40632. 'InputEnabled',
  40633. 'InWorld',
  40634. 'LifeSpan',
  40635. 'LoadTexture',
  40636. 'Overlap',
  40637. 'PhysicsBody',
  40638. 'Reset',
  40639. 'ScaleMinMax',
  40640. 'Smoothed'
  40641. ]);
  40642. Phaser.Sprite.prototype.preUpdatePhysics = Phaser.Component.PhysicsBody.preUpdate;
  40643. Phaser.Sprite.prototype.preUpdateLifeSpan = Phaser.Component.LifeSpan.preUpdate;
  40644. Phaser.Sprite.prototype.preUpdateInWorld = Phaser.Component.InWorld.preUpdate;
  40645. Phaser.Sprite.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
  40646. /**
  40647. * Automatically called by World.preUpdate.
  40648. *
  40649. * @method
  40650. * @memberof Phaser.Sprite
  40651. * @return {boolean} True if the Sprite was rendered, otherwise false.
  40652. */
  40653. Phaser.Sprite.prototype.preUpdate = function () {
  40654. if (!this.preUpdatePhysics() || !this.preUpdateLifeSpan() || !this.preUpdateInWorld())
  40655. {
  40656. return false;
  40657. }
  40658. return this.preUpdateCore();
  40659. };
  40660. /**
  40661. * @author Richard Davey <rich@photonstorm.com>
  40662. * @copyright 2016 Photon Storm Ltd.
  40663. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  40664. */
  40665. /**
  40666. * An Image is a light-weight object you can use to display anything that doesn't need health, physics, or complex position monitoring.
  40667. *
  40668. * It can still rotate, scale, crop and receive input events. This makes it perfect for logos, backgrounds, simple buttons and other non-Sprite graphics.
  40669. *
  40670. * @class Phaser.Image
  40671. * @extends PIXI.Sprite
  40672. * @extends Phaser.Component.Core
  40673. * @extends Phaser.Component.Angle
  40674. * @extends Phaser.Component.Animation
  40675. * @extends Phaser.Component.AutoCull
  40676. * @extends Phaser.Component.Bounds
  40677. * @extends Phaser.Component.BringToTop
  40678. * @extends Phaser.Component.Crop
  40679. * @extends Phaser.Component.Destroy
  40680. * @extends Phaser.Component.FixedToCamera
  40681. * @extends Phaser.Component.InputEnabled
  40682. * @extends Phaser.Component.LifeSpan
  40683. * @extends Phaser.Component.LoadTexture
  40684. * @extends Phaser.Component.Overlap
  40685. * @extends Phaser.Component.Reset
  40686. * @extends Phaser.Component.ScaleMinMax
  40687. * @extends Phaser.Component.Smoothed
  40688. * @constructor
  40689. * @param {Phaser.Game} game - A reference to the currently running game.
  40690. * @param {number} [x=0] - The x coordinate of the Image. The coordinate is relative to any parent container this Image may be in.
  40691. * @param {number} [y=0] - The y coordinate of the Image. The coordinate is relative to any parent container this Image may be in.
  40692. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} [key] - The texture used by the Image during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture, BitmapData or PIXI.Texture. If this argument is omitted, the image will receive {@link Phaser.Cache.DEFAULT the default texture} (as if you had passed '__default'), but its `key` will remain empty.
  40693. * @param {string|number} [frame] - If this Image is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  40694. */
  40695. Phaser.Image = function (game, x, y, key, frame) {
  40696. x = x || 0;
  40697. y = y || 0;
  40698. key = key || null;
  40699. frame = frame || null;
  40700. /**
  40701. * @property {number} type - The const type of this object.
  40702. * @readonly
  40703. */
  40704. this.type = Phaser.IMAGE;
  40705. PIXI.Sprite.call(this, Phaser.Cache.DEFAULT);
  40706. Phaser.Component.Core.init.call(this, game, x, y, key, frame);
  40707. };
  40708. Phaser.Image.prototype = Object.create(PIXI.Sprite.prototype);
  40709. Phaser.Image.prototype.constructor = Phaser.Image;
  40710. Phaser.Component.Core.install.call(Phaser.Image.prototype, [
  40711. 'Angle',
  40712. 'Animation',
  40713. 'AutoCull',
  40714. 'Bounds',
  40715. 'BringToTop',
  40716. 'Crop',
  40717. 'Destroy',
  40718. 'FixedToCamera',
  40719. 'InputEnabled',
  40720. 'LifeSpan',
  40721. 'LoadTexture',
  40722. 'Overlap',
  40723. 'Reset',
  40724. 'ScaleMinMax',
  40725. 'Smoothed'
  40726. ]);
  40727. Phaser.Image.prototype.preUpdateLifeSpan = Phaser.Component.LifeSpan.preUpdate;
  40728. Phaser.Image.prototype.preUpdateInWorld = Phaser.Component.InWorld.preUpdate;
  40729. Phaser.Image.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
  40730. /**
  40731. * Automatically called by World.preUpdate.
  40732. *
  40733. * @method Phaser.Image#preUpdate
  40734. * @memberof Phaser.Image
  40735. */
  40736. Phaser.Image.prototype.preUpdate = function() {
  40737. if (!this.preUpdateInWorld() || !this.preUpdateLifeSpan())
  40738. {
  40739. return false;
  40740. }
  40741. return this.preUpdateCore();
  40742. };
  40743. /**
  40744. * @author Richard Davey <rich@photonstorm.com>
  40745. * @copyright 2016 Photon Storm Ltd.
  40746. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  40747. */
  40748. /**
  40749. * Create a new `Button` object. A Button is a special type of Sprite that is set-up to handle Pointer events automatically.
  40750. *
  40751. * The four states a Button responds to are:
  40752. *
  40753. * * 'Over' - when the Pointer moves over the Button. This is also commonly known as 'hover'.
  40754. * * 'Out' - when the Pointer that was previously over the Button moves out of it.
  40755. * * 'Down' - when the Pointer is pressed down on the Button. I.e. touched on a touch enabled device or clicked with the mouse.
  40756. * * 'Up' - when the Pointer that was pressed down on the Button is released again.
  40757. *
  40758. * A different texture/frame and activation sound can be specified for any of the states.
  40759. *
  40760. * Frames can be specified as either an integer (the frame ID) or a string (the frame name); the same values that can be used with a Sprite constructor.
  40761. *
  40762. * @class Phaser.Button
  40763. * @constructor
  40764. * @extends Phaser.Image
  40765. * @param {Phaser.Game} game Current game instance.
  40766. * @param {number} [x=0] - X position of the Button.
  40767. * @param {number} [y=0] - Y position of the Button.
  40768. * @param {string} [key] - The image key (in the Game.Cache) to use as the texture for this Button.
  40769. * @param {function} [callback] - The function to call when this Button is pressed, receiving `this` (the Button), `pointer`, and `isOver` (see {@link Phaser.Events#onInputUp}.)
  40770. * @param {object} [callbackContext] - The context in which the callback will be called (usually 'this').
  40771. * @param {string|integer} [overFrame] - The frame / frameName when the button is in the Over state.
  40772. * @param {string|integer} [outFrame] - The frame / frameName when the button is in the Out state.
  40773. * @param {string|integer} [downFrame] - The frame / frameName when the button is in the Down state.
  40774. * @param {string|integer} [upFrame] - The frame / frameName when the button is in the Up state.
  40775. */
  40776. Phaser.Button = function (game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame) {
  40777. x = x || 0;
  40778. y = y || 0;
  40779. key = key || null;
  40780. callback = callback || null;
  40781. callbackContext = callbackContext || this;
  40782. Phaser.Image.call(this, game, x, y, key, outFrame);
  40783. /**
  40784. * The Phaser Object Type.
  40785. * @property {number} type
  40786. * @readonly
  40787. */
  40788. this.type = Phaser.BUTTON;
  40789. /**
  40790. * @property {number} physicsType - The const physics body type of this object.
  40791. * @readonly
  40792. */
  40793. this.physicsType = Phaser.SPRITE;
  40794. /**
  40795. * The name or ID of the Over state frame.
  40796. * @property {string|integer} onOverFrame
  40797. * @private
  40798. */
  40799. this._onOverFrame = null;
  40800. /**
  40801. * The name or ID of the Out state frame.
  40802. * @property {string|integer} onOutFrame
  40803. * @private
  40804. */
  40805. this._onOutFrame = null;
  40806. /**
  40807. * The name or ID of the Down state frame.
  40808. * @property {string|integer} onDownFrame
  40809. * @private
  40810. */
  40811. this._onDownFrame = null;
  40812. /**
  40813. * The name or ID of the Up state frame.
  40814. * @property {string|integer} onUpFrame
  40815. * @private
  40816. */
  40817. this._onUpFrame = null;
  40818. /**
  40819. * The Sound to be played when this Buttons Over state is activated.
  40820. * @property {Phaser.Sound|Phaser.AudioSprite|null} onOverSound
  40821. * @readonly
  40822. */
  40823. this.onOverSound = null;
  40824. /**
  40825. * The Sound to be played when this Buttons Out state is activated.
  40826. * @property {Phaser.Sound|Phaser.AudioSprite|null} onOutSound
  40827. * @readonly
  40828. */
  40829. this.onOutSound = null;
  40830. /**
  40831. * The Sound to be played when this Buttons Down state is activated.
  40832. * @property {Phaser.Sound|Phaser.AudioSprite|null} onDownSound
  40833. * @readonly
  40834. */
  40835. this.onDownSound = null;
  40836. /**
  40837. * The Sound to be played when this Buttons Up state is activated.
  40838. * @property {Phaser.Sound|Phaser.AudioSprite|null} onUpSound
  40839. * @readonly
  40840. */
  40841. this.onUpSound = null;
  40842. /**
  40843. * The Sound Marker used in conjunction with the onOverSound.
  40844. * @property {string} onOverSoundMarker
  40845. * @readonly
  40846. */
  40847. this.onOverSoundMarker = '';
  40848. /**
  40849. * The Sound Marker used in conjunction with the onOutSound.
  40850. * @property {string} onOutSoundMarker
  40851. * @readonly
  40852. */
  40853. this.onOutSoundMarker = '';
  40854. /**
  40855. * The Sound Marker used in conjunction with the onDownSound.
  40856. * @property {string} onDownSoundMarker
  40857. * @readonly
  40858. */
  40859. this.onDownSoundMarker = '';
  40860. /**
  40861. * The Sound Marker used in conjunction with the onUpSound.
  40862. * @property {string} onUpSoundMarker
  40863. * @readonly
  40864. */
  40865. this.onUpSoundMarker = '';
  40866. /**
  40867. * The Signal (or event) dispatched when this Button is in an Over state.
  40868. * @property {Phaser.Signal} onInputOver
  40869. */
  40870. this.onInputOver = new Phaser.Signal();
  40871. /**
  40872. * The Signal (or event) dispatched when this Button is in an Out state.
  40873. * @property {Phaser.Signal} onInputOut
  40874. */
  40875. this.onInputOut = new Phaser.Signal();
  40876. /**
  40877. * The Signal (or event) dispatched when this Button is in an Down state.
  40878. * @property {Phaser.Signal} onInputDown
  40879. */
  40880. this.onInputDown = new Phaser.Signal();
  40881. /**
  40882. * The Signal (or event) dispatched when this Button is in an Up state.
  40883. * @property {Phaser.Signal} onInputUp
  40884. */
  40885. this.onInputUp = new Phaser.Signal();
  40886. /**
  40887. * If true then onOver events (such as onOverSound) will only be triggered if the Pointer object causing them was the Mouse Pointer.
  40888. * The frame will still be changed as applicable.
  40889. *
  40890. * @property {boolean} onOverMouseOnly
  40891. * @default
  40892. */
  40893. this.onOverMouseOnly = true;
  40894. /**
  40895. * Suppress the over event if a pointer was just released and it matches the given {@link Phaser.PointerModer pointer mode bitmask}.
  40896. *
  40897. * This behavior was introduced in Phaser 2.3.1; this property is a soft-revert of the change.
  40898. *
  40899. * @property {Phaser.PointerMode?} justReleasedPreventsOver=ACTIVE_CURSOR
  40900. */
  40901. this.justReleasedPreventsOver = Phaser.PointerMode.TOUCH;
  40902. /**
  40903. * When true the the texture frame will not be automatically switched on up/down/over/out events.
  40904. * @property {boolean} freezeFrames
  40905. * @default
  40906. */
  40907. this.freezeFrames = false;
  40908. /**
  40909. * When the Button is touched / clicked and then released you can force it to enter a state of "out" instead of "up".
  40910. *
  40911. * This can also accept a {@link Phaser.PointerModer pointer mode bitmask} for more refined control.
  40912. *
  40913. * @property {boolean|Phaser.PointerMode} forceOut=false
  40914. * @default
  40915. */
  40916. this.forceOut = false;
  40917. this.inputEnabled = true;
  40918. this.input.start(0, true);
  40919. this.input.useHandCursor = true;
  40920. this.setFrames(overFrame, outFrame, downFrame, upFrame);
  40921. if (callback !== null)
  40922. {
  40923. this.onInputUp.add(callback, callbackContext);
  40924. }
  40925. // Redirect the input events to here so we can handle animation updates, etc
  40926. this.events.onInputOver.add(this.onInputOverHandler, this);
  40927. this.events.onInputOut.add(this.onInputOutHandler, this);
  40928. this.events.onInputDown.add(this.onInputDownHandler, this);
  40929. this.events.onInputUp.add(this.onInputUpHandler, this);
  40930. };
  40931. Phaser.Button.prototype = Object.create(Phaser.Image.prototype);
  40932. Phaser.Button.prototype.constructor = Phaser.Button;
  40933. // State constants; local only. These are tied to property names in Phaser.Button.
  40934. var STATE_OVER = 'Over';
  40935. var STATE_OUT = 'Out';
  40936. var STATE_DOWN = 'Down';
  40937. var STATE_UP = 'Up';
  40938. /**
  40939. * Clears all of the frames set on this Button.
  40940. *
  40941. * @method Phaser.Button#clearFrames
  40942. */
  40943. Phaser.Button.prototype.clearFrames = function () {
  40944. this.setFrames(null, null, null, null);
  40945. };
  40946. /**
  40947. * Set the frame name/ID for the given state.
  40948. *
  40949. * @method Phaser.Button#setStateFrame
  40950. * @private
  40951. * @param {object} state - See `STATE_*`
  40952. * @param {number|string} frame - The number or string representing the frame.
  40953. * @param {boolean} switchImmediately - Immediately switch to the frame if it was set - and this is true.
  40954. */
  40955. Phaser.Button.prototype.setStateFrame = function (state, frame, switchImmediately)
  40956. {
  40957. var frameKey = '_on' + state + 'Frame';
  40958. if (frame !== null) // not null or undefined
  40959. {
  40960. this[frameKey] = frame;
  40961. if (switchImmediately)
  40962. {
  40963. this.changeStateFrame(state);
  40964. }
  40965. }
  40966. else
  40967. {
  40968. this[frameKey] = null;
  40969. }
  40970. };
  40971. /**
  40972. * Change the frame to that of the given state, _if_ the state has a frame assigned _and_ if the frames are not currently "frozen".
  40973. *
  40974. * @method Phaser.Button#changeStateFrame
  40975. * @private
  40976. * @param {object} state - See `STATE_*`
  40977. * @return {boolean} True only if the frame was assigned a value, possibly the same one it already had.
  40978. */
  40979. Phaser.Button.prototype.changeStateFrame = function (state) {
  40980. if (this.freezeFrames)
  40981. {
  40982. return false;
  40983. }
  40984. var frameKey = '_on' + state + 'Frame';
  40985. var frame = this[frameKey];
  40986. if (typeof frame === 'string')
  40987. {
  40988. this.frameName = frame;
  40989. return true;
  40990. }
  40991. else if (typeof frame === 'number')
  40992. {
  40993. this.frame = frame;
  40994. return true;
  40995. }
  40996. else
  40997. {
  40998. return false;
  40999. }
  41000. };
  41001. /**
  41002. * Used to manually set the frames that will be used for the different states of the Button.
  41003. *
  41004. * Frames can be specified as either an integer (the frame ID) or a string (the frame name); these are the same values that can be used with a Sprite constructor.
  41005. *
  41006. * @method Phaser.Button#setFrames
  41007. * @public
  41008. * @param {string|integer} [overFrame] - The frame / frameName when the button is in the Over state.
  41009. * @param {string|integer} [outFrame] - The frame / frameName when the button is in the Out state.
  41010. * @param {string|integer} [downFrame] - The frame / frameName when the button is in the Down state.
  41011. * @param {string|integer} [upFrame] - The frame / frameName when the button is in the Up state.
  41012. */
  41013. Phaser.Button.prototype.setFrames = function (overFrame, outFrame, downFrame, upFrame) {
  41014. this.setStateFrame(STATE_OVER, overFrame, this.input.pointerOver());
  41015. this.setStateFrame(STATE_OUT, outFrame, !this.input.pointerOver());
  41016. this.setStateFrame(STATE_DOWN, downFrame, this.input.pointerDown());
  41017. this.setStateFrame(STATE_UP, upFrame, this.input.pointerUp());
  41018. };
  41019. /**
  41020. * Set the sound/marker for the given state.
  41021. *
  41022. * @method Phaser.Button#setStateSound
  41023. * @private
  41024. * @param {object} state - See `STATE_*`
  41025. * @param {Phaser.Sound|Phaser.AudioSprite} [sound] - Sound.
  41026. * @param {string} [marker=''] - Sound marker.
  41027. */
  41028. Phaser.Button.prototype.setStateSound = function (state, sound, marker) {
  41029. var soundKey = 'on' + state + 'Sound';
  41030. var markerKey = 'on' + state + 'SoundMarker';
  41031. if (sound instanceof Phaser.Sound || sound instanceof Phaser.AudioSprite)
  41032. {
  41033. this[soundKey] = sound;
  41034. this[markerKey] = typeof marker === 'string' ? marker : '';
  41035. }
  41036. else
  41037. {
  41038. this[soundKey] = null;
  41039. this[markerKey] = '';
  41040. }
  41041. };
  41042. /**
  41043. * Play the sound for the given state, _if_ the state has a sound assigned.
  41044. *
  41045. * @method Phaser.Button#playStateSound
  41046. * @private
  41047. * @param {object} state - See `STATE_*`
  41048. * @return {boolean} True only if a sound was played.
  41049. */
  41050. Phaser.Button.prototype.playStateSound = function (state) {
  41051. var soundKey = 'on' + state + 'Sound';
  41052. var sound = this[soundKey];
  41053. if (sound)
  41054. {
  41055. var markerKey = 'on' + state + 'SoundMarker';
  41056. var marker = this[markerKey];
  41057. sound.play(marker);
  41058. return true;
  41059. }
  41060. else
  41061. {
  41062. return false;
  41063. }
  41064. };
  41065. /**
  41066. * Sets the sounds to be played whenever this Button is interacted with. Sounds can be either full Sound objects, or markers pointing to a section of a Sound object.
  41067. * The most common forms of sounds are 'hover' effects and 'click' effects, which is why the order of the parameters is overSound then downSound.
  41068. *
  41069. * Call this function with no parameters to reset all sounds on this Button.
  41070. *
  41071. * @method Phaser.Button#setSounds
  41072. * @public
  41073. * @param {Phaser.Sound|Phaser.AudioSprite} [overSound] - Over Button Sound.
  41074. * @param {string} [overMarker] - Over Button Sound Marker.
  41075. * @param {Phaser.Sound|Phaser.AudioSprite} [downSound] - Down Button Sound.
  41076. * @param {string} [downMarker] - Down Button Sound Marker.
  41077. * @param {Phaser.Sound|Phaser.AudioSprite} [outSound] - Out Button Sound.
  41078. * @param {string} [outMarker] - Out Button Sound Marker.
  41079. * @param {Phaser.Sound|Phaser.AudioSprite} [upSound] - Up Button Sound.
  41080. * @param {string} [upMarker] - Up Button Sound Marker.
  41081. */
  41082. Phaser.Button.prototype.setSounds = function (overSound, overMarker, downSound, downMarker, outSound, outMarker, upSound, upMarker) {
  41083. this.setStateSound(STATE_OVER, overSound, overMarker);
  41084. this.setStateSound(STATE_OUT, outSound, outMarker);
  41085. this.setStateSound(STATE_DOWN, downSound, downMarker);
  41086. this.setStateSound(STATE_UP, upSound, upMarker);
  41087. };
  41088. /**
  41089. * The Sound to be played when a Pointer moves over this Button.
  41090. *
  41091. * @method Phaser.Button#setOverSound
  41092. * @public
  41093. * @param {Phaser.Sound|Phaser.AudioSprite} sound - The Sound that will be played.
  41094. * @param {string} [marker] - A Sound Marker that will be used in the playback.
  41095. */
  41096. Phaser.Button.prototype.setOverSound = function (sound, marker) {
  41097. this.setStateSound(STATE_OVER, sound, marker);
  41098. };
  41099. /**
  41100. * The Sound to be played when a Pointer moves out of this Button.
  41101. *
  41102. * @method Phaser.Button#setOutSound
  41103. * @public
  41104. * @param {Phaser.Sound|Phaser.AudioSprite} sound - The Sound that will be played.
  41105. * @param {string} [marker] - A Sound Marker that will be used in the playback.
  41106. */
  41107. Phaser.Button.prototype.setOutSound = function (sound, marker) {
  41108. this.setStateSound(STATE_OUT, sound, marker);
  41109. };
  41110. /**
  41111. * The Sound to be played when a Pointer presses down on this Button.
  41112. *
  41113. * @method Phaser.Button#setDownSound
  41114. * @public
  41115. * @param {Phaser.Sound|Phaser.AudioSprite} sound - The Sound that will be played.
  41116. * @param {string} [marker] - A Sound Marker that will be used in the playback.
  41117. */
  41118. Phaser.Button.prototype.setDownSound = function (sound, marker) {
  41119. this.setStateSound(STATE_DOWN, sound, marker);
  41120. };
  41121. /**
  41122. * The Sound to be played when a Pointer has pressed down and is released from this Button.
  41123. *
  41124. * @method Phaser.Button#setUpSound
  41125. * @public
  41126. * @param {Phaser.Sound|Phaser.AudioSprite} sound - The Sound that will be played.
  41127. * @param {string} [marker] - A Sound Marker that will be used in the playback.
  41128. */
  41129. Phaser.Button.prototype.setUpSound = function (sound, marker) {
  41130. this.setStateSound(STATE_UP, sound, marker);
  41131. };
  41132. /**
  41133. * Internal function that handles input events.
  41134. *
  41135. * @method Phaser.Button#onInputOverHandler
  41136. * @protected
  41137. * @param {Phaser.Button} sprite - The Button that the event occurred on.
  41138. * @param {Phaser.Pointer} pointer - The Pointer that activated the Button.
  41139. */
  41140. Phaser.Button.prototype.onInputOverHandler = function (sprite, pointer) {
  41141. if (pointer.justReleased() &&
  41142. (this.justReleasedPreventsOver & pointer.pointerMode) === pointer.pointerMode)
  41143. {
  41144. // If the Pointer was only just released then we don't fire an over event
  41145. return;
  41146. }
  41147. this.changeStateFrame(STATE_OVER);
  41148. if (this.onOverMouseOnly && !pointer.isMouse)
  41149. {
  41150. return;
  41151. }
  41152. this.playStateSound(STATE_OVER);
  41153. if (this.onInputOver)
  41154. {
  41155. this.onInputOver.dispatch(this, pointer);
  41156. }
  41157. };
  41158. /**
  41159. * Internal function that handles input events.
  41160. *
  41161. * @method Phaser.Button#onInputOutHandler
  41162. * @protected
  41163. * @param {Phaser.Button} sprite - The Button that the event occurred on.
  41164. * @param {Phaser.Pointer} pointer - The Pointer that activated the Button.
  41165. */
  41166. Phaser.Button.prototype.onInputOutHandler = function (sprite, pointer) {
  41167. this.changeStateFrame(STATE_OUT);
  41168. this.playStateSound(STATE_OUT);
  41169. if (this.onInputOut)
  41170. {
  41171. this.onInputOut.dispatch(this, pointer);
  41172. }
  41173. };
  41174. /**
  41175. * Internal function that handles input events.
  41176. *
  41177. * @method Phaser.Button#onInputDownHandler
  41178. * @protected
  41179. * @param {Phaser.Button} sprite - The Button that the event occurred on.
  41180. * @param {Phaser.Pointer} pointer - The Pointer that activated the Button.
  41181. */
  41182. Phaser.Button.prototype.onInputDownHandler = function (sprite, pointer) {
  41183. this.changeStateFrame(STATE_DOWN);
  41184. this.playStateSound(STATE_DOWN);
  41185. if (this.onInputDown)
  41186. {
  41187. this.onInputDown.dispatch(this, pointer);
  41188. }
  41189. };
  41190. /**
  41191. * Internal function that handles input events.
  41192. *
  41193. * @method Phaser.Button#onInputUpHandler
  41194. * @protected
  41195. * @param {Phaser.Button} sprite - The Button that the event occurred on.
  41196. * @param {Phaser.Pointer} pointer - The Pointer that activated the Button.
  41197. */
  41198. Phaser.Button.prototype.onInputUpHandler = function (sprite, pointer, isOver) {
  41199. this.playStateSound(STATE_UP);
  41200. // Input dispatched early, before state change (but after sound)
  41201. if (this.onInputUp)
  41202. {
  41203. this.onInputUp.dispatch(this, pointer, isOver);
  41204. }
  41205. if (this.freezeFrames)
  41206. {
  41207. return;
  41208. }
  41209. if (this.forceOut === true || (this.forceOut & pointer.pointerMode) === pointer.pointerMode)
  41210. {
  41211. this.changeStateFrame(STATE_OUT);
  41212. }
  41213. else
  41214. {
  41215. var changedUp = this.changeStateFrame(STATE_UP);
  41216. if (!changedUp)
  41217. {
  41218. // No Up frame to show..
  41219. if (isOver)
  41220. {
  41221. this.changeStateFrame(STATE_OVER);
  41222. }
  41223. else
  41224. {
  41225. this.changeStateFrame(STATE_OUT);
  41226. }
  41227. }
  41228. }
  41229. };
  41230. /**
  41231. * @author Richard Davey <rich@photonstorm.com>
  41232. * @copyright 2016 Photon Storm Ltd.
  41233. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  41234. */
  41235. /**
  41236. * The SpriteBatch class is a really fast version of the DisplayObjectContainer built purely for speed, so use when you need a lot of sprites or particles.
  41237. * It's worth mentioning that by default sprite batches are used through-out the renderer, so you only really need to use a SpriteBatch if you have over
  41238. * 1000 sprites that all share the same texture (or texture atlas). It's also useful if running in Canvas mode and you have a lot of un-rotated or un-scaled
  41239. * Sprites as it skips all of the Canvas setTransform calls, which helps performance, especially on mobile devices.
  41240. *
  41241. * Please note that any Sprite that is part of a SpriteBatch will not have its bounds updated, so will fail checks such as outOfBounds.
  41242. *
  41243. * @class Phaser.SpriteBatch
  41244. * @extends Phaser.Group
  41245. * @constructor
  41246. * @param {Phaser.Game} game - A reference to the currently running game.
  41247. * @param {Phaser.Group|Phaser.Sprite|null} parent - The parent Group, DisplayObject or DisplayObjectContainer that this Group will be added to. If `undefined` or `null` it will use game.world.
  41248. * @param {string} [name=group] - A name for this Group. Not used internally but useful for debugging.
  41249. * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World.
  41250. */
  41251. Phaser.SpriteBatch = function (game, parent, name, addToStage) {
  41252. if (parent === undefined || parent === null) { parent = game.world; }
  41253. Phaser.Group.call(this, game, parent, name, addToStage);
  41254. /**
  41255. * @property {number} type - Internal Phaser Type value.
  41256. * @protected
  41257. */
  41258. this.type = Phaser.SPRITEBATCH;
  41259. /**
  41260. * @property {Object} fastSpriteBatch - WebGL Batch Shader.
  41261. * @private
  41262. */
  41263. this.fastSpriteBatch = null;
  41264. /**
  41265. * @property {boolean} ready - Internal flag.
  41266. * @private
  41267. */
  41268. this.ready = false;
  41269. };
  41270. Phaser.SpriteBatch.prototype = Object.create(Phaser.Group.prototype);
  41271. Phaser.SpriteBatch.prototype.constructor = Phaser.SpriteBatch;
  41272. /**
  41273. * Renders the Sprite Batch using the WebGL renderer.
  41274. *
  41275. * @private
  41276. * @method
  41277. * @memberof Phaser.SpriteBatch
  41278. * @param {RenderSession} renderSession
  41279. */
  41280. Phaser.SpriteBatch.prototype._renderWebGL = function (renderSession) {
  41281. if (!this.visible || this.alpha <= 0 || !this.children.length)
  41282. {
  41283. return;
  41284. }
  41285. if (!this.ready)
  41286. {
  41287. this.fastSpriteBatch = new PIXI.WebGLFastSpriteBatch(renderSession.gl);
  41288. this.ready = true;
  41289. }
  41290. if (this.fastSpriteBatch.gl !== renderSession.gl)
  41291. {
  41292. this.fastSpriteBatch.setContext(renderSession.gl);
  41293. }
  41294. renderSession.spriteBatch.stop();
  41295. renderSession.shaderManager.setShader(renderSession.shaderManager.fastShader);
  41296. this.fastSpriteBatch.begin(this, renderSession);
  41297. this.fastSpriteBatch.render(this);
  41298. renderSession.spriteBatch.start();
  41299. };
  41300. /**
  41301. * Renders the Sprite Batch using the Canvas renderer.
  41302. *
  41303. * @private
  41304. * @method
  41305. * @memberof Phaser.SpriteBatch
  41306. * @param {RenderSession} renderSession
  41307. */
  41308. Phaser.SpriteBatch.prototype._renderCanvas = function (renderSession) {
  41309. if (!this.visible || this.alpha <= 0 || !this.children.length)
  41310. {
  41311. return;
  41312. }
  41313. var context = renderSession.context;
  41314. context.globalAlpha = this.worldAlpha;
  41315. this.displayObjectUpdateTransform();
  41316. var transform = this.worldTransform;
  41317. var isRotated = true;
  41318. for (var i = 0; i < this.children.length; i++)
  41319. {
  41320. var child = this.children[i];
  41321. if (!child.visible)
  41322. {
  41323. continue;
  41324. }
  41325. var texture = child.texture;
  41326. var frame = texture.frame;
  41327. context.globalAlpha = this.worldAlpha * child.alpha;
  41328. if (child.rotation % (Math.PI * 2) === 0)
  41329. {
  41330. // If rotation === 0 we can avoid setTransform
  41331. if (isRotated)
  41332. {
  41333. context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
  41334. isRotated = false;
  41335. }
  41336. context.drawImage(
  41337. texture.baseTexture.source,
  41338. frame.x,
  41339. frame.y,
  41340. frame.width,
  41341. frame.height,
  41342. ((child.anchor.x) * (-frame.width * child.scale.x) + child.position.x + 0.5 + renderSession.shakeX) | 0,
  41343. ((child.anchor.y) * (-frame.height * child.scale.y) + child.position.y + 0.5 + renderSession.shakeY) | 0,
  41344. frame.width * child.scale.x,
  41345. frame.height * child.scale.y);
  41346. }
  41347. else
  41348. {
  41349. if (!isRotated)
  41350. {
  41351. isRotated = true;
  41352. }
  41353. child.displayObjectUpdateTransform();
  41354. var childTransform = child.worldTransform;
  41355. var tx = (childTransform.tx * renderSession.resolution) + renderSession.shakeX;
  41356. var ty = (childTransform.ty * renderSession.resolution) + renderSession.shakeY;
  41357. // allow for trimming
  41358. if (renderSession.roundPixels)
  41359. {
  41360. context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, tx | 0, ty | 0);
  41361. }
  41362. else
  41363. {
  41364. context.setTransform(childTransform.a, childTransform.b, childTransform.c, childTransform.d, tx, ty);
  41365. }
  41366. context.drawImage(
  41367. texture.baseTexture.source,
  41368. frame.x,
  41369. frame.y,
  41370. frame.width,
  41371. frame.height,
  41372. ((child.anchor.x) * (-frame.width) + 0.5) | 0,
  41373. ((child.anchor.y) * (-frame.height) + 0.5) | 0,
  41374. frame.width,
  41375. frame.height);
  41376. }
  41377. }
  41378. };
  41379. /**
  41380. * @author Richard Davey <rich@photonstorm.com>
  41381. * @copyright 2016 Photon Storm Ltd.
  41382. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  41383. */
  41384. /**
  41385. * A BitmapData object contains a Canvas element to which you can draw anything you like via normal Canvas context operations.
  41386. * A single BitmapData can be used as the texture for one or many Images / Sprites.
  41387. * So if you need to dynamically create a Sprite texture then they are a good choice.
  41388. *
  41389. * Important note: Every BitmapData creates its own Canvas element. Because BitmapData's are now Game Objects themselves, and don't
  41390. * live on the display list, they are NOT automatically cleared when you change State. Therefore you _must_ call BitmapData.destroy
  41391. * in your State's shutdown method if you wish to free-up the resources the BitmapData used, it will not happen for you.
  41392. *
  41393. * @class Phaser.BitmapData
  41394. * @constructor
  41395. * @param {Phaser.Game} game - A reference to the currently running game.
  41396. * @param {string} key - Internal Phaser reference key for the BitmapData.
  41397. * @param {number} [width=256] - The width of the BitmapData in pixels. If undefined or zero it's set to a default value.
  41398. * @param {number} [height=256] - The height of the BitmapData in pixels. If undefined or zero it's set to a default value.
  41399. * @param {boolean} [skipPool=false] - When this BitmapData generates its internal canvas to use for rendering, it will get the canvas from the CanvasPool if false, or create its own if true.
  41400. */
  41401. Phaser.BitmapData = function (game, key, width, height, skipPool) {
  41402. if (width === undefined || width === 0) { width = 256; }
  41403. if (height === undefined || height === 0) { height = 256; }
  41404. if (skipPool === undefined) { skipPool = false; }
  41405. /**
  41406. * @property {Phaser.Game} game - A reference to the currently running game.
  41407. */
  41408. this.game = game;
  41409. /**
  41410. * @property {string} key - The key of the BitmapData in the Cache, if stored there.
  41411. */
  41412. this.key = key;
  41413. /**
  41414. * @property {number} width - The width of the BitmapData in pixels.
  41415. */
  41416. this.width = width;
  41417. /**
  41418. * @property {number} height - The height of the BitmapData in pixels.
  41419. */
  41420. this.height = height;
  41421. /**
  41422. * @property {HTMLCanvasElement} canvas - The canvas to which this BitmapData draws.
  41423. * @default
  41424. */
  41425. this.canvas = Phaser.Canvas.create(this, width, height, null, skipPool);
  41426. /**
  41427. * @property {CanvasRenderingContext2D} context - The 2d context of the canvas.
  41428. * @default
  41429. */
  41430. this.context = this.canvas.getContext('2d', { alpha: true });
  41431. /**
  41432. * @property {CanvasRenderingContext2D} ctx - A reference to BitmapData.context.
  41433. */
  41434. this.ctx = this.context;
  41435. /**
  41436. * @property {string} smoothProperty - The context property needed for smoothing this Canvas.
  41437. */
  41438. this.smoothProperty = (game.renderType === Phaser.CANVAS) ? game.renderer.renderSession.smoothProperty : Phaser.Canvas.getSmoothingPrefix(this.context);
  41439. /**
  41440. * @property {ImageData} imageData - The context image data.
  41441. * Please note that a call to BitmapData.draw() or BitmapData.copy() does not update immediately this property for performance reason. Use BitmapData.update() to do so.
  41442. * This property is updated automatically after the first game loop, according to the dirty flag property.
  41443. */
  41444. this.imageData = this.context.getImageData(0, 0, width, height);
  41445. /**
  41446. * A Uint8ClampedArray view into BitmapData.buffer.
  41447. * Note that this is unavailable in some browsers (such as Epic Browser due to its security restrictions)
  41448. * @property {Uint8ClampedArray} data
  41449. */
  41450. this.data = null;
  41451. if (this.imageData)
  41452. {
  41453. this.data = this.imageData.data;
  41454. }
  41455. /**
  41456. * @property {Uint32Array} pixels - An Uint32Array view into BitmapData.buffer.
  41457. */
  41458. this.pixels = null;
  41459. /**
  41460. * @property {ArrayBuffer} buffer - An ArrayBuffer the same size as the context ImageData.
  41461. */
  41462. if (this.data)
  41463. {
  41464. if (this.imageData.data.buffer)
  41465. {
  41466. this.buffer = this.imageData.data.buffer;
  41467. this.pixels = new Uint32Array(this.buffer);
  41468. }
  41469. else
  41470. {
  41471. if (window['ArrayBuffer'])
  41472. {
  41473. this.buffer = new ArrayBuffer(this.imageData.data.length);
  41474. this.pixels = new Uint32Array(this.buffer);
  41475. }
  41476. else
  41477. {
  41478. this.pixels = this.imageData.data;
  41479. }
  41480. }
  41481. }
  41482. /**
  41483. * @property {PIXI.BaseTexture} baseTexture - The PIXI.BaseTexture.
  41484. * @default
  41485. */
  41486. this.baseTexture = new PIXI.BaseTexture(this.canvas, null, this.game.resolution);
  41487. /**
  41488. * @property {PIXI.Texture} texture - The PIXI.Texture.
  41489. * @default
  41490. */
  41491. this.texture = new PIXI.Texture(this.baseTexture);
  41492. /**
  41493. * @property {Phaser.FrameData} frameData - The FrameData container this BitmapData uses for rendering.
  41494. */
  41495. this.frameData = new Phaser.FrameData();
  41496. /**
  41497. * @property {Phaser.Frame} textureFrame - The Frame this BitmapData uses for rendering.
  41498. * @default
  41499. */
  41500. this.textureFrame = this.frameData.addFrame(new Phaser.Frame(0, 0, 0, width, height, 'bitmapData'));
  41501. this.texture.frame = this.textureFrame;
  41502. /**
  41503. * @property {number} type - The const type of this object.
  41504. * @default
  41505. */
  41506. this.type = Phaser.BITMAPDATA;
  41507. /**
  41508. * @property {boolean} disableTextureUpload - If disableTextureUpload is true this BitmapData will never send its image data to the GPU when its dirty flag is true.
  41509. */
  41510. this.disableTextureUpload = false;
  41511. /**
  41512. * @property {boolean} dirty - If dirty this BitmapData will be re-rendered.
  41513. */
  41514. this.dirty = false;
  41515. // Aliases
  41516. this.cls = this.clear;
  41517. /**
  41518. * @property {number} _image - Internal cache var.
  41519. * @private
  41520. */
  41521. this._image = null;
  41522. /**
  41523. * @property {Phaser.Point} _pos - Internal cache var.
  41524. * @private
  41525. */
  41526. this._pos = new Phaser.Point();
  41527. /**
  41528. * @property {Phaser.Point} _size - Internal cache var.
  41529. * @private
  41530. */
  41531. this._size = new Phaser.Point();
  41532. /**
  41533. * @property {Phaser.Point} _scale - Internal cache var.
  41534. * @private
  41535. */
  41536. this._scale = new Phaser.Point();
  41537. /**
  41538. * @property {number} _rotate - Internal cache var.
  41539. * @private
  41540. */
  41541. this._rotate = 0;
  41542. /**
  41543. * @property {object} _alpha - Internal cache var.
  41544. * @private
  41545. */
  41546. this._alpha = { prev: 1, current: 1 };
  41547. /**
  41548. * @property {Phaser.Point} _anchor - Internal cache var.
  41549. * @private
  41550. */
  41551. this._anchor = new Phaser.Point();
  41552. /**
  41553. * @property {number} _tempR - Internal cache var.
  41554. * @private
  41555. */
  41556. this._tempR = 0;
  41557. /**
  41558. * @property {number} _tempG - Internal cache var.
  41559. * @private
  41560. */
  41561. this._tempG = 0;
  41562. /**
  41563. * @property {number} _tempB - Internal cache var.
  41564. * @private
  41565. */
  41566. this._tempB = 0;
  41567. /**
  41568. * @property {Phaser.Circle} _circle - Internal cache var.
  41569. * @private
  41570. */
  41571. this._circle = new Phaser.Circle();
  41572. /**
  41573. * @property {HTMLCanvasElement} _swapCanvas - A swap canvas. Used by moveH and moveV, created in those methods.
  41574. * @private
  41575. */
  41576. this._swapCanvas = undefined;
  41577. };
  41578. Phaser.BitmapData.prototype = {
  41579. /**
  41580. * Shifts the contents of this BitmapData by the distances given.
  41581. *
  41582. * The image will wrap-around the edges on all sides if the wrap argument is true (the default).
  41583. *
  41584. * @method Phaser.BitmapData#move
  41585. * @param {integer} x - The amount of pixels to horizontally shift the canvas by. Use a negative value to shift to the left, positive to the right.
  41586. * @param {integer} y - The amount of pixels to vertically shift the canvas by. Use a negative value to shift up, positive to shift down.
  41587. * @param {boolean} [wrap=true] - Wrap the content of the BitmapData.
  41588. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41589. */
  41590. move: function (x, y, wrap) {
  41591. if (x !== 0)
  41592. {
  41593. this.moveH(x, wrap);
  41594. }
  41595. if (y !== 0)
  41596. {
  41597. this.moveV(y, wrap);
  41598. }
  41599. return this;
  41600. },
  41601. /**
  41602. * Shifts the contents of this BitmapData horizontally.
  41603. *
  41604. * The image will wrap-around the sides if the wrap argument is true (the default).
  41605. *
  41606. * @method Phaser.BitmapData#moveH
  41607. * @param {integer} distance - The amount of pixels to horizontally shift the canvas by. Use a negative value to shift to the left, positive to the right.
  41608. * @param {boolean} [wrap=true] - Wrap the content of the BitmapData.
  41609. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41610. */
  41611. moveH: function (distance, wrap) {
  41612. if (wrap === undefined) { wrap = true; }
  41613. if (this._swapCanvas === undefined)
  41614. {
  41615. this._swapCanvas = Phaser.CanvasPool.create(this, this.width, this.height);
  41616. }
  41617. var c = this._swapCanvas;
  41618. var ctx = c.getContext('2d');
  41619. var h = this.height;
  41620. var src = this.canvas;
  41621. ctx.clearRect(0, 0, this.width, this.height);
  41622. if (distance < 0)
  41623. {
  41624. distance = Math.abs(distance);
  41625. // Moving to the left
  41626. var w = this.width - distance;
  41627. // Left-hand chunk
  41628. if (wrap)
  41629. {
  41630. ctx.drawImage(src, 0, 0, distance, h, w, 0, distance, h);
  41631. }
  41632. // Rest of the image
  41633. ctx.drawImage(src, distance, 0, w, h, 0, 0, w, h);
  41634. }
  41635. else
  41636. {
  41637. // Moving to the right
  41638. var w = this.width - distance;
  41639. // Right-hand chunk
  41640. if (wrap)
  41641. {
  41642. ctx.drawImage(src, w, 0, distance, h, 0, 0, distance, h);
  41643. }
  41644. // Rest of the image
  41645. ctx.drawImage(src, 0, 0, w, h, distance, 0, w, h);
  41646. }
  41647. this.clear();
  41648. return this.copy(this._swapCanvas);
  41649. },
  41650. /**
  41651. * Shifts the contents of this BitmapData vertically.
  41652. *
  41653. * The image will wrap-around the sides if the wrap argument is true (the default).
  41654. *
  41655. * @method Phaser.BitmapData#moveV
  41656. * @param {integer} distance - The amount of pixels to vertically shift the canvas by. Use a negative value to shift up, positive to shift down.
  41657. * @param {boolean} [wrap=true] - Wrap the content of the BitmapData.
  41658. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41659. */
  41660. moveV: function (distance, wrap) {
  41661. if (wrap === undefined) { wrap = true; }
  41662. if (this._swapCanvas === undefined)
  41663. {
  41664. this._swapCanvas = Phaser.CanvasPool.create(this, this.width, this.height);
  41665. }
  41666. var c = this._swapCanvas;
  41667. var ctx = c.getContext('2d');
  41668. var w = this.width;
  41669. var src = this.canvas;
  41670. ctx.clearRect(0, 0, this.width, this.height);
  41671. if (distance < 0)
  41672. {
  41673. distance = Math.abs(distance);
  41674. // Moving up
  41675. var h = this.height - distance;
  41676. // Top chunk
  41677. if (wrap)
  41678. {
  41679. ctx.drawImage(src, 0, 0, w, distance, 0, h, w, distance);
  41680. }
  41681. // Rest of the image
  41682. ctx.drawImage(src, 0, distance, w, h, 0, 0, w, h);
  41683. }
  41684. else
  41685. {
  41686. // Moving down
  41687. var h = this.height - distance;
  41688. // Bottom chunk
  41689. if (wrap)
  41690. {
  41691. ctx.drawImage(src, 0, h, w, distance, 0, 0, w, distance);
  41692. }
  41693. // Rest of the image
  41694. ctx.drawImage(src, 0, 0, w, h, 0, distance, w, h);
  41695. }
  41696. this.clear();
  41697. return this.copy(this._swapCanvas);
  41698. },
  41699. /**
  41700. * Updates the given objects so that they use this BitmapData as their texture.
  41701. * This will replace any texture they will currently have set.
  41702. *
  41703. * @method Phaser.BitmapData#add
  41704. * @param {Phaser.Sprite|Phaser.Sprite[]|Phaser.Image|Phaser.Image[]} object - Either a single Sprite/Image or an Array of Sprites/Images.
  41705. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41706. */
  41707. add: function (object) {
  41708. if (Array.isArray(object))
  41709. {
  41710. for (var i = 0; i < object.length; i++)
  41711. {
  41712. if (object[i]['loadTexture'])
  41713. {
  41714. object[i].loadTexture(this);
  41715. }
  41716. }
  41717. }
  41718. else
  41719. {
  41720. object.loadTexture(this);
  41721. }
  41722. return this;
  41723. },
  41724. /**
  41725. * Takes the given Game Object, resizes this BitmapData to match it and then draws it into this BitmapDatas canvas, ready for further processing.
  41726. * The source game object is not modified by this operation.
  41727. * If the source object uses a texture as part of a Texture Atlas or Sprite Sheet, only the current frame will be used for sizing.
  41728. * If a string is given it will assume it's a cache key and look in Phaser.Cache for an image key matching the string.
  41729. *
  41730. * @method Phaser.BitmapData#load
  41731. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapData|Image|HTMLCanvasElement|string} source - The object that will be used to populate this BitmapData. If you give a string it will try and find the Image in the Game.Cache first.
  41732. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41733. */
  41734. load: function (source) {
  41735. if (typeof source === 'string')
  41736. {
  41737. source = this.game.cache.getImage(source);
  41738. }
  41739. if (source)
  41740. {
  41741. this.resize(source.width, source.height);
  41742. this.cls();
  41743. }
  41744. else
  41745. {
  41746. return;
  41747. }
  41748. this.draw(source);
  41749. this.update();
  41750. return this;
  41751. },
  41752. /**
  41753. * Clears the BitmapData context using a clearRect.
  41754. *
  41755. * @method Phaser.BitmapData#cls
  41756. */
  41757. /**
  41758. * Clears the BitmapData context using a clearRect.
  41759. *
  41760. * You can optionally define the area to clear.
  41761. * If the arguments are left empty it will clear the entire canvas.
  41762. *
  41763. * You may need to call BitmapData.update after this in order to clear out the pixel data,
  41764. * but Phaser will not do this automatically for you.
  41765. *
  41766. * @method Phaser.BitmapData#clear
  41767. * @param {number} [x=0] - The x coordinate of the top-left of the area to clear.
  41768. * @param {number} [y=0] - The y coordinate of the top-left of the area to clear.
  41769. * @param {number} [width] - The width of the area to clear. If undefined it will use BitmapData.width.
  41770. * @param {number} [height] - The height of the area to clear. If undefined it will use BitmapData.height.
  41771. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41772. */
  41773. clear: function (x, y, width, height) {
  41774. if (x === undefined) { x = 0; }
  41775. if (y === undefined) { y = 0; }
  41776. if (width === undefined) { width = this.width; }
  41777. if (height === undefined) { height = this.height; }
  41778. this.context.clearRect(x, y, width, height);
  41779. this.dirty = true;
  41780. return this;
  41781. },
  41782. /**
  41783. * Fills the BitmapData with the given color.
  41784. *
  41785. * @method Phaser.BitmapData#fill
  41786. * @param {number} r - The red color value, between 0 and 0xFF (255).
  41787. * @param {number} g - The green color value, between 0 and 0xFF (255).
  41788. * @param {number} b - The blue color value, between 0 and 0xFF (255).
  41789. * @param {number} [a=1] - The alpha color value, between 0 and 1.
  41790. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41791. */
  41792. fill: function (r, g, b, a) {
  41793. if (a === undefined) { a = 1; }
  41794. this.context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
  41795. this.context.fillRect(0, 0, this.width, this.height);
  41796. this.dirty = true;
  41797. return this;
  41798. },
  41799. /**
  41800. * Creates a new {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image Image} element by converting this BitmapDatas canvas into a dataURL.
  41801. *
  41802. * The image is then stored in the {@link Phaser.Cache image Cache} using the key given.
  41803. *
  41804. * Finally a {@link PIXI.Texture} is created based on the image and returned.
  41805. *
  41806. * You can apply the texture to a sprite or any other supporting object by using either the
  41807. * key or the texture. First call `generateTexture`:
  41808. *
  41809. * ```javascript
  41810. * var texture = bitmapdata.generateTexture('ball');
  41811. * ```
  41812. *
  41813. * Then you can either apply the texture to a sprite:
  41814. *
  41815. * ```javascript
  41816. * game.add.sprite(0, 0, texture);
  41817. * ```
  41818. *
  41819. * or by using the string based key:
  41820. *
  41821. * ```javascript
  41822. * game.add.sprite(0, 0, 'ball');
  41823. * ```
  41824. *
  41825. * Most browsers now load the image data asynchronously, so you should use a callback:
  41826. *
  41827. * ```javascript
  41828. * bitmapdata.generateTexture('ball', function (texture) {
  41829. * game.add.sprite(0, 0, texture);
  41830. * // or
  41831. * game.add.sprite(0, 0, 'ball');
  41832. * });
  41833. * ```
  41834. *
  41835. * If this BitmapData is available during preload, you can use {@link Phaser.Loader#imageFromBitmapData} instead.
  41836. *
  41837. * @method Phaser.BitmapData#generateTexture
  41838. * @param {string} key - The key which will be used to store the image in the Cache.
  41839. * @param {function} [callback] - A function to execute once the texture is generated. It will be passed the newly generated texture.
  41840. * @param {any} [callbackContext] - The context in which to invoke the callback.
  41841. * @return {PIXI.Texture|null} The newly generated texture, or `null` if a callback was passed and the texture isn't available yet.
  41842. */
  41843. generateTexture: function (key, callback, callbackContext) {
  41844. var cache = this.game.cache;
  41845. var image = new Image();
  41846. if (callback)
  41847. {
  41848. image.onload = function () {
  41849. var obj = cache.addImage(key, '', image);
  41850. var texture = new PIXI.Texture(obj.base);
  41851. callback.call(callbackContext || null, texture);
  41852. image.onload = null;
  41853. };
  41854. }
  41855. image.src = this.canvas.toDataURL("image/png");
  41856. if (!callback)
  41857. {
  41858. var obj = cache.addImage(key, '', image);
  41859. return new PIXI.Texture(obj.base);
  41860. }
  41861. return null;
  41862. },
  41863. /**
  41864. * Resizes the BitmapData. This changes the size of the underlying canvas and refreshes the buffer.
  41865. *
  41866. * @method Phaser.BitmapData#resize
  41867. * @param {integer} width - The new width of the BitmapData.
  41868. * @param {integer} height - The new height of the BitmapData.
  41869. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41870. */
  41871. resize: function (width, height) {
  41872. if (width !== this.width || height !== this.height)
  41873. {
  41874. this.width = width;
  41875. this.height = height;
  41876. this.canvas.width = width;
  41877. this.canvas.height = height;
  41878. if (this._swapCanvas !== undefined)
  41879. {
  41880. this._swapCanvas.width = width;
  41881. this._swapCanvas.height = height;
  41882. }
  41883. this.baseTexture.width = width;
  41884. this.baseTexture.height = height;
  41885. this.textureFrame.width = width;
  41886. this.textureFrame.height = height;
  41887. this.texture.width = width;
  41888. this.texture.height = height;
  41889. this.texture.crop.width = width;
  41890. this.texture.crop.height = height;
  41891. this.update();
  41892. this.dirty = true;
  41893. }
  41894. return this;
  41895. },
  41896. /**
  41897. * This re-creates the BitmapData.imageData from the current context.
  41898. * It then re-builds the ArrayBuffer, the data Uint8ClampedArray reference and the pixels Int32Array.
  41899. * If not given the dimensions defaults to the full size of the context.
  41900. *
  41901. * Warning: This is a very expensive operation, so use it sparingly.
  41902. *
  41903. * @method Phaser.BitmapData#update
  41904. * @param {number} [x=0] - The x coordinate of the top-left of the image data area to grab from.
  41905. * @param {number} [y=0] - The y coordinate of the top-left of the image data area to grab from.
  41906. * @param {number} [width=1] - The width of the image data area.
  41907. * @param {number} [height=1] - The height of the image data area.
  41908. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41909. */
  41910. update: function (x, y, width, height) {
  41911. if (x === undefined) { x = 0; }
  41912. if (y === undefined) { y = 0; }
  41913. if (width === undefined) { width = Math.max(1, this.width); }
  41914. if (height === undefined) { height = Math.max(1, this.height); }
  41915. this.imageData = this.context.getImageData(x, y, width, height);
  41916. this.data = this.imageData.data;
  41917. if (this.imageData.data.buffer)
  41918. {
  41919. this.buffer = this.imageData.data.buffer;
  41920. this.pixels = new Uint32Array(this.buffer);
  41921. }
  41922. else
  41923. {
  41924. if (window['ArrayBuffer'])
  41925. {
  41926. this.buffer = new ArrayBuffer(this.imageData.data.length);
  41927. this.pixels = new Uint32Array(this.buffer);
  41928. }
  41929. else
  41930. {
  41931. this.pixels = this.imageData.data;
  41932. }
  41933. }
  41934. return this;
  41935. },
  41936. /**
  41937. * Scans through the area specified in this BitmapData and sends a color object for every pixel to the given callback.
  41938. * The callback will be sent a color object with 6 properties: `{ r: number, g: number, b: number, a: number, color: number, rgba: string }`.
  41939. * Where r, g, b and a are integers between 0 and 255 representing the color component values for red, green, blue and alpha.
  41940. * The `color` property is an Int32 of the full color. Note the endianess of this will change per system.
  41941. * The `rgba` property is a CSS style rgba() string which can be used with context.fillStyle calls, among others.
  41942. * The callback will also be sent the pixels x and y coordinates respectively.
  41943. * The callback must return either `false`, in which case no change will be made to the pixel, or a new color object.
  41944. * If a new color object is returned the pixel will be set to the r, g, b and a color values given within it.
  41945. *
  41946. * @method Phaser.BitmapData#processPixelRGB
  41947. * @param {function} callback - The callback that will be sent each pixel color object to be processed.
  41948. * @param {object} callbackContext - The context under which the callback will be called.
  41949. * @param {number} [x=0] - The x coordinate of the top-left of the region to process from.
  41950. * @param {number} [y=0] - The y coordinate of the top-left of the region to process from.
  41951. * @param {number} [width] - The width of the region to process.
  41952. * @param {number} [height] - The height of the region to process.
  41953. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  41954. */
  41955. processPixelRGB: function (callback, callbackContext, x, y, width, height) {
  41956. if (x === undefined) { x = 0; }
  41957. if (y === undefined) { y = 0; }
  41958. if (width === undefined) { width = this.width; }
  41959. if (height === undefined) { height = this.height; }
  41960. var w = x + width;
  41961. var h = y + height;
  41962. var pixel = Phaser.Color.createColor();
  41963. var result = { r: 0, g: 0, b: 0, a: 0 };
  41964. var dirty = false;
  41965. for (var ty = y; ty < h; ty++)
  41966. {
  41967. for (var tx = x; tx < w; tx++)
  41968. {
  41969. Phaser.Color.unpackPixel(this.getPixel32(tx, ty), pixel);
  41970. result = callback.call(callbackContext, pixel, tx, ty);
  41971. if (result !== false && result !== null && result !== undefined)
  41972. {
  41973. this.setPixel32(tx, ty, result.r, result.g, result.b, result.a, false);
  41974. dirty = true;
  41975. }
  41976. }
  41977. }
  41978. if (dirty)
  41979. {
  41980. this.context.putImageData(this.imageData, 0, 0);
  41981. this.dirty = true;
  41982. }
  41983. return this;
  41984. },
  41985. /**
  41986. * Scans through the area specified in this BitmapData and sends the color for every pixel to the given callback along with its x and y coordinates.
  41987. * Whatever value the callback returns is set as the new color for that pixel, unless it returns the same color, in which case it's skipped.
  41988. * Note that the format of the color received will be different depending on if the system is big or little endian.
  41989. * It is expected that your callback will deal with endianess. If you'd rather Phaser did it then use processPixelRGB instead.
  41990. * The callback will also be sent the pixels x and y coordinates respectively.
  41991. *
  41992. * @method Phaser.BitmapData#processPixel
  41993. * @param {function} callback - The callback that will be sent each pixel color to be processed.
  41994. * @param {object} callbackContext - The context under which the callback will be called.
  41995. * @param {number} [x=0] - The x coordinate of the top-left of the region to process from.
  41996. * @param {number} [y=0] - The y coordinate of the top-left of the region to process from.
  41997. * @param {number} [width] - The width of the region to process.
  41998. * @param {number} [height] - The height of the region to process.
  41999. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42000. */
  42001. processPixel: function (callback, callbackContext, x, y, width, height) {
  42002. if (x === undefined) { x = 0; }
  42003. if (y === undefined) { y = 0; }
  42004. if (width === undefined) { width = this.width; }
  42005. if (height === undefined) { height = this.height; }
  42006. var w = x + width;
  42007. var h = y + height;
  42008. var pixel = 0;
  42009. var result = 0;
  42010. var dirty = false;
  42011. for (var ty = y; ty < h; ty++)
  42012. {
  42013. for (var tx = x; tx < w; tx++)
  42014. {
  42015. pixel = this.getPixel32(tx, ty);
  42016. result = callback.call(callbackContext, pixel, tx, ty);
  42017. if (result !== pixel)
  42018. {
  42019. this.pixels[ty * this.width + tx] = result;
  42020. dirty = true;
  42021. }
  42022. }
  42023. }
  42024. if (dirty)
  42025. {
  42026. this.context.putImageData(this.imageData, 0, 0);
  42027. this.dirty = true;
  42028. }
  42029. return this;
  42030. },
  42031. /**
  42032. * Replaces all pixels matching one color with another. The color values are given as two sets of RGBA values.
  42033. * An optional region parameter controls if the replacement happens in just a specific area of the BitmapData or the entire thing.
  42034. *
  42035. * @method Phaser.BitmapData#replaceRGB
  42036. * @param {number} r1 - The red color value to be replaced. Between 0 and 255.
  42037. * @param {number} g1 - The green color value to be replaced. Between 0 and 255.
  42038. * @param {number} b1 - The blue color value to be replaced. Between 0 and 255.
  42039. * @param {number} a1 - The alpha color value to be replaced. Between 0 and 255.
  42040. * @param {number} r2 - The red color value that is the replacement color. Between 0 and 255.
  42041. * @param {number} g2 - The green color value that is the replacement color. Between 0 and 255.
  42042. * @param {number} b2 - The blue color value that is the replacement color. Between 0 and 255.
  42043. * @param {number} a2 - The alpha color value that is the replacement color. Between 0 and 255.
  42044. * @param {Phaser.Rectangle} [region] - The area to perform the search over. If not given it will replace over the whole BitmapData.
  42045. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42046. */
  42047. replaceRGB: function (r1, g1, b1, a1, r2, g2, b2, a2, region) {
  42048. var sx = 0;
  42049. var sy = 0;
  42050. var w = this.width;
  42051. var h = this.height;
  42052. var source = Phaser.Color.packPixel(r1, g1, b1, a1);
  42053. if (region !== undefined && region instanceof Phaser.Rectangle)
  42054. {
  42055. sx = region.x;
  42056. sy = region.y;
  42057. w = region.width;
  42058. h = region.height;
  42059. }
  42060. for (var y = 0; y < h; y++)
  42061. {
  42062. for (var x = 0; x < w; x++)
  42063. {
  42064. if (this.getPixel32(sx + x, sy + y) === source)
  42065. {
  42066. this.setPixel32(sx + x, sy + y, r2, g2, b2, a2, false);
  42067. }
  42068. }
  42069. }
  42070. this.context.putImageData(this.imageData, 0, 0);
  42071. this.dirty = true;
  42072. return this;
  42073. },
  42074. /**
  42075. * Sets the hue, saturation and lightness values on every pixel in the given region, or the whole BitmapData if no region was specified.
  42076. *
  42077. * @method Phaser.BitmapData#setHSL
  42078. * @param {number} [h=null] - The hue, in the range 0 - 1.
  42079. * @param {number} [s=null] - The saturation, in the range 0 - 1.
  42080. * @param {number} [l=null] - The lightness, in the range 0 - 1.
  42081. * @param {Phaser.Rectangle} [region] - The area to perform the operation on. If not given it will run over the whole BitmapData.
  42082. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42083. */
  42084. setHSL: function (h, s, l, region) {
  42085. var bHaveH = h || h === 0;
  42086. var bHaveS = s || s === 0;
  42087. var bHaveL = l || l === 0;
  42088. if (!bHaveH && !bHaveS && !bHaveL)
  42089. {
  42090. return;
  42091. }
  42092. if (region === undefined)
  42093. {
  42094. region = new Phaser.Rectangle(0, 0, this.width, this.height);
  42095. }
  42096. var pixel = Phaser.Color.createColor();
  42097. for (var y = region.y; y < region.bottom; y++)
  42098. {
  42099. for (var x = region.x; x < region.right; x++)
  42100. {
  42101. Phaser.Color.unpackPixel(this.getPixel32(x, y), pixel, true);
  42102. if (bHaveH)
  42103. {
  42104. pixel.h = h;
  42105. }
  42106. if (bHaveS)
  42107. {
  42108. pixel.s = s;
  42109. }
  42110. if (bHaveL)
  42111. {
  42112. pixel.l = l;
  42113. }
  42114. Phaser.Color.HSLtoRGB(pixel.h, pixel.s, pixel.l, pixel);
  42115. this.setPixel32(x, y, pixel.r, pixel.g, pixel.b, pixel.a, false);
  42116. }
  42117. }
  42118. this.context.putImageData(this.imageData, 0, 0);
  42119. this.dirty = true;
  42120. return this;
  42121. },
  42122. /**
  42123. * Shifts any or all of the hue, saturation and lightness values on every pixel in the given region, or the whole BitmapData if no region was specified.
  42124. * Shifting will add the given value onto the current h, s and l values, not replace them.
  42125. * The hue is wrapped to keep it within the range 0 to 1. Saturation and lightness are clamped to not exceed 1.
  42126. *
  42127. * @method Phaser.BitmapData#shiftHSL
  42128. * @param {number} [h=null] - The amount to shift the hue by.
  42129. * @param {number} [s=null] - The amount to shift the saturation by.
  42130. * @param {number} [l=null] - The amount to shift the lightness by.
  42131. * @param {Phaser.Rectangle} [region] - The area to perform the operation on. If not given it will run over the whole BitmapData.
  42132. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42133. */
  42134. shiftHSL: function (h, s, l, region) {
  42135. if (h === undefined || h === null) { h = false; }
  42136. if (s === undefined || s === null) { s = false; }
  42137. if (l === undefined || l === null) { l = false; }
  42138. if (!h && !s && !l)
  42139. {
  42140. return;
  42141. }
  42142. if (region === undefined)
  42143. {
  42144. region = new Phaser.Rectangle(0, 0, this.width, this.height);
  42145. }
  42146. var pixel = Phaser.Color.createColor();
  42147. for (var y = region.y; y < region.bottom; y++)
  42148. {
  42149. for (var x = region.x; x < region.right; x++)
  42150. {
  42151. Phaser.Color.unpackPixel(this.getPixel32(x, y), pixel, true);
  42152. if (h)
  42153. {
  42154. pixel.h = this.game.math.wrap(pixel.h + h, 0, 1);
  42155. }
  42156. if (s)
  42157. {
  42158. pixel.s = this.game.math.clamp(pixel.s + s, 0, 1);
  42159. }
  42160. if (l)
  42161. {
  42162. pixel.l = this.game.math.clamp(pixel.l + l, 0, 1);
  42163. }
  42164. Phaser.Color.HSLtoRGB(pixel.h, pixel.s, pixel.l, pixel);
  42165. this.setPixel32(x, y, pixel.r, pixel.g, pixel.b, pixel.a, false);
  42166. }
  42167. }
  42168. this.context.putImageData(this.imageData, 0, 0);
  42169. this.dirty = true;
  42170. return this;
  42171. },
  42172. /**
  42173. * Sets the color of the given pixel to the specified red, green, blue and alpha values.
  42174. *
  42175. * @method Phaser.BitmapData#setPixel32
  42176. * @param {integer} x - The x coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42177. * @param {integer} y - The y coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42178. * @param {number} red - The red color value, between 0 and 0xFF (255).
  42179. * @param {number} green - The green color value, between 0 and 0xFF (255).
  42180. * @param {number} blue - The blue color value, between 0 and 0xFF (255).
  42181. * @param {number} alpha - The alpha color value, between 0 and 0xFF (255).
  42182. * @param {boolean} [immediate=true] - If `true` the context.putImageData will be called and the dirty flag set.
  42183. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42184. */
  42185. setPixel32: function (x, y, red, green, blue, alpha, immediate) {
  42186. if (immediate === undefined) { immediate = true; }
  42187. if (x >= 0 && x <= this.width && y >= 0 && y <= this.height)
  42188. {
  42189. if (Phaser.Device.LITTLE_ENDIAN)
  42190. {
  42191. this.pixels[y * this.width + x] = (alpha << 24) | (blue << 16) | (green << 8) | red;
  42192. }
  42193. else
  42194. {
  42195. this.pixels[y * this.width + x] = (red << 24) | (green << 16) | (blue << 8) | alpha;
  42196. }
  42197. if (immediate)
  42198. {
  42199. this.context.putImageData(this.imageData, 0, 0);
  42200. this.dirty = true;
  42201. }
  42202. }
  42203. return this;
  42204. },
  42205. /**
  42206. * Sets the color of the given pixel to the specified red, green and blue values.
  42207. *
  42208. * @method Phaser.BitmapData#setPixel
  42209. * @param {integer} x - The x coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42210. * @param {integer} y - The y coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42211. * @param {number} red - The red color value, between 0 and 0xFF (255).
  42212. * @param {number} green - The green color value, between 0 and 0xFF (255).
  42213. * @param {number} blue - The blue color value, between 0 and 0xFF (255).
  42214. * @param {boolean} [immediate=true] - If `true` the context.putImageData will be called and the dirty flag set.
  42215. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42216. */
  42217. setPixel: function (x, y, red, green, blue, immediate) {
  42218. return this.setPixel32(x, y, red, green, blue, 255, immediate);
  42219. },
  42220. /**
  42221. * Get the color of a specific pixel in the context into a color object.
  42222. * If you have drawn anything to the BitmapData since it was created you must call BitmapData.update to refresh the array buffer,
  42223. * otherwise this may return out of date color values, or worse - throw a run-time error as it tries to access an array element that doesn't exist.
  42224. *
  42225. * @method Phaser.BitmapData#getPixel
  42226. * @param {integer} x - The x coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42227. * @param {integer} y - The y coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42228. * @param {object} [out] - An object into which 4 properties will be created: r, g, b and a. If not provided a new object will be created.
  42229. * @return {object} An object with the red, green, blue and alpha values set in the r, g, b and a properties.
  42230. */
  42231. getPixel: function (x, y, out) {
  42232. if (!out)
  42233. {
  42234. out = Phaser.Color.createColor();
  42235. }
  42236. var index = ~~(x + (y * this.width));
  42237. index *= 4;
  42238. out.r = this.data[index];
  42239. out.g = this.data[++index];
  42240. out.b = this.data[++index];
  42241. out.a = this.data[++index];
  42242. return out;
  42243. },
  42244. /**
  42245. * Get the color of a specific pixel including its alpha value.
  42246. * If you have drawn anything to the BitmapData since it was created you must call BitmapData.update to refresh the array buffer,
  42247. * otherwise this may return out of date color values, or worse - throw a run-time error as it tries to access an array element that doesn't exist.
  42248. * Note that on little-endian systems the format is 0xAABBGGRR and on big-endian the format is 0xRRGGBBAA.
  42249. *
  42250. * @method Phaser.BitmapData#getPixel32
  42251. * @param {integer} x - The x coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42252. * @param {integer} y - The y coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42253. * @return {number} A native color value integer (format: 0xAARRGGBB)
  42254. */
  42255. getPixel32: function (x, y) {
  42256. if (x >= 0 && x <= this.width && y >= 0 && y <= this.height)
  42257. {
  42258. return this.pixels[y * this.width + x];
  42259. }
  42260. },
  42261. /**
  42262. * Get the color of a specific pixel including its alpha value as a color object containing r,g,b,a and rgba properties.
  42263. * If you have drawn anything to the BitmapData since it was created you must call BitmapData.update to refresh the array buffer,
  42264. * otherwise this may return out of date color values, or worse - throw a run-time error as it tries to access an array element that doesn't exist.
  42265. *
  42266. * @method Phaser.BitmapData#getPixelRGB
  42267. * @param {integer} x - The x coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42268. * @param {integer} y - The y coordinate of the pixel to be set. Must lay within the dimensions of this BitmapData and be an integer, not a float.
  42269. * @param {object} [out] - An object into which 3 properties will be created: r, g and b. If not provided a new object will be created.
  42270. * @param {boolean} [hsl=false] - Also convert the rgb values into hsl?
  42271. * @param {boolean} [hsv=false] - Also convert the rgb values into hsv?
  42272. * @return {object} An object with the red, green and blue values set in the r, g and b properties.
  42273. */
  42274. getPixelRGB: function (x, y, out, hsl, hsv) {
  42275. return Phaser.Color.unpackPixel(this.getPixel32(x, y), out, hsl, hsv);
  42276. },
  42277. /**
  42278. * Gets all the pixels from the region specified by the given Rectangle object.
  42279. *
  42280. * @method Phaser.BitmapData#getPixels
  42281. * @param {Phaser.Rectangle} rect - The Rectangle region to get.
  42282. * @return {ImageData} Returns a ImageData object containing a Uint8ClampedArray data property.
  42283. */
  42284. getPixels: function (rect) {
  42285. return this.context.getImageData(rect.x, rect.y, rect.width, rect.height);
  42286. },
  42287. /**
  42288. * Scans the BitmapData, pixel by pixel, until it encounters a pixel that isn't transparent (i.e. has an alpha value > 0).
  42289. * It then stops scanning and returns an object containing the color of the pixel in r, g and b properties and the location in the x and y properties.
  42290. *
  42291. * The direction parameter controls from which direction it should start the scan:
  42292. *
  42293. * 0 = top to bottom
  42294. * 1 = bottom to top
  42295. * 2 = left to right
  42296. * 3 = right to left
  42297. *
  42298. * @method Phaser.BitmapData#getFirstPixel
  42299. * @param {number} [direction=0] - The direction in which to scan for the first pixel. 0 = top to bottom, 1 = bottom to top, 2 = left to right and 3 = right to left.
  42300. * @return {object} Returns an object containing the color of the pixel in the `r`, `g` and `b` properties and the location in the `x` and `y` properties.
  42301. */
  42302. getFirstPixel: function (direction) {
  42303. if (direction === undefined) { direction = 0; }
  42304. var pixel = Phaser.Color.createColor();
  42305. var x = 0;
  42306. var y = 0;
  42307. var v = 1;
  42308. var scan = false;
  42309. if (direction === 1)
  42310. {
  42311. v = -1;
  42312. y = this.height;
  42313. }
  42314. else if (direction === 3)
  42315. {
  42316. v = -1;
  42317. x = this.width;
  42318. }
  42319. do {
  42320. Phaser.Color.unpackPixel(this.getPixel32(x, y), pixel);
  42321. if (direction === 0 || direction === 1)
  42322. {
  42323. // Top to Bottom / Bottom to Top
  42324. x++;
  42325. if (x === this.width)
  42326. {
  42327. x = 0;
  42328. y += v;
  42329. if (y >= this.height || y <= 0)
  42330. {
  42331. scan = true;
  42332. }
  42333. }
  42334. }
  42335. else if (direction === 2 || direction === 3)
  42336. {
  42337. // Left to Right / Right to Left
  42338. y++;
  42339. if (y === this.height)
  42340. {
  42341. y = 0;
  42342. x += v;
  42343. if (x >= this.width || x <= 0)
  42344. {
  42345. scan = true;
  42346. }
  42347. }
  42348. }
  42349. }
  42350. while (pixel.a === 0 && !scan);
  42351. pixel.x = x;
  42352. pixel.y = y;
  42353. return pixel;
  42354. },
  42355. /**
  42356. * Scans the BitmapData and calculates the bounds. This is a rectangle that defines the extent of all non-transparent pixels.
  42357. * The rectangle returned will extend from the top-left of the image to the bottom-right, excluding transparent pixels.
  42358. *
  42359. * @method Phaser.BitmapData#getBounds
  42360. * @param {Phaser.Rectangle} [rect] - If provided this Rectangle object will be populated with the bounds, otherwise a new object will be created.
  42361. * @return {Phaser.Rectangle} A Rectangle whose dimensions encompass the full extent of non-transparent pixels in this BitmapData.
  42362. */
  42363. getBounds: function (rect) {
  42364. if (rect === undefined) { rect = new Phaser.Rectangle(); }
  42365. rect.x = this.getFirstPixel(2).x;
  42366. // If we hit this, there's no point scanning any more, the image is empty
  42367. if (rect.x === this.width)
  42368. {
  42369. return rect.setTo(0, 0, 0, 0);
  42370. }
  42371. rect.y = this.getFirstPixel(0).y;
  42372. rect.width = (this.getFirstPixel(3).x - rect.x) + 1;
  42373. rect.height = (this.getFirstPixel(1).y - rect.y) + 1;
  42374. return rect;
  42375. },
  42376. /**
  42377. * Creates a new Phaser.Image object, assigns this BitmapData to be its texture, adds it to the world then returns it.
  42378. *
  42379. * @method Phaser.BitmapData#addToWorld
  42380. * @param {number} [x=0] - The x coordinate to place the Image at.
  42381. * @param {number} [y=0] - The y coordinate to place the Image at.
  42382. * @param {number} [anchorX=0] - Set the x anchor point of the Image. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  42383. * @param {number} [anchorY=0] - Set the y anchor point of the Image. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  42384. * @param {number} [scaleX=1] - The horizontal scale factor of the Image. A value of 1 means no scaling. 2 would be twice the size, and so on.
  42385. * @param {number} [scaleY=1] - The vertical scale factor of the Image. A value of 1 means no scaling. 2 would be twice the size, and so on.
  42386. * @return {Phaser.Image} The newly added Image object.
  42387. */
  42388. addToWorld: function (x, y, anchorX, anchorY, scaleX, scaleY) {
  42389. scaleX = scaleX || 1;
  42390. scaleY = scaleY || 1;
  42391. var image = this.game.add.image(x, y, this);
  42392. image.anchor.set(anchorX, anchorY);
  42393. image.scale.set(scaleX, scaleY);
  42394. return image;
  42395. },
  42396. /**
  42397. * Copies a rectangular area from the source object to this BitmapData. If you give `null` as the source it will copy from itself.
  42398. *
  42399. * You can optionally resize, translate, rotate, scale, alpha or blend as it's drawn.
  42400. *
  42401. * All rotation, scaling and drawing takes place around the regions center point by default, but can be changed with the anchor parameters.
  42402. *
  42403. * Note that the source image can also be this BitmapData, which can create some interesting effects.
  42404. *
  42405. * This method has a lot of parameters for maximum control.
  42406. * You can use the more friendly methods like `copyRect` and `draw` to avoid having to remember them all.
  42407. *
  42408. * You may prefer to use `copyTransform` if you're simply trying to draw a Sprite to this BitmapData,
  42409. * and don't wish to translate, scale or rotate it from its original values.
  42410. *
  42411. * @method Phaser.BitmapData#copy
  42412. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapData|Phaser.RenderTexture|Image|HTMLCanvasElement|string} [source] - The source to copy from. If you give a string it will try and find the Image in the Game.Cache first. This is quite expensive so try to provide the image itself.
  42413. * @param {number} [x=0] - The x coordinate representing the top-left of the region to copy from the source image.
  42414. * @param {number} [y=0] - The y coordinate representing the top-left of the region to copy from the source image.
  42415. * @param {number} [width] - The width of the region to copy from the source image. If not specified it will use the full source image width.
  42416. * @param {number} [height] - The height of the region to copy from the source image. If not specified it will use the full source image height.
  42417. * @param {number} [tx] - The x coordinate to translate to before drawing. If not specified it will default to the `x` parameter. If `null` and `source` is a Display Object, it will default to `source.x`.
  42418. * @param {number} [ty] - The y coordinate to translate to before drawing. If not specified it will default to the `y` parameter. If `null` and `source` is a Display Object, it will default to `source.y`.
  42419. * @param {number} [newWidth] - The new width of the block being copied. If not specified it will default to the `width` parameter.
  42420. * @param {number} [newHeight] - The new height of the block being copied. If not specified it will default to the `height` parameter.
  42421. * @param {number} [rotate=0] - The angle in radians to rotate the block to before drawing. Rotation takes place around the center by default, but can be changed with the `anchor` parameters.
  42422. * @param {number} [anchorX=0] - The anchor point around which the block is rotated and scaled. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  42423. * @param {number} [anchorY=0] - The anchor point around which the block is rotated and scaled. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  42424. * @param {number} [scaleX=1] - The horizontal scale factor of the block. A value of 1 means no scaling. 2 would be twice the size, and so on.
  42425. * @param {number} [scaleY=1] - The vertical scale factor of the block. A value of 1 means no scaling. 2 would be twice the size, and so on.
  42426. * @param {number} [alpha=1] - The alpha that will be set on the context before drawing. A value between 0 (fully transparent) and 1, opaque.
  42427. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  42428. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  42429. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42430. */
  42431. copy: function (source, x, y, width, height, tx, ty, newWidth, newHeight, rotate, anchorX, anchorY, scaleX, scaleY, alpha, blendMode, roundPx) {
  42432. if (source === undefined || source === null) { source = this; }
  42433. if (source instanceof Phaser.RenderTexture)
  42434. {
  42435. source = source.getCanvas();
  42436. }
  42437. this._image = source;
  42438. if (source instanceof Phaser.Sprite || source instanceof Phaser.Image || source instanceof Phaser.Text || source instanceof PIXI.Sprite)
  42439. {
  42440. // Copy over sprite values
  42441. this._pos.set(source.texture.crop.x, source.texture.crop.y);
  42442. this._size.set(source.texture.crop.width, source.texture.crop.height);
  42443. this._scale.set(source.scale.x, source.scale.y);
  42444. this._anchor.set(source.anchor.x, source.anchor.y);
  42445. this._rotate = source.rotation;
  42446. this._alpha.current = source.alpha;
  42447. if (source.texture instanceof Phaser.RenderTexture)
  42448. {
  42449. this._image = source.texture.getCanvas();
  42450. }
  42451. else
  42452. {
  42453. this._image = source.texture.baseTexture.source;
  42454. }
  42455. if (tx === undefined || tx === null) { tx = source.x; }
  42456. if (ty === undefined || ty === null) { ty = source.y; }
  42457. if (source.texture.trim)
  42458. {
  42459. // Offset the translation coordinates by the trim amount
  42460. tx += source.texture.trim.x - source.anchor.x * source.texture.trim.width;
  42461. ty += source.texture.trim.y - source.anchor.y * source.texture.trim.height;
  42462. }
  42463. if (source.tint !== 0xFFFFFF)
  42464. {
  42465. if (source.cachedTint !== source.tint)
  42466. {
  42467. source.cachedTint = source.tint;
  42468. source.tintedTexture = PIXI.CanvasTinter.getTintedTexture(source, source.tint);
  42469. }
  42470. this._image = source.tintedTexture;
  42471. this._pos.set(0);
  42472. }
  42473. }
  42474. else
  42475. {
  42476. // Reset
  42477. this._pos.set(0);
  42478. this._scale.set(1);
  42479. this._anchor.set(0);
  42480. this._rotate = 0;
  42481. this._alpha.current = 1;
  42482. if (source instanceof Phaser.BitmapData)
  42483. {
  42484. this._image = source.canvas;
  42485. }
  42486. else if (typeof source === 'string')
  42487. {
  42488. source = this.game.cache.getImage(source);
  42489. if (source === null)
  42490. {
  42491. return;
  42492. }
  42493. else
  42494. {
  42495. this._image = source;
  42496. }
  42497. }
  42498. this._size.set(this._image.width, this._image.height);
  42499. }
  42500. // The source region to copy from
  42501. if (x === undefined || x === null) { x = 0; }
  42502. if (y === undefined || y === null) { y = 0; }
  42503. // If they set a width/height then we override the frame values with them
  42504. if (width)
  42505. {
  42506. this._size.x = width;
  42507. }
  42508. if (height)
  42509. {
  42510. this._size.y = height;
  42511. }
  42512. // The destination region to copy to
  42513. if (tx === undefined || tx === null) { tx = x; }
  42514. if (ty === undefined || ty === null) { ty = y; }
  42515. if (newWidth === undefined || newWidth === null) { newWidth = this._size.x; }
  42516. if (newHeight === undefined || newHeight === null) { newHeight = this._size.y; }
  42517. // Rotation - if set this will override any potential Sprite value
  42518. if (typeof rotate === 'number')
  42519. {
  42520. this._rotate = rotate;
  42521. }
  42522. // Anchor - if set this will override any potential Sprite value
  42523. if (typeof anchorX === 'number')
  42524. {
  42525. this._anchor.x = anchorX;
  42526. }
  42527. if (typeof anchorY === 'number')
  42528. {
  42529. this._anchor.y = anchorY;
  42530. }
  42531. // Scaling - if set this will override any potential Sprite value
  42532. if (typeof scaleX === 'number')
  42533. {
  42534. this._scale.x = scaleX;
  42535. }
  42536. if (typeof scaleY === 'number')
  42537. {
  42538. this._scale.y = scaleY;
  42539. }
  42540. // Effects
  42541. if (typeof alpha === 'number')
  42542. {
  42543. this._alpha.current = alpha;
  42544. }
  42545. if (blendMode === undefined) { blendMode = null; }
  42546. if (roundPx === undefined) { roundPx = false; }
  42547. if (this._alpha.current <= 0 || this._scale.x === 0 || this._scale.y === 0 || this._size.x === 0 || this._size.y === 0)
  42548. {
  42549. // Why bother wasting CPU cycles drawing something you can't see?
  42550. return;
  42551. }
  42552. var ctx = this.context;
  42553. this._alpha.prev = ctx.globalAlpha;
  42554. ctx.save();
  42555. ctx.globalAlpha = this._alpha.current;
  42556. if (blendMode)
  42557. {
  42558. this.op = blendMode;
  42559. }
  42560. if (roundPx)
  42561. {
  42562. tx |= 0;
  42563. ty |= 0;
  42564. }
  42565. // Doesn't work fully with children, or nested scale + rotation transforms (see copyTransform)
  42566. ctx.translate(tx, ty);
  42567. ctx.scale(this._scale.x, this._scale.y);
  42568. ctx.rotate(this._rotate);
  42569. ctx.drawImage(this._image, this._pos.x + x, this._pos.y + y, this._size.x, this._size.y, -newWidth * this._anchor.x, -newHeight * this._anchor.y, newWidth, newHeight);
  42570. // Carry on ...
  42571. ctx.restore();
  42572. ctx.globalAlpha = this._alpha.prev;
  42573. this.dirty = true;
  42574. return this;
  42575. },
  42576. /**
  42577. * Draws the given `source` Game Object to this BitmapData, using its `worldTransform` property to set the
  42578. * position, scale and rotation of where it is drawn. This function is used internally by `drawGroup`.
  42579. * It takes the objects tint and scale mode into consideration before drawing.
  42580. *
  42581. * You can optionally specify Blend Mode and Round Pixels arguments.
  42582. *
  42583. * @method Phaser.BitmapData#copyTransform
  42584. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapData|Phaser.BitmapText} [source] - The Game Object to draw.
  42585. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  42586. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  42587. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42588. */
  42589. copyTransform: function (source, blendMode, roundPx) {
  42590. if (blendMode === undefined) { blendMode = null; }
  42591. if (roundPx === undefined) { roundPx = false; }
  42592. if (!source.hasOwnProperty('worldTransform') || !source.worldVisible || source.worldAlpha === 0)
  42593. {
  42594. return this;
  42595. }
  42596. var wt = source.worldTransform;
  42597. this._pos.set(source.texture.crop.x, source.texture.crop.y);
  42598. this._size.set(source.texture.crop.width, source.texture.crop.height);
  42599. if (wt.a === 0 || wt.d === 0 || this._size.x === 0 || this._size.y === 0)
  42600. {
  42601. // Why bother wasting CPU cycles drawing something you can't see?
  42602. return this;
  42603. }
  42604. if (source.texture instanceof Phaser.RenderTexture)
  42605. {
  42606. this._image = source.texture.getCanvas();
  42607. }
  42608. else
  42609. {
  42610. this._image = source.texture.baseTexture.source;
  42611. }
  42612. var tx = wt.tx;
  42613. var ty = wt.ty;
  42614. if (source.texture.trim)
  42615. {
  42616. // Offset the translation coordinates by the trim amount
  42617. tx += source.texture.trim.x - source.anchor.x * source.texture.trim.width;
  42618. ty += source.texture.trim.y - source.anchor.y * source.texture.trim.height;
  42619. }
  42620. if (source.tint !== 0xFFFFFF)
  42621. {
  42622. if (source.cachedTint !== source.tint)
  42623. {
  42624. source.cachedTint = source.tint;
  42625. source.tintedTexture = PIXI.CanvasTinter.getTintedTexture(source, source.tint);
  42626. }
  42627. this._image = source.tintedTexture;
  42628. this._pos.set(0);
  42629. }
  42630. if (roundPx)
  42631. {
  42632. tx |= 0;
  42633. ty |= 0;
  42634. }
  42635. var ctx = this.context;
  42636. this._alpha.prev = ctx.globalAlpha;
  42637. ctx.save();
  42638. ctx.globalAlpha = this._alpha.current;
  42639. if (blendMode)
  42640. {
  42641. this.op = blendMode;
  42642. }
  42643. ctx[this.smoothProperty] = (source.texture.baseTexture.scaleMode === PIXI.scaleModes.LINEAR);
  42644. ctx.setTransform(wt.a, wt.b, wt.c, wt.d, tx, ty);
  42645. ctx.drawImage(this._image,
  42646. this._pos.x,
  42647. this._pos.y,
  42648. this._size.x,
  42649. this._size.y,
  42650. -this._size.x * source.anchor.x,
  42651. -this._size.y * source.anchor.y,
  42652. this._size.x,
  42653. this._size.y);
  42654. ctx.restore();
  42655. ctx.globalAlpha = this._alpha.prev;
  42656. this.dirty = true;
  42657. return this;
  42658. },
  42659. /**
  42660. * Copies the area defined by the Rectangle parameter from the source image to this BitmapData at the given location.
  42661. *
  42662. * @method Phaser.BitmapData#copyRect
  42663. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapData|Phaser.RenderTexture|Image|string} source - The Image to copy from. If you give a string it will try and find the Image in the Game.Cache.
  42664. * @param {Phaser.Rectangle} area - The Rectangle region to copy from the source image.
  42665. * @param {number} x - The destination x coordinate to copy the image to.
  42666. * @param {number} y - The destination y coordinate to copy the image to.
  42667. * @param {number} [alpha=1] - The alpha that will be set on the context before drawing. A value between 0 (fully transparent) and 1, opaque.
  42668. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  42669. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  42670. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42671. */
  42672. copyRect: function (source, area, x, y, alpha, blendMode, roundPx) {
  42673. return this.copy(source, area.x, area.y, area.width, area.height, x, y, area.width, area.height, 0, 0, 0, 1, 1, alpha, blendMode, roundPx);
  42674. },
  42675. /**
  42676. * Draws the given Phaser.Sprite, Phaser.Image or Phaser.Text to this BitmapData at the coordinates specified.
  42677. * You can use the optional width and height values to 'stretch' the sprite as it is drawn. This uses drawImage stretching, not scaling.
  42678. *
  42679. * The children will be drawn at their `x` and `y` world space coordinates. If this is outside the bounds of the BitmapData they won't be visible.
  42680. * When drawing it will take into account the rotation, scale, scaleMode, alpha and tint values.
  42681. *
  42682. * Note: You should ensure that at least 1 full update has taken place before calling this,
  42683. * otherwise the objects are likely to render incorrectly, if at all.
  42684. * You can trigger an update yourself by calling `stage.updateTransform()` before calling `draw`.
  42685. *
  42686. * @method Phaser.BitmapData#draw
  42687. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.RenderTexture} source - The Sprite, Image or Text object to draw onto this BitmapData.
  42688. * @param {number} [x=0] - The x coordinate to translate to before drawing. If not specified it will default to `source.x`.
  42689. * @param {number} [y=0] - The y coordinate to translate to before drawing. If not specified it will default to `source.y`.
  42690. * @param {number} [width] - The new width of the Sprite being copied. If not specified it will default to `source.width`.
  42691. * @param {number} [height] - The new height of the Sprite being copied. If not specified it will default to `source.height`.
  42692. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  42693. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  42694. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42695. */
  42696. draw: function (source, x, y, width, height, blendMode, roundPx) {
  42697. // By specifying null for most parameters it will tell `copy` to use the Sprite values instead, which is what we want here
  42698. return this.copy(source, null, null, null, null, x, y, width, height, null, null, null, null, null, null, blendMode, roundPx);
  42699. },
  42700. /**
  42701. * Draws the immediate children of a Phaser.Group to this BitmapData.
  42702. *
  42703. * It's perfectly valid to pass in `game.world` as the Group, and it will iterate through the entire display list.
  42704. *
  42705. * Children are drawn _only_ if they have their `exists` property set to `true`, and have image, or RenderTexture, based Textures.
  42706. *
  42707. * The children will be drawn at their `x` and `y` world space coordinates. If this is outside the bounds of the BitmapData they won't be visible.
  42708. * When drawing it will take into account the rotation, scale, scaleMode, alpha and tint values.
  42709. *
  42710. * Note: You should ensure that at least 1 full update has taken place before calling this,
  42711. * otherwise the objects are likely to render incorrectly, if at all.
  42712. * You can trigger an update yourself by calling `stage.updateTransform()` before calling `drawGroup`.
  42713. *
  42714. * @method Phaser.BitmapData#drawGroup
  42715. * @param {Phaser.Group} group - The Group to draw onto this BitmapData. Can also be Phaser.World.
  42716. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  42717. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  42718. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42719. */
  42720. drawGroup: function (group, blendMode, roundPx) {
  42721. if (group.total > 0)
  42722. {
  42723. group.forEachExists(this.drawGroupProxy, this, blendMode, roundPx);
  42724. }
  42725. return this;
  42726. },
  42727. /**
  42728. * A proxy for drawGroup that handles child iteration for more complex Game Objects.
  42729. *
  42730. * @method Phaser.BitmapData#drawGroupProxy
  42731. * @private
  42732. * @param {Phaser.Sprite|Phaser.Image|Phaser.BitmapText} child - The child to draw.
  42733. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  42734. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  42735. */
  42736. drawGroupProxy: function (child, blendMode, roundPx) {
  42737. if (child.hasOwnProperty('texture'))
  42738. {
  42739. this.copyTransform(child, blendMode, roundPx);
  42740. }
  42741. if (child.type === Phaser.GROUP && child.exists)
  42742. {
  42743. this.drawGroup(child, blendMode, roundPx);
  42744. }
  42745. else
  42746. {
  42747. if (child.hasOwnProperty('children') && child.children.length > 0)
  42748. {
  42749. for (var i = 0; i < child.children.length; i++)
  42750. {
  42751. if (child.children[i].exists)
  42752. {
  42753. this.copyTransform(child.children[i], blendMode, roundPx);
  42754. }
  42755. }
  42756. }
  42757. }
  42758. },
  42759. /**
  42760. * Draws the Game Object or Group to this BitmapData and then recursively iterates through all of its children.
  42761. *
  42762. * If a child has an `exists` property then it (and its children) will be only be drawn if exists is `true`.
  42763. *
  42764. * The children will be drawn at their `x` and `y` world space coordinates. If this is outside the bounds of the BitmapData
  42765. * they won't be drawn. Depending on your requirements you may need to resize the BitmapData in advance to match the
  42766. * bounds of the top-level Game Object.
  42767. *
  42768. * When drawing it will take into account the child's world rotation, scale and alpha values.
  42769. *
  42770. * It's perfectly valid to pass in `game.world` as the parent object, and it will iterate through the entire display list.
  42771. *
  42772. * Note: If you are trying to grab your entire game at the start of a State then you should ensure that at least 1 full update
  42773. * has taken place before doing so, otherwise all of the objects will render with incorrect positions and scales. You can
  42774. * trigger an update yourself by calling `stage.updateTransform()` before calling `drawFull`.
  42775. *
  42776. * @method Phaser.BitmapData#drawFull
  42777. * @param {Phaser.World|Phaser.Group|Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText} parent - The Game Object to draw onto this BitmapData and then recursively draw all of its children.
  42778. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  42779. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  42780. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42781. */
  42782. drawFull: function (parent, blendMode, roundPx) {
  42783. if (parent.worldVisible === false || parent.worldAlpha === 0 || (parent.hasOwnProperty('exists') && parent.exists === false))
  42784. {
  42785. return this;
  42786. }
  42787. if (parent.type !== Phaser.GROUP && parent.type !== Phaser.EMITTER && parent.type !== Phaser.BITMAPTEXT)
  42788. {
  42789. if (parent.type === Phaser.GRAPHICS)
  42790. {
  42791. var bounds = parent.getBounds();
  42792. this.ctx.save();
  42793. this.ctx.translate(bounds.x, bounds.y);
  42794. PIXI.CanvasGraphics.renderGraphics(parent, this.ctx);
  42795. this.ctx.restore();
  42796. }
  42797. else
  42798. {
  42799. this.copy(parent, null, null, null, null, parent.worldPosition.x, parent.worldPosition.y, null, null, parent.worldRotation, null, null, parent.worldScale.x, parent.worldScale.y, parent.worldAlpha, blendMode, roundPx);
  42800. }
  42801. }
  42802. if (parent.children)
  42803. {
  42804. for (var i = 0; i < parent.children.length; i++)
  42805. {
  42806. this.drawFull(parent.children[i], blendMode, roundPx);
  42807. }
  42808. }
  42809. return this;
  42810. },
  42811. /**
  42812. * Sets the shadow properties of this BitmapDatas context which will affect all draw operations made to it.
  42813. * You can cancel an existing shadow by calling this method and passing no parameters.
  42814. * Note: At the time of writing (October 2014) Chrome still doesn't support shadowBlur used with drawImage.
  42815. *
  42816. * @method Phaser.BitmapData#shadow
  42817. * @param {string} color - The color of the shadow, given in a CSS format, i.e. `#000000` or `rgba(0,0,0,1)`. If `null` or `undefined` the shadow will be reset.
  42818. * @param {number} [blur=5] - The amount the shadow will be blurred by. Low values = a crisp shadow, high values = a softer shadow.
  42819. * @param {number} [x=10] - The horizontal offset of the shadow in pixels.
  42820. * @param {number} [y=10] - The vertical offset of the shadow in pixels.
  42821. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42822. */
  42823. shadow: function (color, blur, x, y) {
  42824. var ctx = this.context;
  42825. if (color === undefined || color === null)
  42826. {
  42827. ctx.shadowColor = 'rgba(0,0,0,0)';
  42828. }
  42829. else
  42830. {
  42831. ctx.shadowColor = color;
  42832. ctx.shadowBlur = blur || 5;
  42833. ctx.shadowOffsetX = x || 10;
  42834. ctx.shadowOffsetY = y || 10;
  42835. }
  42836. return this;
  42837. },
  42838. /**
  42839. * Draws the image onto this BitmapData using an image as an alpha mask.
  42840. *
  42841. * @method Phaser.BitmapData#alphaMask
  42842. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapData|Image|HTMLCanvasElement|string} source - The source to copy from. If you give a string it will try and find the Image in the Game.Cache first. This is quite expensive so try to provide the image itself.
  42843. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapData|Image|HTMLCanvasElement|string} [mask] - The object to be used as the mask. If you give a string it will try and find the Image in the Game.Cache first. This is quite expensive so try to provide the image itself. If you don't provide a mask it will use this BitmapData as the mask.
  42844. * @param {Phaser.Rectangle} [sourceRect] - A Rectangle where x/y define the coordinates to draw the Source image to and width/height define the size.
  42845. * @param {Phaser.Rectangle} [maskRect] - A Rectangle where x/y define the coordinates to draw the Mask image to and width/height define the size.
  42846. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42847. */
  42848. alphaMask: function (source, mask, sourceRect, maskRect) {
  42849. if (maskRect === undefined || maskRect === null)
  42850. {
  42851. this.draw(mask).blendSourceAtop();
  42852. }
  42853. else
  42854. {
  42855. this.draw(mask, maskRect.x, maskRect.y, maskRect.width, maskRect.height).blendSourceAtop();
  42856. }
  42857. if (sourceRect === undefined || sourceRect === null)
  42858. {
  42859. this.draw(source).blendReset();
  42860. }
  42861. else
  42862. {
  42863. this.draw(source, sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height).blendReset();
  42864. }
  42865. return this;
  42866. },
  42867. /**
  42868. * Scans this BitmapData for all pixels matching the given r,g,b values and then draws them into the given destination BitmapData.
  42869. * The original BitmapData remains unchanged.
  42870. * The destination BitmapData must be large enough to receive all of the pixels that are scanned unless the 'resize' parameter is true.
  42871. * Although the destination BitmapData is returned from this method, it's actually modified directly in place, meaning this call is perfectly valid:
  42872. * `picture.extract(mask, r, g, b)`
  42873. * You can specify optional r2, g2, b2 color values. If given the pixel written to the destination bitmap will be of the r2, g2, b2 color.
  42874. * If not given it will be written as the same color it was extracted. You can provide one or more alternative colors, allowing you to tint
  42875. * the color during extraction.
  42876. *
  42877. * @method Phaser.BitmapData#extract
  42878. * @param {Phaser.BitmapData} destination - The BitmapData that the extracted pixels will be drawn to.
  42879. * @param {number} r - The red color component, in the range 0 - 255.
  42880. * @param {number} g - The green color component, in the range 0 - 255.
  42881. * @param {number} b - The blue color component, in the range 0 - 255.
  42882. * @param {number} [a=255] - The alpha color component, in the range 0 - 255 that the new pixel will be drawn at.
  42883. * @param {boolean} [resize=false] - Should the destination BitmapData be resized to match this one before the pixels are copied?
  42884. * @param {number} [r2] - An alternative red color component to be written to the destination, in the range 0 - 255.
  42885. * @param {number} [g2] - An alternative green color component to be written to the destination, in the range 0 - 255.
  42886. * @param {number} [b2] - An alternative blue color component to be written to the destination, in the range 0 - 255.
  42887. * @returns {Phaser.BitmapData} The BitmapData that the extract pixels were drawn on.
  42888. */
  42889. extract: function (destination, r, g, b, a, resize, r2, g2, b2) {
  42890. if (a === undefined) { a = 255; }
  42891. if (resize === undefined) { resize = false; }
  42892. if (r2 === undefined) { r2 = r; }
  42893. if (g2 === undefined) { g2 = g; }
  42894. if (b2 === undefined) { b2 = b; }
  42895. if (resize)
  42896. {
  42897. destination.resize(this.width, this.height);
  42898. }
  42899. this.processPixelRGB(
  42900. function (pixel, x, y)
  42901. {
  42902. if (pixel.r === r && pixel.g === g && pixel.b === b)
  42903. {
  42904. destination.setPixel32(x, y, r2, g2, b2, a, false);
  42905. }
  42906. return false;
  42907. },
  42908. this);
  42909. destination.context.putImageData(destination.imageData, 0, 0);
  42910. destination.dirty = true;
  42911. return destination;
  42912. },
  42913. /**
  42914. * Draws a filled Rectangle to the BitmapData at the given x, y coordinates and width / height in size.
  42915. *
  42916. * @method Phaser.BitmapData#rect
  42917. * @param {number} x - The x coordinate of the top-left of the Rectangle.
  42918. * @param {number} y - The y coordinate of the top-left of the Rectangle.
  42919. * @param {number} width - The width of the Rectangle.
  42920. * @param {number} height - The height of the Rectangle.
  42921. * @param {string} [fillStyle] - If set the context fillStyle will be set to this value before the rect is drawn.
  42922. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42923. */
  42924. rect: function (x, y, width, height, fillStyle) {
  42925. if (typeof fillStyle !== 'undefined')
  42926. {
  42927. this.context.fillStyle = fillStyle;
  42928. }
  42929. this.context.fillRect(x, y, width, height);
  42930. return this;
  42931. },
  42932. /**
  42933. * Draws text to the BitmapData in the given font and color.
  42934. * The default font is 14px Courier, so useful for quickly drawing debug text.
  42935. * If you need to do a lot of font work to this BitmapData we'd recommend implementing your own text draw method.
  42936. *
  42937. * @method Phaser.BitmapData#text
  42938. * @param {string} text - The text to write to the BitmapData.
  42939. * @param {number} x - The x coordinate of the top-left of the text string.
  42940. * @param {number} y - The y coordinate of the top-left of the text string.
  42941. * @param {string} [font='14px Courier'] - The font. This is passed directly to Context.font, so anything that can support, this can.
  42942. * @param {string} [color='rgb(255,255,255)'] - The color the text will be drawn in.
  42943. * @param {boolean} [shadow=true] - Draw a single pixel black shadow below the text (offset by text.x/y + 1)
  42944. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42945. */
  42946. text: function (text, x, y, font, color, shadow) {
  42947. if (x === undefined) { x = 0; }
  42948. if (y === undefined) { y = 0; }
  42949. if (font === undefined) { font = '14px Courier'; }
  42950. if (color === undefined) { color = 'rgb(255,255,255)'; }
  42951. if (shadow === undefined) { shadow = true; }
  42952. var ctx = this.context;
  42953. var prevFont = ctx.font;
  42954. ctx.font = font;
  42955. if (shadow)
  42956. {
  42957. ctx.fillStyle = 'rgb(0,0,0)';
  42958. ctx.fillText(text, x + 1, y + 1);
  42959. }
  42960. ctx.fillStyle = color;
  42961. ctx.fillText(text, x, y);
  42962. ctx.font = prevFont;
  42963. return this;
  42964. },
  42965. /**
  42966. * Draws a filled Circle to the BitmapData at the given x, y coordinates and radius in size.
  42967. *
  42968. * @method Phaser.BitmapData#circle
  42969. * @param {number} x - The x coordinate to draw the Circle at. This is the center of the circle.
  42970. * @param {number} y - The y coordinate to draw the Circle at. This is the center of the circle.
  42971. * @param {number} radius - The radius of the Circle in pixels. The radius is half the diameter.
  42972. * @param {string} [fillStyle] - If set the context fillStyle will be set to this value before the circle is drawn.
  42973. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42974. */
  42975. circle: function (x, y, radius, fillStyle) {
  42976. var ctx = this.context;
  42977. if (fillStyle !== undefined)
  42978. {
  42979. ctx.fillStyle = fillStyle;
  42980. }
  42981. ctx.beginPath();
  42982. ctx.arc(x, y, radius, 0, Math.PI * 2, false);
  42983. ctx.closePath();
  42984. ctx.fill();
  42985. return this;
  42986. },
  42987. /**
  42988. * Draws a line between the coordinates given in the color and thickness specified.
  42989. *
  42990. * @method Phaser.BitmapData#line
  42991. * @param {number} x1 - The x coordinate to start the line from.
  42992. * @param {number} y1 - The y coordinate to start the line from.
  42993. * @param {number} x2 - The x coordinate to draw the line to.
  42994. * @param {number} y2 - The y coordinate to draw the line to.
  42995. * @param {string} [color='#fff'] - The stroke color that the line will be drawn in.
  42996. * @param {number} [width=1] - The line thickness.
  42997. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  42998. */
  42999. line: function (x1, y1, x2, y2, color, width) {
  43000. if (color === undefined) { color = '#fff'; }
  43001. if (width === undefined) { width = 1; }
  43002. var ctx = this.context;
  43003. ctx.beginPath();
  43004. ctx.moveTo(x1, y1);
  43005. ctx.lineTo(x2, y2);
  43006. ctx.lineWidth = width;
  43007. ctx.strokeStyle = color;
  43008. ctx.stroke();
  43009. ctx.closePath();
  43010. return this;
  43011. },
  43012. /**
  43013. * Takes the given Line object and image and renders it to this BitmapData as a repeating texture line.
  43014. *
  43015. * @method Phaser.BitmapData#textureLine
  43016. * @param {Phaser.Line} line - A Phaser.Line object that will be used to plot the start and end of the line.
  43017. * @param {string|Image} image - The key of an image in the Phaser.Cache to use as the texture for this line, or an actual Image.
  43018. * @param {string} [repeat='repeat-x'] - The pattern repeat mode to use when drawing the line. Either `repeat`, `repeat-x` or `no-repeat`.
  43019. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43020. */
  43021. textureLine: function (line, image, repeat) {
  43022. if (repeat === undefined) { repeat = 'repeat-x'; }
  43023. if (typeof image === 'string')
  43024. {
  43025. image = this.game.cache.getImage(image);
  43026. if (!image)
  43027. {
  43028. return;
  43029. }
  43030. }
  43031. var width = line.length;
  43032. if (repeat === 'no-repeat' && width > image.width)
  43033. {
  43034. width = image.width;
  43035. }
  43036. var ctx = this.context;
  43037. ctx.fillStyle = ctx.createPattern(image, repeat);
  43038. this._circle = new Phaser.Circle(line.start.x, line.start.y, image.height);
  43039. this._circle.circumferencePoint(line.angle - 1.5707963267948966, false, this._pos);
  43040. ctx.save();
  43041. ctx.translate(this._pos.x, this._pos.y);
  43042. ctx.rotate(line.angle);
  43043. ctx.fillRect(0, 0, width, image.height);
  43044. ctx.restore();
  43045. this.dirty = true;
  43046. return this;
  43047. },
  43048. /**
  43049. * If the game is running in WebGL this will push the texture up to the GPU if it's dirty.
  43050. * This is called automatically if the BitmapData is being used by a Sprite, otherwise you need to remember to call it in your render function.
  43051. * If you wish to suppress this functionality set BitmapData.disableTextureUpload to `true`.
  43052. *
  43053. * @method Phaser.BitmapData#render
  43054. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43055. */
  43056. render: function () {
  43057. if (!this.disableTextureUpload && this.dirty)
  43058. {
  43059. this.baseTexture.dirty();
  43060. this.dirty = false;
  43061. }
  43062. return this;
  43063. },
  43064. /**
  43065. * Destroys this BitmapData and puts the canvas it was using back into the canvas pool for re-use.
  43066. *
  43067. * @method Phaser.BitmapData#destroy
  43068. */
  43069. destroy: function () {
  43070. this.frameData.destroy();
  43071. this.texture.destroy(true);
  43072. Phaser.CanvasPool.remove(this);
  43073. },
  43074. /**
  43075. * Resets the blend mode (effectively sets it to 'source-over')
  43076. *
  43077. * @method Phaser.BitmapData#blendReset
  43078. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43079. */
  43080. blendReset: function () {
  43081. this.op = 'source-over';
  43082. return this;
  43083. },
  43084. /**
  43085. * Sets the blend mode to 'source-over'
  43086. *
  43087. * @method Phaser.BitmapData#blendSourceOver
  43088. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43089. */
  43090. blendSourceOver: function () {
  43091. this.op = 'source-over';
  43092. return this;
  43093. },
  43094. /**
  43095. * Sets the blend mode to 'source-in'
  43096. *
  43097. * @method Phaser.BitmapData#blendSourceIn
  43098. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43099. */
  43100. blendSourceIn: function () {
  43101. this.op = 'source-in';
  43102. return this;
  43103. },
  43104. /**
  43105. * Sets the blend mode to 'source-out'
  43106. *
  43107. * @method Phaser.BitmapData#blendSourceOut
  43108. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43109. */
  43110. blendSourceOut: function () {
  43111. this.op = 'source-out';
  43112. return this;
  43113. },
  43114. /**
  43115. * Sets the blend mode to 'source-atop'
  43116. *
  43117. * @method Phaser.BitmapData#blendSourceAtop
  43118. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43119. */
  43120. blendSourceAtop: function () {
  43121. this.op = 'source-atop';
  43122. return this;
  43123. },
  43124. /**
  43125. * Sets the blend mode to 'destination-over'
  43126. *
  43127. * @method Phaser.BitmapData#blendDestinationOver
  43128. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43129. */
  43130. blendDestinationOver: function () {
  43131. this.op = 'destination-over';
  43132. return this;
  43133. },
  43134. /**
  43135. * Sets the blend mode to 'destination-in'
  43136. *
  43137. * @method Phaser.BitmapData#blendDestinationIn
  43138. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43139. */
  43140. blendDestinationIn: function () {
  43141. this.op = 'destination-in';
  43142. return this;
  43143. },
  43144. /**
  43145. * Sets the blend mode to 'destination-out'
  43146. *
  43147. * @method Phaser.BitmapData#blendDestinationOut
  43148. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43149. */
  43150. blendDestinationOut: function () {
  43151. this.op = 'destination-out';
  43152. return this;
  43153. },
  43154. /**
  43155. * Sets the blend mode to 'destination-atop'
  43156. *
  43157. * @method Phaser.BitmapData#blendDestinationAtop
  43158. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43159. */
  43160. blendDestinationAtop: function () {
  43161. this.op = 'destination-atop';
  43162. return this;
  43163. },
  43164. /**
  43165. * Sets the blend mode to 'xor'
  43166. *
  43167. * @method Phaser.BitmapData#blendXor
  43168. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43169. */
  43170. blendXor: function () {
  43171. this.op = 'xor';
  43172. return this;
  43173. },
  43174. /**
  43175. * Sets the blend mode to 'lighter'
  43176. *
  43177. * @method Phaser.BitmapData#blendAdd
  43178. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43179. */
  43180. blendAdd: function () {
  43181. this.op = 'lighter';
  43182. return this;
  43183. },
  43184. /**
  43185. * Sets the blend mode to 'multiply'
  43186. *
  43187. * @method Phaser.BitmapData#blendMultiply
  43188. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43189. */
  43190. blendMultiply: function () {
  43191. this.op = 'multiply';
  43192. return this;
  43193. },
  43194. /**
  43195. * Sets the blend mode to 'screen'
  43196. *
  43197. * @method Phaser.BitmapData#blendScreen
  43198. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43199. */
  43200. blendScreen: function () {
  43201. this.op = 'screen';
  43202. return this;
  43203. },
  43204. /**
  43205. * Sets the blend mode to 'overlay'
  43206. *
  43207. * @method Phaser.BitmapData#blendOverlay
  43208. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43209. */
  43210. blendOverlay: function () {
  43211. this.op = 'overlay';
  43212. return this;
  43213. },
  43214. /**
  43215. * Sets the blend mode to 'darken'
  43216. *
  43217. * @method Phaser.BitmapData#blendDarken
  43218. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43219. */
  43220. blendDarken: function () {
  43221. this.op = 'darken';
  43222. return this;
  43223. },
  43224. /**
  43225. * Sets the blend mode to 'lighten'
  43226. *
  43227. * @method Phaser.BitmapData#blendLighten
  43228. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43229. */
  43230. blendLighten: function () {
  43231. this.op = 'lighten';
  43232. return this;
  43233. },
  43234. /**
  43235. * Sets the blend mode to 'color-dodge'
  43236. *
  43237. * @method Phaser.BitmapData#blendColorDodge
  43238. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43239. */
  43240. blendColorDodge: function () {
  43241. this.op = 'color-dodge';
  43242. return this;
  43243. },
  43244. /**
  43245. * Sets the blend mode to 'color-burn'
  43246. *
  43247. * @method Phaser.BitmapData#blendColorBurn
  43248. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43249. */
  43250. blendColorBurn: function () {
  43251. this.op = 'color-burn';
  43252. return this;
  43253. },
  43254. /**
  43255. * Sets the blend mode to 'hard-light'
  43256. *
  43257. * @method Phaser.BitmapData#blendHardLight
  43258. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43259. */
  43260. blendHardLight: function () {
  43261. this.op = 'hard-light';
  43262. return this;
  43263. },
  43264. /**
  43265. * Sets the blend mode to 'soft-light'
  43266. *
  43267. * @method Phaser.BitmapData#blendSoftLight
  43268. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43269. */
  43270. blendSoftLight: function () {
  43271. this.op = 'soft-light';
  43272. return this;
  43273. },
  43274. /**
  43275. * Sets the blend mode to 'difference'
  43276. *
  43277. * @method Phaser.BitmapData#blendDifference
  43278. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43279. */
  43280. blendDifference: function () {
  43281. this.op = 'difference';
  43282. return this;
  43283. },
  43284. /**
  43285. * Sets the blend mode to 'exclusion'
  43286. *
  43287. * @method Phaser.BitmapData#blendExclusion
  43288. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43289. */
  43290. blendExclusion: function () {
  43291. this.op = 'exclusion';
  43292. return this;
  43293. },
  43294. /**
  43295. * Sets the blend mode to 'hue'
  43296. *
  43297. * @method Phaser.BitmapData#blendHue
  43298. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43299. */
  43300. blendHue: function () {
  43301. this.op = 'hue';
  43302. return this;
  43303. },
  43304. /**
  43305. * Sets the blend mode to 'saturation'
  43306. *
  43307. * @method Phaser.BitmapData#blendSaturation
  43308. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43309. */
  43310. blendSaturation: function () {
  43311. this.op = 'saturation';
  43312. return this;
  43313. },
  43314. /**
  43315. * Sets the blend mode to 'color'
  43316. *
  43317. * @method Phaser.BitmapData#blendColor
  43318. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43319. */
  43320. blendColor: function () {
  43321. this.op = 'color';
  43322. return this;
  43323. },
  43324. /**
  43325. * Sets the blend mode to 'luminosity'
  43326. *
  43327. * @method Phaser.BitmapData#blendLuminosity
  43328. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43329. */
  43330. blendLuminosity: function () {
  43331. this.op = 'luminosity';
  43332. return this;
  43333. },
  43334. /**
  43335. * Updates a portion of the BitmapData from a source Bitmap.
  43336. * This optimization is important if calling update() on a large Bitmap is causing performance issues.
  43337. * Make sure you use getPixel32() instead of getPixel().
  43338. * This does not work with floating point numbers for x and y.
  43339. *
  43340. * @method Phaser.BitmapData#copyBitmapData
  43341. * @param {Phaser.BitmapData} [source] - The BitmapData you wish to copy.
  43342. * @param {number} [x] - The x coordinate of the top-left of the area to copy.
  43343. * @param {number} [y] - The y coordinate of the top-left of the area to copy.
  43344. * @return {Phaser.BitmapData} This BitmapData object for method chaining.
  43345. */
  43346. copyBitmapData: function(source, x, y) {
  43347. source.update();
  43348. for (var i = 0, destRowStart; i < source.height; i++) {
  43349. destRowStart = (y + i) * this.width + x;
  43350. for (var j = 0; j < source.width; j++) {
  43351. this.pixels[destRowStart + j] = source.pixels[i * source.width + j];
  43352. }
  43353. }
  43354. return this;
  43355. }
  43356. };
  43357. /**
  43358. * @memberof Phaser.BitmapData
  43359. * @property {boolean} smoothed - Gets or sets this BitmapData.contexts smoothing enabled value.
  43360. */
  43361. Object.defineProperty(Phaser.BitmapData.prototype, "smoothed", {
  43362. get: function () {
  43363. Phaser.Canvas.getSmoothingEnabled(this.context);
  43364. },
  43365. set: function (value) {
  43366. Phaser.Canvas.setSmoothingEnabled(this.context, value);
  43367. }
  43368. });
  43369. /**
  43370. * @memberof Phaser.BitmapData
  43371. * @property {string} op - A short-hand code to get or set the global composite operation of the BitmapDatas canvas.
  43372. */
  43373. Object.defineProperty(Phaser.BitmapData.prototype, "op", {
  43374. get: function () {
  43375. return this.context.globalCompositeOperation;
  43376. },
  43377. set: function (value) {
  43378. this.context.globalCompositeOperation = value;
  43379. }
  43380. });
  43381. /**
  43382. * Gets a JavaScript object that has 6 properties set that are used by BitmapData in a transform.
  43383. *
  43384. * @method Phaser.BitmapData.getTransform
  43385. * @param {number} translateX - The x translate value.
  43386. * @param {number} translateY - The y translate value.
  43387. * @param {number} scaleX - The scale x value.
  43388. * @param {number} scaleY - The scale y value.
  43389. * @param {number} skewX - The skew x value.
  43390. * @param {number} skewY - The skew y value.
  43391. * @return {object} A JavaScript object containing all of the properties BitmapData needs for transforms.
  43392. */
  43393. Phaser.BitmapData.getTransform = function (translateX, translateY, scaleX, scaleY, skewX, skewY) {
  43394. if (typeof translateX !== 'number') { translateX = 0; }
  43395. if (typeof translateY !== 'number') { translateY = 0; }
  43396. if (typeof scaleX !== 'number') { scaleX = 1; }
  43397. if (typeof scaleY !== 'number') { scaleY = 1; }
  43398. if (typeof skewX !== 'number') { skewX = 0; }
  43399. if (typeof skewY !== 'number') { skewY = 0; }
  43400. return { sx: scaleX, sy: scaleY, scaleX: scaleX, scaleY: scaleY, skewX: skewX, skewY: skewY, translateX: translateX, translateY: translateY, tx: translateX, ty: translateY };
  43401. };
  43402. Phaser.BitmapData.prototype.constructor = Phaser.BitmapData;
  43403. /* jshint ignore:start */
  43404. /*
  43405. Copyright (c) 2016, Mapbox
  43406. Permission to use, copy, modify, and/or distribute this software for any purpose
  43407. with or without fee is hereby granted, provided that the above copyright notice
  43408. and this permission notice appear in all copies.
  43409. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  43410. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  43411. FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  43412. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  43413. OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  43414. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  43415. THIS SOFTWARE.
  43416. */
  43417. /**
  43418. * @class EarCut
  43419. */
  43420. Phaser.EarCut = {};
  43421. Phaser.EarCut.Triangulate = function (data, holeIndices, dim) {
  43422. dim = dim || 2;
  43423. var hasHoles = holeIndices && holeIndices.length,
  43424. outerLen = hasHoles ? holeIndices[0] * dim : data.length,
  43425. outerNode = Phaser.EarCut.linkedList(data, 0, outerLen, dim, true),
  43426. triangles = [];
  43427. if (!outerNode) return triangles;
  43428. var minX, minY, maxX, maxY, x, y, size;
  43429. if (hasHoles) outerNode = Phaser.EarCut.eliminateHoles(data, holeIndices, outerNode, dim);
  43430. // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  43431. if (data.length > 80 * dim) {
  43432. minX = maxX = data[0];
  43433. minY = maxY = data[1];
  43434. for (var i = dim; i < outerLen; i += dim) {
  43435. x = data[i];
  43436. y = data[i + 1];
  43437. if (x < minX) minX = x;
  43438. if (y < minY) minY = y;
  43439. if (x > maxX) maxX = x;
  43440. if (y > maxY) maxY = y;
  43441. }
  43442. // minX, minY and size are later used to transform coords into integers for z-order calculation
  43443. size = Math.max(maxX - minX, maxY - minY);
  43444. }
  43445. Phaser.EarCut.earcutLinked(outerNode, triangles, dim, minX, minY, size);
  43446. return triangles;
  43447. };
  43448. // create a circular doubly linked list from polygon points in the specified winding order
  43449. Phaser.EarCut.linkedList = function (data, start, end, dim, clockwise) {
  43450. var sum = 0,
  43451. i, j, last;
  43452. // calculate original winding order of a polygon ring
  43453. for (i = start, j = end - dim; i < end; i += dim) {
  43454. sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
  43455. j = i;
  43456. }
  43457. // link points into circular doubly-linked list in the specified winding order
  43458. if (clockwise === (sum > 0)) {
  43459. for (i = start; i < end; i += dim) last = Phaser.EarCut.insertNode(i, data[i], data[i + 1], last);
  43460. } else {
  43461. for (i = end - dim; i >= start; i -= dim) last = Phaser.EarCut.insertNode(i, data[i], data[i + 1], last);
  43462. }
  43463. return last;
  43464. };
  43465. // eliminate colinear or duplicate points
  43466. Phaser.EarCut.filterPoints = function (start, end) {
  43467. if (!start) return start;
  43468. if (!end) end = start;
  43469. var p = start,
  43470. again;
  43471. do {
  43472. again = false;
  43473. if (!p.steiner && (Phaser.EarCut.equals(p, p.next) || Phaser.EarCut.area(p.prev, p, p.next) === 0)) {
  43474. Phaser.EarCut.removeNode(p);
  43475. p = end = p.prev;
  43476. if (p === p.next) return null;
  43477. again = true;
  43478. } else {
  43479. p = p.next;
  43480. }
  43481. } while (again || p !== end);
  43482. return end;
  43483. };
  43484. // main ear slicing loop which triangulates a polygon (given as a linked list)
  43485. Phaser.EarCut.earcutLinked = function (ear, triangles, dim, minX, minY, size, pass) {
  43486. if (!ear) return;
  43487. // interlink polygon nodes in z-order
  43488. if (!pass && size) Phaser.EarCut.indexCurve(ear, minX, minY, size);
  43489. var stop = ear,
  43490. prev, next;
  43491. // iterate through ears, slicing them one by one
  43492. while (ear.prev !== ear.next) {
  43493. prev = ear.prev;
  43494. next = ear.next;
  43495. if (size ? Phaser.EarCut.isEarHashed(ear, minX, minY, size) : Phaser.EarCut.isEar(ear)) {
  43496. // cut off the triangle
  43497. triangles.push(prev.i / dim);
  43498. triangles.push(ear.i / dim);
  43499. triangles.push(next.i / dim);
  43500. Phaser.EarCut.removeNode(ear);
  43501. // skipping the next vertice leads to less sliver triangles
  43502. ear = next.next;
  43503. stop = next.next;
  43504. continue;
  43505. }
  43506. ear = next;
  43507. // if we looped through the whole remaining polygon and can't find any more ears
  43508. if (ear === stop) {
  43509. // try filtering points and slicing again
  43510. if (!pass) {
  43511. Phaser.EarCut.earcutLinked(Phaser.EarCut.filterPoints(ear), triangles, dim, minX, minY, size, 1);
  43512. // if this didn't work, try curing all small self-intersections locally
  43513. } else if (pass === 1) {
  43514. ear = Phaser.EarCut.cureLocalIntersections(ear, triangles, dim);
  43515. Phaser.EarCut.earcutLinked(ear, triangles, dim, minX, minY, size, 2);
  43516. // as a last resort, try splitting the remaining polygon into two
  43517. } else if (pass === 2) {
  43518. Phaser.EarCut.splitEarcut(ear, triangles, dim, minX, minY, size);
  43519. }
  43520. break;
  43521. }
  43522. }
  43523. };
  43524. // check whether a polygon node forms a valid ear with adjacent nodes
  43525. Phaser.EarCut.isEar = function (ear) {
  43526. var a = ear.prev,
  43527. b = ear,
  43528. c = ear.next;
  43529. if (Phaser.EarCut.area(a, b, c) >= 0) return false; // reflex, can't be an ear
  43530. // now make sure we don't have other points inside the potential ear
  43531. var p = ear.next.next;
  43532. while (p !== ear.prev) {
  43533. if (Phaser.EarCut.pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
  43534. Phaser.EarCut.area(p.prev, p, p.next) >= 0) return false;
  43535. p = p.next;
  43536. }
  43537. return true;
  43538. };
  43539. Phaser.EarCut.isEarHashed = function (ear, minX, minY, size) {
  43540. var a = ear.prev,
  43541. b = ear,
  43542. c = ear.next;
  43543. if (Phaser.EarCut.area(a, b, c) >= 0) return false; // reflex, can't be an ear
  43544. // triangle bbox; min & max are calculated like this for speed
  43545. var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
  43546. minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
  43547. maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
  43548. maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
  43549. // z-order range for the current triangle bbox;
  43550. var minZ = Phaser.EarCut.zOrder(minTX, minTY, minX, minY, size),
  43551. maxZ = Phaser.EarCut.zOrder(maxTX, maxTY, minX, minY, size);
  43552. // first look for points inside the triangle in increasing z-order
  43553. var p = ear.nextZ;
  43554. while (p && p.z <= maxZ) {
  43555. if (p !== ear.prev && p !== ear.next &&
  43556. Phaser.EarCut.pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
  43557. Phaser.EarCut.area(p.prev, p, p.next) >= 0) return false;
  43558. p = p.nextZ;
  43559. }
  43560. // then look for points in decreasing z-order
  43561. p = ear.prevZ;
  43562. while (p && p.z >= minZ) {
  43563. if (p !== ear.prev && p !== ear.next &&
  43564. Phaser.EarCut.pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
  43565. Phaser.EarCut.area(p.prev, p, p.next) >= 0) return false;
  43566. p = p.prevZ;
  43567. }
  43568. return true;
  43569. };
  43570. // go through all polygon nodes and cure small local self-intersections
  43571. Phaser.EarCut.cureLocalIntersections = function (start, triangles, dim) {
  43572. var p = start;
  43573. do {
  43574. var a = p.prev,
  43575. b = p.next.next;
  43576. // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2])
  43577. if (Phaser.EarCut.intersects(a, p, p.next, b) && Phaser.EarCut.locallyInside(a, b) && Phaser.EarCut.locallyInside(b, a)) {
  43578. triangles.push(a.i / dim);
  43579. triangles.push(p.i / dim);
  43580. triangles.push(b.i / dim);
  43581. // remove two nodes involved
  43582. Phaser.EarCut.removeNode(p);
  43583. Phaser.EarCut.removeNode(p.next);
  43584. p = start = b;
  43585. }
  43586. p = p.next;
  43587. } while (p !== start);
  43588. return p;
  43589. };
  43590. // try splitting polygon into two and triangulate them independently
  43591. Phaser.EarCut.splitEarcut = function (start, triangles, dim, minX, minY, size) {
  43592. // look for a valid diagonal that divides the polygon into two
  43593. var a = start;
  43594. do {
  43595. var b = a.next.next;
  43596. while (b !== a.prev) {
  43597. if (a.i !== b.i && Phaser.EarCut.isValidDiagonal(a, b)) {
  43598. // split the polygon in two by the diagonal
  43599. var c = Phaser.EarCut.splitPolygon(a, b);
  43600. // filter colinear points around the cuts
  43601. a = Phaser.EarCut.filterPoints(a, a.next);
  43602. c = Phaser.EarCut.filterPoints(c, c.next);
  43603. // run earcut on each half
  43604. Phaser.EarCut.earcutLinked(a, triangles, dim, minX, minY, size);
  43605. Phaser.EarCut.earcutLinked(c, triangles, dim, minX, minY, size);
  43606. return;
  43607. }
  43608. b = b.next;
  43609. }
  43610. a = a.next;
  43611. } while (a !== start);
  43612. };
  43613. // link every hole into the outer loop, producing a single-ring polygon without holes
  43614. Phaser.EarCut.eliminateHoles = function (data, holeIndices, outerNode, dim) {
  43615. var queue = [],
  43616. i, len, start, end, list;
  43617. for (i = 0, len = holeIndices.length; i < len; i++) {
  43618. start = holeIndices[i] * dim;
  43619. end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
  43620. list = Phaser.EarCut.linkedList(data, start, end, dim, false);
  43621. if (list === list.next) list.steiner = true;
  43622. queue.push(Phaser.EarCut.getLeftmost(list));
  43623. }
  43624. queue.sort(compareX);
  43625. // process holes from left to right
  43626. for (i = 0; i < queue.length; i++) {
  43627. Phaser.EarCut.eliminateHole(queue[i], outerNode);
  43628. outerNode = Phaser.EarCut.filterPoints(outerNode, outerNode.next);
  43629. }
  43630. return outerNode;
  43631. };
  43632. Phaser.EarCut.compareX = function (a, b) {
  43633. return a.x - b.x;
  43634. };
  43635. // find a bridge between vertices that connects hole with an outer ring and and link it
  43636. Phaser.EarCut.eliminateHole = function (hole, outerNode) {
  43637. outerNode = Phaser.EarCut.findHoleBridge(hole, outerNode);
  43638. if (outerNode) {
  43639. var b = Phaser.EarCut.splitPolygon(outerNode, hole);
  43640. Phaser.EarCut.filterPoints(b, b.next);
  43641. }
  43642. };
  43643. // David Eberly's algorithm for finding a bridge between hole and outer polygon
  43644. Phaser.EarCut.findHoleBridge = function (hole, outerNode) {
  43645. var p = outerNode,
  43646. hx = hole.x,
  43647. hy = hole.y,
  43648. qx = -Infinity,
  43649. m;
  43650. // find a segment intersected by a ray from the hole's leftmost point to the left;
  43651. // segment's endpoint with lesser x will be potential connection point
  43652. do {
  43653. if (hy <= p.y && hy >= p.next.y) {
  43654. var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
  43655. if (x <= hx && x > qx) {
  43656. qx = x;
  43657. m = p.x < p.next.x ? p : p.next;
  43658. }
  43659. }
  43660. p = p.next;
  43661. } while (p !== outerNode);
  43662. if (!m) return null;
  43663. if (hole.x === m.x) return m.prev; // hole touches outer segment; pick lower endpoint
  43664. // look for points inside the triangle of hole point, segment intersection and endpoint;
  43665. // if there are no points found, we have a valid connection;
  43666. // otherwise choose the point of the minimum angle with the ray as connection point
  43667. var stop = m,
  43668. tanMin = Infinity,
  43669. tan;
  43670. p = m.next;
  43671. while (p !== stop) {
  43672. if (hx >= p.x && p.x >= m.x &&
  43673. Phaser.EarCut.pointInTriangle(hy < m.y ? hx : qx, hy, m.x, m.y, hy < m.y ? qx : hx, hy, p.x, p.y)) {
  43674. tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
  43675. if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && Phaser.EarCut.locallyInside(p, hole)) {
  43676. m = p;
  43677. tanMin = tan;
  43678. }
  43679. }
  43680. p = p.next;
  43681. }
  43682. return m;
  43683. };
  43684. // interlink polygon nodes in z-order
  43685. Phaser.EarCut.indexCurve = function (start, minX, minY, size) {
  43686. var p = start;
  43687. do {
  43688. if (p.z === null) p.z = Phaser.EarCut.zOrder(p.x, p.y, minX, minY, size);
  43689. p.prevZ = p.prev;
  43690. p.nextZ = p.next;
  43691. p = p.next;
  43692. } while (p !== start);
  43693. p.prevZ.nextZ = null;
  43694. p.prevZ = null;
  43695. Phaser.EarCut.sortLinked(p);
  43696. };
  43697. // Simon Tatham's linked list merge sort algorithm
  43698. // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
  43699. Phaser.EarCut.sortLinked = function (list) {
  43700. var i, p, q, e, tail, numMerges, pSize, qSize,
  43701. inSize = 1;
  43702. do {
  43703. p = list;
  43704. list = null;
  43705. tail = null;
  43706. numMerges = 0;
  43707. while (p) {
  43708. numMerges++;
  43709. q = p;
  43710. pSize = 0;
  43711. for (i = 0; i < inSize; i++) {
  43712. pSize++;
  43713. q = q.nextZ;
  43714. if (!q) break;
  43715. }
  43716. qSize = inSize;
  43717. while (pSize > 0 || (qSize > 0 && q)) {
  43718. if (pSize === 0) {
  43719. e = q;
  43720. q = q.nextZ;
  43721. qSize--;
  43722. } else if (qSize === 0 || !q) {
  43723. e = p;
  43724. p = p.nextZ;
  43725. pSize--;
  43726. } else if (p.z <= q.z) {
  43727. e = p;
  43728. p = p.nextZ;
  43729. pSize--;
  43730. } else {
  43731. e = q;
  43732. q = q.nextZ;
  43733. qSize--;
  43734. }
  43735. if (tail) tail.nextZ = e;
  43736. else list = e;
  43737. e.prevZ = tail;
  43738. tail = e;
  43739. }
  43740. p = q;
  43741. }
  43742. tail.nextZ = null;
  43743. inSize *= 2;
  43744. } while (numMerges > 1);
  43745. return list;
  43746. };
  43747. // z-order of a point given coords and size of the data bounding box
  43748. Phaser.EarCut.zOrder = function (x, y, minX, minY, size) {
  43749. // coords are transformed into non-negative 15-bit integer range
  43750. x = 32767 * (x - minX) / size;
  43751. y = 32767 * (y - minY) / size;
  43752. x = (x | (x << 8)) & 0x00FF00FF;
  43753. x = (x | (x << 4)) & 0x0F0F0F0F;
  43754. x = (x | (x << 2)) & 0x33333333;
  43755. x = (x | (x << 1)) & 0x55555555;
  43756. y = (y | (y << 8)) & 0x00FF00FF;
  43757. y = (y | (y << 4)) & 0x0F0F0F0F;
  43758. y = (y | (y << 2)) & 0x33333333;
  43759. y = (y | (y << 1)) & 0x55555555;
  43760. return x | (y << 1);
  43761. };
  43762. // find the leftmost node of a polygon ring
  43763. Phaser.EarCut.getLeftmost = function (start) {
  43764. var p = start,
  43765. leftmost = start;
  43766. do {
  43767. if (p.x < leftmost.x) leftmost = p;
  43768. p = p.next;
  43769. } while (p !== start);
  43770. return leftmost;
  43771. };
  43772. // check if a point lies within a convex triangle
  43773. Phaser.EarCut.pointInTriangle = function (ax, ay, bx, by, cx, cy, px, py) {
  43774. return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
  43775. (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
  43776. (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
  43777. };
  43778. // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
  43779. Phaser.EarCut.isValidDiagonal = function (a, b) {
  43780. return Phaser.EarCut.equals(a, b) || a.next.i !== b.i && a.prev.i !== b.i && !Phaser.EarCut.intersectsPolygon(a, b) &&
  43781. Phaser.EarCut.locallyInside(a, b) && Phaser.EarCut.locallyInside(b, a) && Phaser.EarCut.middleInside(a, b);
  43782. };
  43783. // signed area of a triangle
  43784. Phaser.EarCut.area = function (p, q, r) {
  43785. return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
  43786. };
  43787. // check if two points are equal
  43788. Phaser.EarCut.equals = function (p1, p2) {
  43789. return p1.x === p2.x && p1.y === p2.y;
  43790. };
  43791. // check if two segments intersect
  43792. Phaser.EarCut.intersects = function (p1, q1, p2, q2) {
  43793. return Phaser.EarCut.area(p1, q1, p2) > 0 !== Phaser.EarCut.area(p1, q1, q2) > 0 &&
  43794. Phaser.EarCut.area(p2, q2, p1) > 0 !== Phaser.EarCut.area(p2, q2, q1) > 0;
  43795. };
  43796. // check if a polygon diagonal intersects any polygon segments
  43797. Phaser.EarCut.intersectsPolygon = function (a, b) {
  43798. var p = a;
  43799. do {
  43800. if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
  43801. Phaser.EarCut.intersects(p, p.next, a, b)) return true;
  43802. p = p.next;
  43803. } while (p !== a);
  43804. return false;
  43805. };
  43806. // check if a polygon diagonal is locally inside the polygon
  43807. Phaser.EarCut.locallyInside = function (a, b) {
  43808. return Phaser.EarCut.area(a.prev, a, a.next) < 0 ?
  43809. Phaser.EarCut.area(a, b, a.next) >= 0 && Phaser.EarCut.area(a, a.prev, b) >= 0 :
  43810. Phaser.EarCut.area(a, b, a.prev) < 0 || Phaser.EarCut.area(a, a.next, b) < 0;
  43811. };
  43812. // check if the middle point of a polygon diagonal is inside the polygon
  43813. Phaser.EarCut.middleInside = function (a, b) {
  43814. var p = a,
  43815. inside = false,
  43816. px = (a.x + b.x) / 2,
  43817. py = (a.y + b.y) / 2;
  43818. do {
  43819. if (((p.y > py) !== (p.next.y > py)) && (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
  43820. inside = !inside;
  43821. p = p.next;
  43822. } while (p !== a);
  43823. return inside;
  43824. };
  43825. // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
  43826. // if one belongs to the outer ring and another to a hole, it merges it into a single ring
  43827. Phaser.EarCut.splitPolygon = function (a, b) {
  43828. var a2 = new Phaser.EarCut.Node(a.i, a.x, a.y),
  43829. b2 = new Phaser.EarCut.Node(b.i, b.x, b.y),
  43830. an = a.next,
  43831. bp = b.prev;
  43832. a.next = b;
  43833. b.prev = a;
  43834. a2.next = an;
  43835. an.prev = a2;
  43836. b2.next = a2;
  43837. a2.prev = b2;
  43838. bp.next = b2;
  43839. b2.prev = bp;
  43840. return b2;
  43841. };
  43842. // create a node and optionally link it with previous one (in a circular doubly linked list)
  43843. Phaser.EarCut.insertNode = function (i, x, y, last) {
  43844. var p = new Phaser.EarCut.Node(i, x, y);
  43845. if (!last) {
  43846. p.prev = p;
  43847. p.next = p;
  43848. } else {
  43849. p.next = last.next;
  43850. p.prev = last;
  43851. last.next.prev = p;
  43852. last.next = p;
  43853. }
  43854. return p;
  43855. };
  43856. Phaser.EarCut.removeNode = function (p) {
  43857. p.next.prev = p.prev;
  43858. p.prev.next = p.next;
  43859. if (p.prevZ) p.prevZ.nextZ = p.nextZ;
  43860. if (p.nextZ) p.nextZ.prevZ = p.prevZ;
  43861. };
  43862. Phaser.EarCut.Node = function (i, x, y) {
  43863. // vertice index in coordinates array
  43864. this.i = i;
  43865. // vertex coordinates
  43866. this.x = x;
  43867. this.y = y;
  43868. // previous and next vertice nodes in a polygon ring
  43869. this.prev = null;
  43870. this.next = null;
  43871. // z-order curve value
  43872. this.z = null;
  43873. // previous and next nodes in z-order
  43874. this.prevZ = null;
  43875. this.nextZ = null;
  43876. // indicates whether this is a steiner point
  43877. this.steiner = false;
  43878. };
  43879. /* jshint ignore:end */
  43880. /**
  43881. * @author Mat Groves http://matgroves.com/ @Doormat23
  43882. */
  43883. /**
  43884. * A set of functions used by the webGL renderer to draw the primitive graphics data
  43885. *
  43886. * @class PIXI.WebGLGraphics
  43887. * @private
  43888. * @static
  43889. */
  43890. PIXI.WebGLGraphics = function()
  43891. {
  43892. };
  43893. /**
  43894. * The number of points beyond which Pixi swaps to using the Stencil Buffer to render the Graphics.
  43895. *
  43896. * @type {number}
  43897. */
  43898. PIXI.WebGLGraphics.stencilBufferLimit = 6;
  43899. /**
  43900. * Renders the graphics object
  43901. *
  43902. * @static
  43903. * @private
  43904. * @method PIXI.WebGLGraphics.renderGraphics
  43905. * @param graphics {Graphics}
  43906. * @param renderSession {Object}
  43907. */
  43908. PIXI.WebGLGraphics.renderGraphics = function(graphics, renderSession)//projection, offset)
  43909. {
  43910. var gl = renderSession.gl;
  43911. var projection = renderSession.projection,
  43912. offset = renderSession.offset,
  43913. shader = renderSession.shaderManager.primitiveShader,
  43914. webGLData;
  43915. if(graphics.dirty)
  43916. {
  43917. PIXI.WebGLGraphics.updateGraphics(graphics, gl);
  43918. }
  43919. var webGL = graphics._webGL[gl.id];
  43920. // if the graphics object does not exist in the webGL context skip rendering!
  43921. if(!webGL)
  43922. {
  43923. return;
  43924. }
  43925. // This could be speeded up for sure!
  43926. for (var i = 0; i < webGL.data.length; i++)
  43927. {
  43928. if(webGL.data[i].mode === 1)
  43929. {
  43930. webGLData = webGL.data[i];
  43931. renderSession.stencilManager.pushStencil(graphics, webGLData, renderSession);
  43932. // render quad..
  43933. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 );
  43934. renderSession.stencilManager.popStencil(graphics, webGLData, renderSession);
  43935. }
  43936. else
  43937. {
  43938. webGLData = webGL.data[i];
  43939. renderSession.shaderManager.setShader( shader );//activatePrimitiveShader();
  43940. shader = renderSession.shaderManager.primitiveShader;
  43941. gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true));
  43942. gl.uniform1f(shader.flipY, 1);
  43943. gl.uniform2f(shader.projectionVector, projection.x, -projection.y);
  43944. gl.uniform2f(shader.offsetVector, -offset.x, -offset.y);
  43945. gl.uniform3fv(shader.tintColor, Phaser.Color.hexToRGBArray(graphics.tint));
  43946. gl.uniform1f(shader.alpha, graphics.worldAlpha);
  43947. gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer);
  43948. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0);
  43949. gl.vertexAttribPointer(shader.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4);
  43950. // set the index buffer!
  43951. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer);
  43952. gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 );
  43953. }
  43954. }
  43955. };
  43956. /**
  43957. * Updates the graphics object
  43958. *
  43959. * @static
  43960. * @private
  43961. * @method PIXI.WebGLGraphics.updateGraphics
  43962. * @param graphicsData {Graphics} The graphics object to update
  43963. * @param gl {WebGLContext} the current WebGL drawing context
  43964. */
  43965. PIXI.WebGLGraphics.updateGraphics = function(graphics, gl)
  43966. {
  43967. // get the contexts graphics object
  43968. var webGL = graphics._webGL[gl.id];
  43969. // if the graphics object does not exist in the webGL context time to create it!
  43970. if(!webGL)webGL = graphics._webGL[gl.id] = {lastIndex:0, data:[], gl:gl};
  43971. // flag the graphics as not dirty as we are about to update it...
  43972. graphics.dirty = false;
  43973. var i;
  43974. // if the user cleared the graphics object we will need to clear every object
  43975. if(graphics.clearDirty)
  43976. {
  43977. graphics.clearDirty = false;
  43978. // lop through and return all the webGLDatas to the object pool so than can be reused later on
  43979. for (i = 0; i < webGL.data.length; i++)
  43980. {
  43981. var graphicsData = webGL.data[i];
  43982. graphicsData.reset();
  43983. PIXI.WebGLGraphics.graphicsDataPool.push( graphicsData );
  43984. }
  43985. // clear the array and reset the index..
  43986. webGL.data = [];
  43987. webGL.lastIndex = 0;
  43988. }
  43989. var webGLData;
  43990. // loop through the graphics datas and construct each one..
  43991. // if the object is a complex fill then the new stencil buffer technique will be used
  43992. // other wise graphics objects will be pushed into a batch..
  43993. for (i = webGL.lastIndex; i < graphics.graphicsData.length; i++)
  43994. {
  43995. var data = graphics.graphicsData[i];
  43996. if (data.type === Phaser.POLYGON)
  43997. {
  43998. // need to add the points the the graphics object..
  43999. data.points = data.shape.points.slice();
  44000. if(data.shape.closed)
  44001. {
  44002. // close the poly if the value is true!
  44003. if(data.points[0] !== data.points[data.points.length-2] || data.points[1] !== data.points[data.points.length-1])
  44004. {
  44005. data.points.push(data.points[0], data.points[1]);
  44006. }
  44007. }
  44008. // MAKE SURE WE HAVE THE CORRECT TYPE..
  44009. if(data.fill)
  44010. {
  44011. if(data.points.length >= PIXI.WebGLGraphics.stencilBufferLimit)
  44012. {
  44013. if(data.points.length < PIXI.WebGLGraphics.stencilBufferLimit * 2)
  44014. {
  44015. webGLData = PIXI.WebGLGraphics.switchMode(webGL, 0);
  44016. var canDrawUsingSimple = PIXI.WebGLGraphics.buildPoly(data, webGLData);
  44017. // console.log(canDrawUsingSimple);
  44018. if(!canDrawUsingSimple)
  44019. {
  44020. // console.log("<>>>")
  44021. webGLData = PIXI.WebGLGraphics.switchMode(webGL, 1);
  44022. PIXI.WebGLGraphics.buildComplexPoly(data, webGLData);
  44023. }
  44024. }
  44025. else
  44026. {
  44027. webGLData = PIXI.WebGLGraphics.switchMode(webGL, 1);
  44028. PIXI.WebGLGraphics.buildComplexPoly(data, webGLData);
  44029. }
  44030. }
  44031. }
  44032. if(data.lineWidth > 0)
  44033. {
  44034. webGLData = PIXI.WebGLGraphics.switchMode(webGL, 0);
  44035. PIXI.WebGLGraphics.buildLine(data, webGLData);
  44036. }
  44037. }
  44038. else
  44039. {
  44040. webGLData = PIXI.WebGLGraphics.switchMode(webGL, 0);
  44041. if (data.type === Phaser.RECTANGLE)
  44042. {
  44043. PIXI.WebGLGraphics.buildRectangle(data, webGLData);
  44044. }
  44045. else if (data.type === Phaser.CIRCLE || data.type === Phaser.ELLIPSE)
  44046. {
  44047. PIXI.WebGLGraphics.buildCircle(data, webGLData);
  44048. }
  44049. else if (data.type === Phaser.ROUNDEDRECTANGLE)
  44050. {
  44051. PIXI.WebGLGraphics.buildRoundedRectangle(data, webGLData);
  44052. }
  44053. }
  44054. webGL.lastIndex++;
  44055. }
  44056. // upload all the dirty data...
  44057. for (i = 0; i < webGL.data.length; i++)
  44058. {
  44059. webGLData = webGL.data[i];
  44060. if(webGLData.dirty)webGLData.upload();
  44061. }
  44062. };
  44063. /**
  44064. * @static
  44065. * @private
  44066. * @method PIXI.WebGLGraphics.switchMode
  44067. * @param webGL {WebGLContext}
  44068. * @param type {Number}
  44069. */
  44070. PIXI.WebGLGraphics.switchMode = function(webGL, type)
  44071. {
  44072. var webGLData;
  44073. if(!webGL.data.length)
  44074. {
  44075. webGLData = PIXI.WebGLGraphics.graphicsDataPool.pop() || new PIXI.WebGLGraphicsData(webGL.gl);
  44076. webGLData.mode = type;
  44077. webGL.data.push(webGLData);
  44078. }
  44079. else
  44080. {
  44081. webGLData = webGL.data[webGL.data.length-1];
  44082. if(webGLData.mode !== type || type === 1)
  44083. {
  44084. webGLData = PIXI.WebGLGraphics.graphicsDataPool.pop() || new PIXI.WebGLGraphicsData(webGL.gl);
  44085. webGLData.mode = type;
  44086. webGL.data.push(webGLData);
  44087. }
  44088. }
  44089. webGLData.dirty = true;
  44090. return webGLData;
  44091. };
  44092. /**
  44093. * Builds a rectangle to draw
  44094. *
  44095. * @static
  44096. * @private
  44097. * @method PIXI.WebGLGraphics.buildRectangle
  44098. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  44099. * @param webGLData {Object}
  44100. */
  44101. PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData)
  44102. {
  44103. // --- //
  44104. // need to convert points to a nice regular data
  44105. //
  44106. var rectData = graphicsData.shape;
  44107. var x = rectData.x;
  44108. var y = rectData.y;
  44109. var width = rectData.width;
  44110. var height = rectData.height;
  44111. if(graphicsData.fill)
  44112. {
  44113. var color = Phaser.Color.hexToRGBArray(graphicsData.fillColor);
  44114. var alpha = graphicsData.fillAlpha;
  44115. var r = color[0] * alpha;
  44116. var g = color[1] * alpha;
  44117. var b = color[2] * alpha;
  44118. var verts = webGLData.points;
  44119. var indices = webGLData.indices;
  44120. var vertPos = verts.length / 6;
  44121. // start
  44122. verts.push(x, y);
  44123. verts.push(r, g, b, alpha);
  44124. verts.push(x + width, y);
  44125. verts.push(r, g, b, alpha);
  44126. verts.push(x , y + height);
  44127. verts.push(r, g, b, alpha);
  44128. verts.push(x + width, y + height);
  44129. verts.push(r, g, b, alpha);
  44130. // insert 2 dead triangles..
  44131. indices.push(vertPos, vertPos, vertPos + 1, vertPos + 2, vertPos + 3, vertPos + 3);
  44132. }
  44133. if (graphicsData.lineWidth)
  44134. {
  44135. var tempPoints = graphicsData.points;
  44136. graphicsData.points = [x, y,
  44137. x + width, y,
  44138. x + width, y + height,
  44139. x, y + height,
  44140. x, y];
  44141. PIXI.WebGLGraphics.buildLine(graphicsData, webGLData);
  44142. graphicsData.points = tempPoints;
  44143. }
  44144. };
  44145. /**
  44146. * Builds a rounded rectangle to draw
  44147. *
  44148. * @static
  44149. * @private
  44150. * @method PIXI.WebGLGraphics.buildRoundedRectangle
  44151. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  44152. * @param webGLData {Object}
  44153. */
  44154. PIXI.WebGLGraphics.buildRoundedRectangle = function(graphicsData, webGLData)
  44155. {
  44156. var rrectData = graphicsData.shape;
  44157. var x = rrectData.x;
  44158. var y = rrectData.y;
  44159. var width = rrectData.width;
  44160. var height = rrectData.height;
  44161. var radius = rrectData.radius;
  44162. var recPoints = [];
  44163. recPoints.push(x, y + radius);
  44164. recPoints = recPoints.concat(PIXI.WebGLGraphics.quadraticBezierCurve(x, y + height - radius, x, y + height, x + radius, y + height));
  44165. recPoints = recPoints.concat(PIXI.WebGLGraphics.quadraticBezierCurve(x + width - radius, y + height, x + width, y + height, x + width, y + height - radius));
  44166. recPoints = recPoints.concat(PIXI.WebGLGraphics.quadraticBezierCurve(x + width, y + radius, x + width, y, x + width - radius, y));
  44167. recPoints = recPoints.concat(PIXI.WebGLGraphics.quadraticBezierCurve(x + radius, y, x, y, x, y + radius));
  44168. if (graphicsData.fill) {
  44169. var color = Phaser.Color.hexToRGBArray(graphicsData.fillColor);
  44170. var alpha = graphicsData.fillAlpha;
  44171. var r = color[0] * alpha;
  44172. var g = color[1] * alpha;
  44173. var b = color[2] * alpha;
  44174. var verts = webGLData.points;
  44175. var indices = webGLData.indices;
  44176. var vecPos = verts.length / 6;
  44177. var triangles = Phaser.EarCut.Triangulate(recPoints, null, 2);
  44178. var i = 0;
  44179. for (i = 0; i < triangles.length; i+=3)
  44180. {
  44181. indices.push(triangles[i] + vecPos);
  44182. indices.push(triangles[i] + vecPos);
  44183. indices.push(triangles[i+1] + vecPos);
  44184. indices.push(triangles[i+2] + vecPos);
  44185. indices.push(triangles[i+2] + vecPos);
  44186. }
  44187. for (i = 0; i < recPoints.length; i++)
  44188. {
  44189. verts.push(recPoints[i], recPoints[++i], r, g, b, alpha);
  44190. }
  44191. }
  44192. if (graphicsData.lineWidth) {
  44193. var tempPoints = graphicsData.points;
  44194. graphicsData.points = recPoints;
  44195. PIXI.WebGLGraphics.buildLine(graphicsData, webGLData);
  44196. graphicsData.points = tempPoints;
  44197. }
  44198. };
  44199. /**
  44200. * Calculate the points for a quadratic bezier curve. (helper function..)
  44201. * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c
  44202. *
  44203. * @static
  44204. * @private
  44205. * @method PIXI.WebGLGraphics.quadraticBezierCurve
  44206. * @param fromX {Number} Origin point x
  44207. * @param fromY {Number} Origin point x
  44208. * @param cpX {Number} Control point x
  44209. * @param cpY {Number} Control point y
  44210. * @param toX {Number} Destination point x
  44211. * @param toY {Number} Destination point y
  44212. * @return {Array(Number)}
  44213. */
  44214. PIXI.WebGLGraphics.quadraticBezierCurve = function(fromX, fromY, cpX, cpY, toX, toY) {
  44215. var xa,
  44216. ya,
  44217. xb,
  44218. yb,
  44219. x,
  44220. y,
  44221. n = 20,
  44222. points = [];
  44223. function getPt(n1 , n2, perc) {
  44224. var diff = n2 - n1;
  44225. return n1 + ( diff * perc );
  44226. }
  44227. var j = 0;
  44228. for (var i = 0; i <= n; i++ )
  44229. {
  44230. j = i / n;
  44231. // The Green Line
  44232. xa = getPt( fromX , cpX , j );
  44233. ya = getPt( fromY , cpY , j );
  44234. xb = getPt( cpX , toX , j );
  44235. yb = getPt( cpY , toY , j );
  44236. // The Black Dot
  44237. x = getPt( xa , xb , j );
  44238. y = getPt( ya , yb , j );
  44239. points.push(x, y);
  44240. }
  44241. return points;
  44242. };
  44243. /**
  44244. * Builds a circle to draw
  44245. *
  44246. * @static
  44247. * @private
  44248. * @method PIXI.WebGLGraphics.buildCircle
  44249. * @param graphicsData {Graphics} The graphics object to draw
  44250. * @param webGLData {Object}
  44251. */
  44252. PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData)
  44253. {
  44254. // need to convert points to a nice regular data
  44255. var circleData = graphicsData.shape;
  44256. var x = circleData.x;
  44257. var y = circleData.y;
  44258. var width;
  44259. var height;
  44260. // TODO - bit hacky??
  44261. if (graphicsData.type === Phaser.CIRCLE)
  44262. {
  44263. width = circleData.radius;
  44264. height = circleData.radius;
  44265. }
  44266. else
  44267. {
  44268. width = circleData.width;
  44269. height = circleData.height;
  44270. }
  44271. var totalSegs = 40;
  44272. var seg = (Math.PI * 2) / totalSegs ;
  44273. var i = 0;
  44274. if(graphicsData.fill)
  44275. {
  44276. var color = Phaser.Color.hexToRGBArray(graphicsData.fillColor);
  44277. var alpha = graphicsData.fillAlpha;
  44278. var r = color[0] * alpha;
  44279. var g = color[1] * alpha;
  44280. var b = color[2] * alpha;
  44281. var verts = webGLData.points;
  44282. var indices = webGLData.indices;
  44283. var vecPos = verts.length / 6;
  44284. indices.push(vecPos);
  44285. for (i = 0; i < totalSegs + 1 ; i++)
  44286. {
  44287. verts.push(x,y, r, g, b, alpha);
  44288. verts.push(x + Math.sin(seg * i) * width,
  44289. y + Math.cos(seg * i) * height,
  44290. r, g, b, alpha);
  44291. indices.push(vecPos++, vecPos++);
  44292. }
  44293. indices.push(vecPos-1);
  44294. }
  44295. if(graphicsData.lineWidth)
  44296. {
  44297. var tempPoints = graphicsData.points;
  44298. graphicsData.points = [];
  44299. for (i = 0; i < totalSegs + 1; i++)
  44300. {
  44301. graphicsData.points.push(x + Math.sin(seg * i) * width,
  44302. y + Math.cos(seg * i) * height);
  44303. }
  44304. PIXI.WebGLGraphics.buildLine(graphicsData, webGLData);
  44305. graphicsData.points = tempPoints;
  44306. }
  44307. };
  44308. /**
  44309. * Builds a line to draw
  44310. *
  44311. * @static
  44312. * @private
  44313. * @method PIXI.WebGLGraphics.buildLine
  44314. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  44315. * @param webGLData {Object}
  44316. */
  44317. PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData)
  44318. {
  44319. // TODO OPTIMISE!
  44320. var i = 0;
  44321. var points = graphicsData.points;
  44322. if(points.length === 0)return;
  44323. // if the line width is an odd number add 0.5 to align to a whole pixel
  44324. if(graphicsData.lineWidth%2)
  44325. {
  44326. for (i = 0; i < points.length; i++) {
  44327. points[i] += 0.5;
  44328. }
  44329. }
  44330. // get first and last point.. figure out the middle!
  44331. var firstPoint = new PIXI.Point( points[0], points[1] );
  44332. var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] );
  44333. // if the first point is the last point - gonna have issues :)
  44334. if(firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y)
  44335. {
  44336. // need to clone as we are going to slightly modify the shape..
  44337. points = points.slice();
  44338. points.pop();
  44339. points.pop();
  44340. lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] );
  44341. var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5;
  44342. var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5;
  44343. points.unshift(midPointX, midPointY);
  44344. points.push(midPointX, midPointY);
  44345. }
  44346. var verts = webGLData.points;
  44347. var indices = webGLData.indices;
  44348. var length = points.length / 2;
  44349. var indexCount = points.length;
  44350. var indexStart = verts.length/6;
  44351. // DRAW the Line
  44352. var width = graphicsData.lineWidth / 2;
  44353. // sort color
  44354. var color = Phaser.Color.hexToRGBArray(graphicsData.lineColor);
  44355. var alpha = graphicsData.lineAlpha;
  44356. var r = color[0] * alpha;
  44357. var g = color[1] * alpha;
  44358. var b = color[2] * alpha;
  44359. var px, py, p1x, p1y, p2x, p2y, p3x, p3y;
  44360. var perpx, perpy, perp2x, perp2y, perp3x, perp3y;
  44361. var a1, b1, c1, a2, b2, c2;
  44362. var denom, pdist, dist;
  44363. p1x = points[0];
  44364. p1y = points[1];
  44365. p2x = points[2];
  44366. p2y = points[3];
  44367. perpx = -(p1y - p2y);
  44368. perpy = p1x - p2x;
  44369. dist = Math.sqrt(perpx*perpx + perpy*perpy);
  44370. perpx /= dist;
  44371. perpy /= dist;
  44372. perpx *= width;
  44373. perpy *= width;
  44374. // start
  44375. verts.push(p1x - perpx , p1y - perpy,
  44376. r, g, b, alpha);
  44377. verts.push(p1x + perpx , p1y + perpy,
  44378. r, g, b, alpha);
  44379. for (i = 1; i < length-1; i++)
  44380. {
  44381. p1x = points[(i-1)*2];
  44382. p1y = points[(i-1)*2 + 1];
  44383. p2x = points[(i)*2];
  44384. p2y = points[(i)*2 + 1];
  44385. p3x = points[(i+1)*2];
  44386. p3y = points[(i+1)*2 + 1];
  44387. perpx = -(p1y - p2y);
  44388. perpy = p1x - p2x;
  44389. dist = Math.sqrt(perpx*perpx + perpy*perpy);
  44390. perpx /= dist;
  44391. perpy /= dist;
  44392. perpx *= width;
  44393. perpy *= width;
  44394. perp2x = -(p2y - p3y);
  44395. perp2y = p2x - p3x;
  44396. dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y);
  44397. perp2x /= dist;
  44398. perp2y /= dist;
  44399. perp2x *= width;
  44400. perp2y *= width;
  44401. a1 = (-perpy + p1y) - (-perpy + p2y);
  44402. b1 = (-perpx + p2x) - (-perpx + p1x);
  44403. c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y);
  44404. a2 = (-perp2y + p3y) - (-perp2y + p2y);
  44405. b2 = (-perp2x + p2x) - (-perp2x + p3x);
  44406. c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y);
  44407. denom = a1*b2 - a2*b1;
  44408. if(Math.abs(denom) < 0.1 )
  44409. {
  44410. denom+=10.1;
  44411. verts.push(p2x - perpx , p2y - perpy,
  44412. r, g, b, alpha);
  44413. verts.push(p2x + perpx , p2y + perpy,
  44414. r, g, b, alpha);
  44415. continue;
  44416. }
  44417. px = (b1*c2 - b2*c1)/denom;
  44418. py = (a2*c1 - a1*c2)/denom;
  44419. pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y);
  44420. if(pdist > 140 * 140)
  44421. {
  44422. perp3x = perpx - perp2x;
  44423. perp3y = perpy - perp2y;
  44424. dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y);
  44425. perp3x /= dist;
  44426. perp3y /= dist;
  44427. perp3x *= width;
  44428. perp3y *= width;
  44429. verts.push(p2x - perp3x, p2y -perp3y);
  44430. verts.push(r, g, b, alpha);
  44431. verts.push(p2x + perp3x, p2y +perp3y);
  44432. verts.push(r, g, b, alpha);
  44433. verts.push(p2x - perp3x, p2y -perp3y);
  44434. verts.push(r, g, b, alpha);
  44435. indexCount++;
  44436. }
  44437. else
  44438. {
  44439. verts.push(px , py);
  44440. verts.push(r, g, b, alpha);
  44441. verts.push(p2x - (px-p2x), p2y - (py - p2y));
  44442. verts.push(r, g, b, alpha);
  44443. }
  44444. }
  44445. p1x = points[(length-2)*2];
  44446. p1y = points[(length-2)*2 + 1];
  44447. p2x = points[(length-1)*2];
  44448. p2y = points[(length-1)*2 + 1];
  44449. perpx = -(p1y - p2y);
  44450. perpy = p1x - p2x;
  44451. dist = Math.sqrt(perpx*perpx + perpy*perpy);
  44452. perpx /= dist;
  44453. perpy /= dist;
  44454. perpx *= width;
  44455. perpy *= width;
  44456. verts.push(p2x - perpx , p2y - perpy);
  44457. verts.push(r, g, b, alpha);
  44458. verts.push(p2x + perpx , p2y + perpy);
  44459. verts.push(r, g, b, alpha);
  44460. indices.push(indexStart);
  44461. for (i = 0; i < indexCount; i++)
  44462. {
  44463. indices.push(indexStart++);
  44464. }
  44465. indices.push(indexStart-1);
  44466. };
  44467. /**
  44468. * Builds a complex polygon to draw
  44469. *
  44470. * @static
  44471. * @private
  44472. * @method PIXI.WebGLGraphics.buildComplexPoly
  44473. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  44474. * @param webGLData {Object}
  44475. */
  44476. PIXI.WebGLGraphics.buildComplexPoly = function(graphicsData, webGLData)
  44477. {
  44478. //TODO - no need to copy this as it gets turned into a FLoat32Array anyways..
  44479. var points = graphicsData.points.slice();
  44480. if(points.length < 6)return;
  44481. // get first and last point.. figure out the middle!
  44482. var indices = webGLData.indices;
  44483. webGLData.points = points;
  44484. webGLData.alpha = graphicsData.fillAlpha;
  44485. webGLData.color = Phaser.Color.hexToRGBArray(graphicsData.fillColor);
  44486. /*
  44487. calclate the bounds..
  44488. */
  44489. var minX = Infinity;
  44490. var maxX = -Infinity;
  44491. var minY = Infinity;
  44492. var maxY = -Infinity;
  44493. var x,y;
  44494. // get size..
  44495. for (var i = 0; i < points.length; i+=2)
  44496. {
  44497. x = points[i];
  44498. y = points[i+1];
  44499. minX = x < minX ? x : minX;
  44500. maxX = x > maxX ? x : maxX;
  44501. minY = y < minY ? y : minY;
  44502. maxY = y > maxY ? y : maxY;
  44503. }
  44504. // add a quad to the end cos there is no point making another buffer!
  44505. points.push(minX, minY,
  44506. maxX, minY,
  44507. maxX, maxY,
  44508. minX, maxY);
  44509. // push a quad onto the end..
  44510. //TODO - this aint needed!
  44511. var length = points.length / 2;
  44512. for (i = 0; i < length; i++)
  44513. {
  44514. indices.push( i );
  44515. }
  44516. };
  44517. /**
  44518. * Builds a polygon to draw
  44519. *
  44520. * @static
  44521. * @private
  44522. * @method PIXI.WebGLGraphics.buildPoly
  44523. * @param graphicsData {Graphics} The graphics object containing all the necessary properties
  44524. * @param webGLData {Object}
  44525. */
  44526. PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData)
  44527. {
  44528. var points = graphicsData.points;
  44529. if(points.length < 6)return;
  44530. // get first and last point.. figure out the middle!
  44531. var verts = webGLData.points;
  44532. var indices = webGLData.indices;
  44533. var length = points.length / 2;
  44534. // sort color
  44535. var color = Phaser.Color.hexToRGBArray(graphicsData.fillColor);
  44536. var alpha = graphicsData.fillAlpha;
  44537. var r = color[0] * alpha;
  44538. var g = color[1] * alpha;
  44539. var b = color[2] * alpha;
  44540. var triangles = Phaser.EarCut.Triangulate(points, null, 2);
  44541. if(!triangles)return false;
  44542. var vertPos = verts.length / 6;
  44543. var i = 0;
  44544. for (i = 0; i < triangles.length; i+=3)
  44545. {
  44546. indices.push(triangles[i] + vertPos);
  44547. indices.push(triangles[i] + vertPos);
  44548. indices.push(triangles[i+1] + vertPos);
  44549. indices.push(triangles[i+2] +vertPos);
  44550. indices.push(triangles[i+2] + vertPos);
  44551. }
  44552. for (i = 0; i < length; i++)
  44553. {
  44554. verts.push(points[i * 2], points[i * 2 + 1],
  44555. r, g, b, alpha);
  44556. }
  44557. return true;
  44558. };
  44559. PIXI.WebGLGraphics.graphicsDataPool = [];
  44560. /**
  44561. * @class WebGLGraphicsData
  44562. * @private
  44563. * @static
  44564. */
  44565. PIXI.WebGLGraphicsData = function(gl)
  44566. {
  44567. this.gl = gl;
  44568. //TODO does this need to be split before uploding??
  44569. this.color = [0,0,0]; // color split!
  44570. this.points = [];
  44571. this.indices = [];
  44572. this.buffer = gl.createBuffer();
  44573. this.indexBuffer = gl.createBuffer();
  44574. this.mode = 1;
  44575. this.alpha = 1;
  44576. this.dirty = true;
  44577. };
  44578. /**
  44579. * @method PIXI.WebGLGraphics.reset
  44580. */
  44581. PIXI.WebGLGraphicsData.prototype.reset = function()
  44582. {
  44583. this.points = [];
  44584. this.indices = [];
  44585. };
  44586. /**
  44587. * @method PIXI.WebGLGraphics.upload
  44588. */
  44589. PIXI.WebGLGraphicsData.prototype.upload = function()
  44590. {
  44591. var gl = this.gl;
  44592. // this.lastIndex = graphics.graphicsData.length;
  44593. this.glPoints = new Float32Array(this.points);
  44594. gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
  44595. gl.bufferData(gl.ARRAY_BUFFER, this.glPoints, gl.STATIC_DRAW);
  44596. this.glIndicies = new Uint16Array(this.indices);
  44597. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
  44598. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.glIndicies, gl.STATIC_DRAW);
  44599. this.dirty = false;
  44600. };
  44601. /**
  44602. * @author Mat Groves http://matgroves.com/ @Doormat23
  44603. */
  44604. /**
  44605. * A set of functions used by the canvas renderer to draw the primitive graphics data.
  44606. *
  44607. * @class PIXI.CanvasGraphics
  44608. * @static
  44609. */
  44610. PIXI.CanvasGraphics = function()
  44611. {
  44612. };
  44613. /**
  44614. * Renders a {@link Phaser.Graphics} object to a canvas.
  44615. *
  44616. * @method PIXI.CanvasGraphics.renderGraphics
  44617. * @static
  44618. * @param graphics {Graphics} the actual graphics object to render
  44619. * @param context {CanvasRenderingContext2D} the 2d drawing method of the canvas
  44620. */
  44621. PIXI.CanvasGraphics.renderGraphics = function(graphics, context)
  44622. {
  44623. var worldAlpha = graphics.worldAlpha;
  44624. if (graphics.dirty)
  44625. {
  44626. this.updateGraphicsTint(graphics);
  44627. graphics.dirty = false;
  44628. }
  44629. for (var i = 0; i < graphics.graphicsData.length; i++)
  44630. {
  44631. var data = graphics.graphicsData[i];
  44632. var shape = data.shape;
  44633. var fillColor = data._fillTint;
  44634. var lineColor = data._lineTint;
  44635. context.lineWidth = data.lineWidth;
  44636. if (data.type === Phaser.POLYGON)
  44637. {
  44638. context.beginPath();
  44639. var points = shape.points;
  44640. context.moveTo(points[0], points[1]);
  44641. for (var j=1; j < points.length/2; j++)
  44642. {
  44643. context.lineTo(points[j * 2], points[j * 2 + 1]);
  44644. }
  44645. if (shape.closed)
  44646. {
  44647. context.lineTo(points[0], points[1]);
  44648. }
  44649. // if the first and last point are the same close the path - much neater :)
  44650. if (points[0] === points[points.length-2] && points[1] === points[points.length-1])
  44651. {
  44652. context.closePath();
  44653. }
  44654. if (data.fill)
  44655. {
  44656. context.globalAlpha = data.fillAlpha * worldAlpha;
  44657. context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6);
  44658. context.fill();
  44659. }
  44660. if (data.lineWidth)
  44661. {
  44662. context.globalAlpha = data.lineAlpha * worldAlpha;
  44663. context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6);
  44664. context.stroke();
  44665. }
  44666. }
  44667. else if (data.type === Phaser.RECTANGLE)
  44668. {
  44669. if (data.fillColor || data.fillColor === 0)
  44670. {
  44671. context.globalAlpha = data.fillAlpha * worldAlpha;
  44672. context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6);
  44673. context.fillRect(shape.x, shape.y, shape.width, shape.height);
  44674. }
  44675. if (data.lineWidth)
  44676. {
  44677. context.globalAlpha = data.lineAlpha * worldAlpha;
  44678. context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6);
  44679. context.strokeRect(shape.x, shape.y, shape.width, shape.height);
  44680. }
  44681. }
  44682. else if (data.type === Phaser.CIRCLE)
  44683. {
  44684. // TODO - need to be Undefined!
  44685. context.beginPath();
  44686. context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI);
  44687. context.closePath();
  44688. if (data.fill)
  44689. {
  44690. context.globalAlpha = data.fillAlpha * worldAlpha;
  44691. context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6);
  44692. context.fill();
  44693. }
  44694. if (data.lineWidth)
  44695. {
  44696. context.globalAlpha = data.lineAlpha * worldAlpha;
  44697. context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6);
  44698. context.stroke();
  44699. }
  44700. }
  44701. else if (data.type === Phaser.ELLIPSE)
  44702. {
  44703. // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
  44704. var w = shape.width * 2;
  44705. var h = shape.height * 2;
  44706. var x = shape.x - w/2;
  44707. var y = shape.y - h/2;
  44708. context.beginPath();
  44709. var kappa = 0.5522848,
  44710. ox = (w / 2) * kappa, // control point offset horizontal
  44711. oy = (h / 2) * kappa, // control point offset vertical
  44712. xe = x + w, // x-end
  44713. ye = y + h, // y-end
  44714. xm = x + w / 2, // x-middle
  44715. ym = y + h / 2; // y-middle
  44716. context.moveTo(x, ym);
  44717. context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  44718. context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  44719. context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  44720. context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  44721. context.closePath();
  44722. if (data.fill)
  44723. {
  44724. context.globalAlpha = data.fillAlpha * worldAlpha;
  44725. context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6);
  44726. context.fill();
  44727. }
  44728. if (data.lineWidth)
  44729. {
  44730. context.globalAlpha = data.lineAlpha * worldAlpha;
  44731. context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6);
  44732. context.stroke();
  44733. }
  44734. }
  44735. else if (data.type === Phaser.ROUNDEDRECTANGLE)
  44736. {
  44737. var rx = shape.x;
  44738. var ry = shape.y;
  44739. var width = shape.width;
  44740. var height = shape.height;
  44741. var radius = shape.radius;
  44742. var maxRadius = Math.min(width, height) / 2 | 0;
  44743. radius = radius > maxRadius ? maxRadius : radius;
  44744. context.beginPath();
  44745. context.moveTo(rx, ry + radius);
  44746. context.lineTo(rx, ry + height - radius);
  44747. context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height);
  44748. context.lineTo(rx + width - radius, ry + height);
  44749. context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius);
  44750. context.lineTo(rx + width, ry + radius);
  44751. context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry);
  44752. context.lineTo(rx + radius, ry);
  44753. context.quadraticCurveTo(rx, ry, rx, ry + radius);
  44754. context.closePath();
  44755. if (data.fillColor || data.fillColor === 0)
  44756. {
  44757. context.globalAlpha = data.fillAlpha * worldAlpha;
  44758. context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6);
  44759. context.fill();
  44760. }
  44761. if (data.lineWidth)
  44762. {
  44763. context.globalAlpha = data.lineAlpha * worldAlpha;
  44764. context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6);
  44765. context.stroke();
  44766. }
  44767. }
  44768. }
  44769. };
  44770. /**
  44771. * Renders a graphics mask
  44772. *
  44773. * @static
  44774. * @private
  44775. * @method PIXI.CanvasGraphics.renderGraphicsMask
  44776. * @param graphics {Graphics} the graphics which will be used as a mask
  44777. * @param context {CanvasRenderingContext2D} the context 2d method of the canvas
  44778. */
  44779. PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context)
  44780. {
  44781. var len = graphics.graphicsData.length;
  44782. if (len === 0)
  44783. {
  44784. return;
  44785. }
  44786. context.beginPath();
  44787. for (var i = 0; i < len; i++)
  44788. {
  44789. var data = graphics.graphicsData[i];
  44790. var shape = data.shape;
  44791. if (data.type === Phaser.POLYGON)
  44792. {
  44793. var points = shape.points;
  44794. context.moveTo(points[0], points[1]);
  44795. for (var j=1; j < points.length/2; j++)
  44796. {
  44797. context.lineTo(points[j * 2], points[j * 2 + 1]);
  44798. }
  44799. // if the first and last point are the same close the path - much neater :)
  44800. if (points[0] === points[points.length-2] && points[1] === points[points.length-1])
  44801. {
  44802. context.closePath();
  44803. }
  44804. }
  44805. else if (data.type === Phaser.RECTANGLE)
  44806. {
  44807. context.rect(shape.x, shape.y, shape.width, shape.height);
  44808. context.closePath();
  44809. }
  44810. else if (data.type === Phaser.CIRCLE)
  44811. {
  44812. // TODO - need to be Undefined!
  44813. context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI);
  44814. context.closePath();
  44815. }
  44816. else if (data.type === Phaser.ELLIPSE)
  44817. {
  44818. // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
  44819. var w = shape.width * 2;
  44820. var h = shape.height * 2;
  44821. var x = shape.x - w/2;
  44822. var y = shape.y - h/2;
  44823. var kappa = 0.5522848,
  44824. ox = (w / 2) * kappa, // control point offset horizontal
  44825. oy = (h / 2) * kappa, // control point offset vertical
  44826. xe = x + w, // x-end
  44827. ye = y + h, // y-end
  44828. xm = x + w / 2, // x-middle
  44829. ym = y + h / 2; // y-middle
  44830. context.moveTo(x, ym);
  44831. context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  44832. context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  44833. context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  44834. context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  44835. context.closePath();
  44836. }
  44837. else if (data.type === Phaser.ROUNDEDRECTANGLE)
  44838. {
  44839. var rx = shape.x;
  44840. var ry = shape.y;
  44841. var width = shape.width;
  44842. var height = shape.height;
  44843. var radius = shape.radius;
  44844. var maxRadius = Math.min(width, height) / 2 | 0;
  44845. radius = radius > maxRadius ? maxRadius : radius;
  44846. context.moveTo(rx, ry + radius);
  44847. context.lineTo(rx, ry + height - radius);
  44848. context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height);
  44849. context.lineTo(rx + width - radius, ry + height);
  44850. context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius);
  44851. context.lineTo(rx + width, ry + radius);
  44852. context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry);
  44853. context.lineTo(rx + radius, ry);
  44854. context.quadraticCurveTo(rx, ry, rx, ry + radius);
  44855. context.closePath();
  44856. }
  44857. }
  44858. };
  44859. PIXI.CanvasGraphics.updateGraphicsTint = function(graphics)
  44860. {
  44861. if (graphics.tint === 0xFFFFFF)
  44862. {
  44863. return;
  44864. }
  44865. var tintR = (graphics.tint >> 16 & 0xFF) / 255;
  44866. var tintG = (graphics.tint >> 8 & 0xFF) / 255;
  44867. var tintB = (graphics.tint & 0xFF)/ 255;
  44868. for (var i = 0; i < graphics.graphicsData.length; i++)
  44869. {
  44870. var data = graphics.graphicsData[i];
  44871. var fillColor = data.fillColor | 0;
  44872. var lineColor = data.lineColor | 0;
  44873. data._fillTint = (((fillColor >> 16 & 0xFF) / 255 * tintR*255 << 16) + ((fillColor >> 8 & 0xFF) / 255 * tintG*255 << 8) + (fillColor & 0xFF) / 255 * tintB*255);
  44874. data._lineTint = (((lineColor >> 16 & 0xFF) / 255 * tintR*255 << 16) + ((lineColor >> 8 & 0xFF) / 255 * tintG*255 << 8) + (lineColor & 0xFF) / 255 * tintB*255);
  44875. }
  44876. };
  44877. /**
  44878. * A GraphicsData object.
  44879. *
  44880. * @class
  44881. * @memberof PIXI
  44882. * @param lineWidth {number} the width of the line to draw
  44883. * @param lineColor {number} the color of the line to draw
  44884. * @param lineAlpha {number} the alpha of the line to draw
  44885. * @param fillColor {number} the color of the fill
  44886. * @param fillAlpha {number} the alpha of the fill
  44887. * @param fill {boolean} whether or not the shape is filled with a colour
  44888. * @param shape {Circle|Rectangle|Ellipse|Line|Polygon} The shape object to draw.
  44889. */
  44890. Phaser.GraphicsData = function (lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) {
  44891. /*
  44892. * @member {number} the width of the line to draw
  44893. */
  44894. this.lineWidth = lineWidth;
  44895. /*
  44896. * @member {number} the color of the line to draw
  44897. */
  44898. this.lineColor = lineColor;
  44899. /*
  44900. * @member {number} the alpha of the line to draw
  44901. */
  44902. this.lineAlpha = lineAlpha;
  44903. /*
  44904. * @member {number} cached tint of the line to draw
  44905. */
  44906. this._lineTint = lineColor;
  44907. /*
  44908. * @member {number} the color of the fill
  44909. */
  44910. this.fillColor = fillColor;
  44911. /*
  44912. * @member {number} the alpha of the fill
  44913. */
  44914. this.fillAlpha = fillAlpha;
  44915. /*
  44916. * @member {number} cached tint of the fill
  44917. */
  44918. this._fillTint = fillColor;
  44919. /*
  44920. * @member {boolean} whether or not the shape is filled with a color
  44921. */
  44922. this.fill = fill;
  44923. /*
  44924. * @member {Circle|Rectangle|Ellipse|Line|Polygon} The shape object to draw.
  44925. */
  44926. this.shape = shape;
  44927. /*
  44928. * @member {number} The type of the shape, see the Const.Shapes file for all the existing types,
  44929. */
  44930. this.type = shape.type;
  44931. };
  44932. Phaser.GraphicsData.prototype.constructor = Phaser.GraphicsData;
  44933. /**
  44934. * Creates a new GraphicsData object with the same values as this one.
  44935. *
  44936. * @return {GraphicsData}
  44937. */
  44938. Phaser.GraphicsData.prototype.clone = function () {
  44939. return new Phaser.GraphicsData(
  44940. this.lineWidth,
  44941. this.lineColor,
  44942. this.lineAlpha,
  44943. this.fillColor,
  44944. this.fillAlpha,
  44945. this.fill,
  44946. this.shape
  44947. );
  44948. };
  44949. /**
  44950. * @author Richard Davey <rich@photonstorm.com>
  44951. * @copyright 2016 Photon Storm Ltd.
  44952. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  44953. */
  44954. /**
  44955. * A Graphics object is a way to draw primitives to your game. Primitives include forms of geometry, such as Rectangles,
  44956. * Circles and Polygons. They also include lines, arcs and curves. When you initially create a Graphics object it will
  44957. * be empty. To 'draw' to it you first specify a lineStyle or fillStyle (or both), and then draw a shape. For example:
  44958. *
  44959. * ```javascript
  44960. * graphics.beginFill(0xff0000);
  44961. * graphics.drawCircle(50, 50, 100);
  44962. * graphics.endFill();
  44963. * ```
  44964. *
  44965. * This will draw a circle shape to the Graphics object, with a diameter of 100, located at x: 50, y: 50.
  44966. *
  44967. * When a Graphics object is rendered it will render differently based on if the game is running under Canvas or
  44968. * WebGL. Under Canvas it will use the HTML Canvas context drawing operations to draw the path. Under WebGL the
  44969. * graphics data is decomposed into polygons. Both of these are expensive processes, especially with complex shapes.
  44970. *
  44971. * If your Graphics object doesn't change much (or at all) once you've drawn your shape to it, then you will help
  44972. * performance by calling `Graphics.generateTexture`. This will 'bake' the Graphics object into a Texture, and return it.
  44973. * You can then use this Texture for Sprites or other display objects. If your Graphics object updates frequently then
  44974. * you should avoid doing this, as it will constantly generate new textures, which will consume memory.
  44975. *
  44976. * As you can tell, Graphics objects are a bit of a trade-off. While they are extremely useful, you need to be careful
  44977. * in their complexity and quantity of them in your game.
  44978. *
  44979. * @class Phaser.Graphics
  44980. * @constructor
  44981. * @extends PIXI.DisplayObjectContainer
  44982. * @extends Phaser.Component.Core
  44983. * @extends Phaser.Component.Angle
  44984. * @extends Phaser.Component.AutoCull
  44985. * @extends Phaser.Component.Bounds
  44986. * @extends Phaser.Component.Destroy
  44987. * @extends Phaser.Component.FixedToCamera
  44988. * @extends Phaser.Component.InputEnabled
  44989. * @extends Phaser.Component.InWorld
  44990. * @extends Phaser.Component.LifeSpan
  44991. * @extends Phaser.Component.PhysicsBody
  44992. * @extends Phaser.Component.Reset
  44993. * @param {Phaser.Game} game - Current game instance.
  44994. * @param {number} [x=0] - X position of the new graphics object.
  44995. * @param {number} [y=0] - Y position of the new graphics object.
  44996. */
  44997. Phaser.Graphics = function (game, x, y) {
  44998. if (x === undefined) { x = 0; }
  44999. if (y === undefined) { y = 0; }
  45000. /**
  45001. * @property {number} type - The const type of this object.
  45002. * @default
  45003. */
  45004. this.type = Phaser.GRAPHICS;
  45005. /**
  45006. * @property {number} physicsType - The const physics body type of this object.
  45007. * @readonly
  45008. */
  45009. this.physicsType = Phaser.SPRITE;
  45010. /**
  45011. * @property {Phaser.Point} anchor - Required for a Graphics shape to work as a Physics body, do not modify this value.
  45012. * @private
  45013. */
  45014. this.anchor = new Phaser.Point();
  45015. PIXI.DisplayObjectContainer.call(this);
  45016. this.renderable = true;
  45017. /**
  45018. * The alpha value used when filling the Graphics object.
  45019. *
  45020. * @property fillAlpha
  45021. * @type Number
  45022. */
  45023. this.fillAlpha = 1;
  45024. /**
  45025. * The width (thickness) of any lines drawn.
  45026. *
  45027. * @property lineWidth
  45028. * @type Number
  45029. */
  45030. this.lineWidth = 0;
  45031. /**
  45032. * The color of any lines drawn.
  45033. *
  45034. * @property lineColor
  45035. * @type String
  45036. * @default 0
  45037. */
  45038. this.lineColor = 0;
  45039. /**
  45040. * Graphics data
  45041. *
  45042. * @property graphicsData
  45043. * @type Array
  45044. * @private
  45045. */
  45046. this.graphicsData = [];
  45047. /**
  45048. * The tint applied to the graphic shape. This is a hex value. Apply a value of 0xFFFFFF to reset the tint.
  45049. *
  45050. * @property tint
  45051. * @type Number
  45052. * @default 0xFFFFFF
  45053. */
  45054. this.tint = 0xFFFFFF;
  45055. /**
  45056. * The blend mode to be applied to the graphic shape. Apply a value of PIXI.blendModes.NORMAL to reset the blend mode.
  45057. *
  45058. * @property blendMode
  45059. * @type Number
  45060. * @default PIXI.blendModes.NORMAL;
  45061. */
  45062. this.blendMode = PIXI.blendModes.NORMAL;
  45063. /**
  45064. * Current path
  45065. *
  45066. * @property currentPath
  45067. * @type Object
  45068. * @private
  45069. */
  45070. this.currentPath = null;
  45071. /**
  45072. * Array containing some WebGL-related properties used by the WebGL renderer.
  45073. *
  45074. * @property _webGL
  45075. * @type Array
  45076. * @private
  45077. */
  45078. this._webGL = [];
  45079. /**
  45080. * Whether this shape is being used as a mask.
  45081. *
  45082. * @property isMask
  45083. * @type Boolean
  45084. */
  45085. this.isMask = false;
  45086. /**
  45087. * The bounds' padding used for bounds calculation.
  45088. *
  45089. * @property boundsPadding
  45090. * @type Number
  45091. */
  45092. this.boundsPadding = 0;
  45093. this._localBounds = new Phaser.Rectangle(0, 0, 1, 1);
  45094. /**
  45095. * Used to detect if the graphics object has changed. If this is set to true then the graphics object will be recalculated.
  45096. *
  45097. * @property dirty
  45098. * @type Boolean
  45099. * @private
  45100. */
  45101. this.dirty = true;
  45102. /**
  45103. * Used to detect if the bounds have been invalidated, by this Graphics being cleared or drawn to.
  45104. * If this is set to true then the updateLocalBounds is called once in the postUpdate method.
  45105. *
  45106. * @property _boundsDirty
  45107. * @type Boolean
  45108. * @private
  45109. */
  45110. this._boundsDirty = false;
  45111. /**
  45112. * Used to detect if the webgl graphics object has changed. If this is set to true then the graphics object will be recalculated.
  45113. *
  45114. * @property webGLDirty
  45115. * @type Boolean
  45116. * @private
  45117. */
  45118. this.webGLDirty = false;
  45119. /**
  45120. * Used to detect if the cached sprite object needs to be updated.
  45121. *
  45122. * @property cachedSpriteDirty
  45123. * @type Boolean
  45124. * @private
  45125. */
  45126. this.cachedSpriteDirty = false;
  45127. Phaser.Component.Core.init.call(this, game, x, y, '', null);
  45128. };
  45129. Phaser.Graphics.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  45130. Phaser.Graphics.prototype.constructor = Phaser.Graphics;
  45131. Phaser.Component.Core.install.call(Phaser.Graphics.prototype, [
  45132. 'Angle',
  45133. 'AutoCull',
  45134. 'Bounds',
  45135. 'Destroy',
  45136. 'FixedToCamera',
  45137. 'InputEnabled',
  45138. 'InWorld',
  45139. 'LifeSpan',
  45140. 'PhysicsBody',
  45141. 'Reset'
  45142. ]);
  45143. Phaser.Graphics.prototype.preUpdatePhysics = Phaser.Component.PhysicsBody.preUpdate;
  45144. Phaser.Graphics.prototype.preUpdateLifeSpan = Phaser.Component.LifeSpan.preUpdate;
  45145. Phaser.Graphics.prototype.preUpdateInWorld = Phaser.Component.InWorld.preUpdate;
  45146. Phaser.Graphics.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
  45147. /**
  45148. * Automatically called by World.preUpdate.
  45149. *
  45150. * @method Phaser.Graphics#preUpdate
  45151. */
  45152. Phaser.Graphics.prototype.preUpdate = function () {
  45153. if (!this.preUpdatePhysics() || !this.preUpdateLifeSpan() || !this.preUpdateInWorld())
  45154. {
  45155. return false;
  45156. }
  45157. return this.preUpdateCore();
  45158. };
  45159. /**
  45160. * Automatically called by World
  45161. *
  45162. * @method Phaser.Graphics#postUpdate
  45163. */
  45164. Phaser.Graphics.prototype.postUpdate = function () {
  45165. Phaser.Component.PhysicsBody.postUpdate.call(this);
  45166. Phaser.Component.FixedToCamera.postUpdate.call(this);
  45167. if (this._boundsDirty)
  45168. {
  45169. this.updateLocalBounds();
  45170. this._boundsDirty = false;
  45171. }
  45172. for (var i = 0; i < this.children.length; i++)
  45173. {
  45174. this.children[i].postUpdate();
  45175. }
  45176. };
  45177. /**
  45178. * Destroy this Graphics instance.
  45179. *
  45180. * @method Phaser.Graphics#destroy
  45181. * @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
  45182. */
  45183. Phaser.Graphics.prototype.destroy = function (destroyChildren) {
  45184. this.clear();
  45185. Phaser.Component.Destroy.prototype.destroy.call(this, destroyChildren);
  45186. };
  45187. /**
  45188. * Draws a single {@link Phaser.Polygon} triangle from a {@link Phaser.Point} array
  45189. *
  45190. * @method Phaser.Graphics#drawTriangle
  45191. * @param {Array<Phaser.Point>} points - An array of Phaser.Points that make up the three vertices of this triangle
  45192. * @param {boolean} [cull=false] - Should we check if the triangle is back-facing
  45193. */
  45194. Phaser.Graphics.prototype.drawTriangle = function (points, cull) {
  45195. if (cull === undefined) { cull = false; }
  45196. var triangle = new Phaser.Polygon(points);
  45197. if (cull)
  45198. {
  45199. var cameraToFace = new Phaser.Point(this.game.camera.x - points[0].x, this.game.camera.y - points[0].y);
  45200. var ab = new Phaser.Point(points[1].x - points[0].x, points[1].y - points[0].y);
  45201. var cb = new Phaser.Point(points[1].x - points[2].x, points[1].y - points[2].y);
  45202. var faceNormal = cb.cross(ab);
  45203. if (cameraToFace.dot(faceNormal) > 0)
  45204. {
  45205. this.drawPolygon(triangle);
  45206. }
  45207. }
  45208. else
  45209. {
  45210. this.drawPolygon(triangle);
  45211. }
  45212. };
  45213. /**
  45214. * Draws {@link Phaser.Polygon} triangles
  45215. *
  45216. * @method Phaser.Graphics#drawTriangles
  45217. * @param {Array<Phaser.Point>|Array<number>} vertices - An array of Phaser.Points or numbers that make up the vertices of the triangles
  45218. * @param {Array<number>} [indices=null] - An array of numbers that describe what order to draw the vertices in
  45219. * @param {boolean} [cull=false] - Should we check if the triangle is back-facing
  45220. */
  45221. Phaser.Graphics.prototype.drawTriangles = function (vertices, indices, cull) {
  45222. if (cull === undefined) { cull = false; }
  45223. var point1 = new Phaser.Point();
  45224. var point2 = new Phaser.Point();
  45225. var point3 = new Phaser.Point();
  45226. var points = [];
  45227. var i;
  45228. if (!indices)
  45229. {
  45230. if (vertices[0] instanceof Phaser.Point)
  45231. {
  45232. for (i = 0; i < vertices.length / 3; i++)
  45233. {
  45234. this.drawTriangle([vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]], cull);
  45235. }
  45236. }
  45237. else
  45238. {
  45239. for (i = 0; i < vertices.length / 6; i++)
  45240. {
  45241. point1.x = vertices[i * 6 + 0];
  45242. point1.y = vertices[i * 6 + 1];
  45243. point2.x = vertices[i * 6 + 2];
  45244. point2.y = vertices[i * 6 + 3];
  45245. point3.x = vertices[i * 6 + 4];
  45246. point3.y = vertices[i * 6 + 5];
  45247. this.drawTriangle([point1, point2, point3], cull);
  45248. }
  45249. }
  45250. }
  45251. else
  45252. {
  45253. if (vertices[0] instanceof Phaser.Point)
  45254. {
  45255. for (i = 0; i < indices.length /3; i++)
  45256. {
  45257. points.push(vertices[indices[i * 3 ]]);
  45258. points.push(vertices[indices[i * 3 + 1]]);
  45259. points.push(vertices[indices[i * 3 + 2]]);
  45260. if (points.length === 3)
  45261. {
  45262. this.drawTriangle(points, cull);
  45263. points = [];
  45264. }
  45265. }
  45266. }
  45267. else
  45268. {
  45269. for (i = 0; i < indices.length; i++)
  45270. {
  45271. point1.x = vertices[indices[i] * 2];
  45272. point1.y = vertices[indices[i] * 2 + 1];
  45273. points.push(point1.copyTo({}));
  45274. if (points.length === 3)
  45275. {
  45276. this.drawTriangle(points, cull);
  45277. points = [];
  45278. }
  45279. }
  45280. }
  45281. }
  45282. };
  45283. /**
  45284. * Specifies the line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method.
  45285. *
  45286. * @method Phaser.Graphics#lineStyle
  45287. * @param lineWidth {Number} width of the line to draw, will update the objects stored style
  45288. * @param color {Number} color of the line to draw, will update the objects stored style
  45289. * @param alpha {Number} alpha of the line to draw, will update the objects stored style
  45290. * @return {Graphics}
  45291. */
  45292. Phaser.Graphics.prototype.lineStyle = function (lineWidth, color, alpha) {
  45293. this.lineWidth = lineWidth || 0;
  45294. this.lineColor = color || 0;
  45295. this.lineAlpha = (alpha === undefined) ? 1 : alpha;
  45296. if (this.currentPath)
  45297. {
  45298. if (this.currentPath.shape.points.length)
  45299. {
  45300. // halfway through a line? start a new one!
  45301. this.drawShape(new Phaser.Polygon(this.currentPath.shape.points.slice(-2)));
  45302. }
  45303. else
  45304. {
  45305. // otherwise its empty so lets just set the line properties
  45306. this.currentPath.lineWidth = this.lineWidth;
  45307. this.currentPath.lineColor = this.lineColor;
  45308. this.currentPath.lineAlpha = this.lineAlpha;
  45309. }
  45310. }
  45311. return this;
  45312. };
  45313. /**
  45314. * Moves the current drawing position to x, y.
  45315. *
  45316. * @method Phaser.Graphics#moveTo
  45317. * @param x {Number} the X coordinate to move to
  45318. * @param y {Number} the Y coordinate to move to
  45319. * @return {Graphics}
  45320. */
  45321. Phaser.Graphics.prototype.moveTo = function (x, y) {
  45322. this.drawShape(new Phaser.Polygon([ x, y ]));
  45323. return this;
  45324. };
  45325. /**
  45326. * Draws a line using the current line style from the current drawing position to (x, y);
  45327. * The current drawing position is then set to (x, y).
  45328. *
  45329. * @method Phaser.Graphics#lineTo
  45330. * @param x {Number} the X coordinate to draw to
  45331. * @param y {Number} the Y coordinate to draw to
  45332. * @return {Graphics}
  45333. */
  45334. Phaser.Graphics.prototype.lineTo = function (x, y) {
  45335. if (!this.currentPath)
  45336. {
  45337. this.moveTo(0, 0);
  45338. }
  45339. this.currentPath.shape.points.push(x, y);
  45340. this.dirty = true;
  45341. this._boundsDirty = true;
  45342. return this;
  45343. };
  45344. /**
  45345. * Calculate the points for a quadratic bezier curve and then draws it.
  45346. * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c
  45347. *
  45348. * @method Phaser.Graphics#quadraticCurveTo
  45349. * @param cpX {Number} Control point x
  45350. * @param cpY {Number} Control point y
  45351. * @param toX {Number} Destination point x
  45352. * @param toY {Number} Destination point y
  45353. * @return {Graphics}
  45354. */
  45355. Phaser.Graphics.prototype.quadraticCurveTo = function (cpX, cpY, toX, toY) {
  45356. if (this.currentPath)
  45357. {
  45358. if (this.currentPath.shape.points.length === 0)
  45359. {
  45360. this.currentPath.shape.points = [ 0, 0 ];
  45361. }
  45362. }
  45363. else
  45364. {
  45365. this.moveTo(0,0);
  45366. }
  45367. var xa,
  45368. ya,
  45369. n = 20,
  45370. points = this.currentPath.shape.points;
  45371. if (points.length === 0)
  45372. {
  45373. this.moveTo(0, 0);
  45374. }
  45375. var fromX = points[points.length - 2];
  45376. var fromY = points[points.length - 1];
  45377. var j = 0;
  45378. for (var i = 1; i <= n; ++i)
  45379. {
  45380. j = i / n;
  45381. xa = fromX + ((cpX - fromX) * j);
  45382. ya = fromY + ((cpY - fromY) * j);
  45383. points.push( xa + ( ((cpX + ( (toX - cpX) * j )) - xa) * j ),
  45384. ya + ( ((cpY + ( (toY - cpY) * j )) - ya) * j ) );
  45385. }
  45386. this.dirty = true;
  45387. this._boundsDirty = true;
  45388. return this;
  45389. };
  45390. /**
  45391. * Calculate the points for a bezier curve and then draws it.
  45392. *
  45393. * @method Phaser.Graphics#bezierCurveTo
  45394. * @param cpX {Number} Control point x
  45395. * @param cpY {Number} Control point y
  45396. * @param cpX2 {Number} Second Control point x
  45397. * @param cpY2 {Number} Second Control point y
  45398. * @param toX {Number} Destination point x
  45399. * @param toY {Number} Destination point y
  45400. * @return {Graphics}
  45401. */
  45402. Phaser.Graphics.prototype.bezierCurveTo = function (cpX, cpY, cpX2, cpY2, toX, toY) {
  45403. if (this.currentPath)
  45404. {
  45405. if (this.currentPath.shape.points.length === 0)
  45406. {
  45407. this.currentPath.shape.points = [0, 0];
  45408. }
  45409. }
  45410. else
  45411. {
  45412. this.moveTo(0,0);
  45413. }
  45414. var n = 20,
  45415. dt,
  45416. dt2,
  45417. dt3,
  45418. t2,
  45419. t3,
  45420. points = this.currentPath.shape.points;
  45421. var fromX = points[points.length-2];
  45422. var fromY = points[points.length-1];
  45423. var j = 0;
  45424. for (var i = 1; i <= n; ++i)
  45425. {
  45426. j = i / n;
  45427. dt = (1 - j);
  45428. dt2 = dt * dt;
  45429. dt3 = dt2 * dt;
  45430. t2 = j * j;
  45431. t3 = t2 * j;
  45432. points.push( dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX,
  45433. dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY);
  45434. }
  45435. this.dirty = true;
  45436. this._boundsDirty = true;
  45437. return this;
  45438. };
  45439. /**
  45440. * The arcTo() method creates an arc/curve between two tangents on the canvas.
  45441. *
  45442. * "borrowed" from https://code.google.com/p/fxcanvas/ - thanks google!
  45443. *
  45444. * @method Phaser.Graphics#arcTo
  45445. * @param x1 {Number} The x-coordinate of the beginning of the arc
  45446. * @param y1 {Number} The y-coordinate of the beginning of the arc
  45447. * @param x2 {Number} The x-coordinate of the end of the arc
  45448. * @param y2 {Number} The y-coordinate of the end of the arc
  45449. * @param radius {Number} The radius of the arc
  45450. * @return {Graphics}
  45451. */
  45452. Phaser.Graphics.prototype.arcTo = function (x1, y1, x2, y2, radius) {
  45453. if (this.currentPath)
  45454. {
  45455. if (this.currentPath.shape.points.length === 0)
  45456. {
  45457. this.currentPath.shape.points.push(x1, y1);
  45458. }
  45459. }
  45460. else
  45461. {
  45462. this.moveTo(x1, y1);
  45463. }
  45464. var points = this.currentPath.shape.points,
  45465. fromX = points[points.length-2],
  45466. fromY = points[points.length-1],
  45467. a1 = fromY - y1,
  45468. b1 = fromX - x1,
  45469. a2 = y2 - y1,
  45470. b2 = x2 - x1,
  45471. mm = Math.abs(a1 * b2 - b1 * a2);
  45472. if (mm < 1.0e-8 || radius === 0)
  45473. {
  45474. if (points[points.length-2] !== x1 || points[points.length-1] !== y1)
  45475. {
  45476. points.push(x1, y1);
  45477. }
  45478. }
  45479. else
  45480. {
  45481. var dd = a1 * a1 + b1 * b1,
  45482. cc = a2 * a2 + b2 * b2,
  45483. tt = a1 * a2 + b1 * b2,
  45484. k1 = radius * Math.sqrt(dd) / mm,
  45485. k2 = radius * Math.sqrt(cc) / mm,
  45486. j1 = k1 * tt / dd,
  45487. j2 = k2 * tt / cc,
  45488. cx = k1 * b2 + k2 * b1,
  45489. cy = k1 * a2 + k2 * a1,
  45490. px = b1 * (k2 + j1),
  45491. py = a1 * (k2 + j1),
  45492. qx = b2 * (k1 + j2),
  45493. qy = a2 * (k1 + j2),
  45494. startAngle = Math.atan2(py - cy, px - cx),
  45495. endAngle = Math.atan2(qy - cy, qx - cx);
  45496. this.arc(cx + x1, cy + y1, radius, startAngle, endAngle, b1 * a2 > b2 * a1);
  45497. }
  45498. this.dirty = true;
  45499. this._boundsDirty = true;
  45500. return this;
  45501. };
  45502. /**
  45503. * The arc method creates an arc/curve (used to create circles, or parts of circles).
  45504. *
  45505. * @method Phaser.Graphics#arc
  45506. * @param cx {Number} The x-coordinate of the center of the circle
  45507. * @param cy {Number} The y-coordinate of the center of the circle
  45508. * @param radius {Number} The radius of the circle
  45509. * @param startAngle {Number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle)
  45510. * @param endAngle {Number} The ending angle, in radians
  45511. * @param anticlockwise {Boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise.
  45512. * @param segments {Number} Optional. The number of segments to use when calculating the arc. The default is 40. If you need more fidelity use a higher number.
  45513. * @return {Graphics}
  45514. */
  45515. Phaser.Graphics.prototype.arc = function (cx, cy, radius, startAngle, endAngle, anticlockwise, segments) {
  45516. // If we do this we can never draw a full circle
  45517. if (startAngle === endAngle)
  45518. {
  45519. return this;
  45520. }
  45521. if (anticlockwise === undefined) { anticlockwise = false; }
  45522. if (segments === undefined) { segments = 40; }
  45523. if (!anticlockwise && endAngle <= startAngle)
  45524. {
  45525. endAngle += Math.PI * 2;
  45526. }
  45527. else if (anticlockwise && startAngle <= endAngle)
  45528. {
  45529. startAngle += Math.PI * 2;
  45530. }
  45531. var sweep = anticlockwise ? (startAngle - endAngle) * -1 : (endAngle - startAngle);
  45532. var segs = Math.ceil(Math.abs(sweep) / (Math.PI * 2)) * segments;
  45533. // Sweep check - moved here because we don't want to do the moveTo below if the arc fails
  45534. if (sweep === 0)
  45535. {
  45536. return this;
  45537. }
  45538. var startX = cx + Math.cos(startAngle) * radius;
  45539. var startY = cy + Math.sin(startAngle) * radius;
  45540. if (anticlockwise && this.filling)
  45541. {
  45542. this.moveTo(cx, cy);
  45543. }
  45544. else
  45545. {
  45546. this.moveTo(startX, startY);
  45547. }
  45548. // currentPath will always exist after calling a moveTo
  45549. var points = this.currentPath.shape.points;
  45550. var theta = sweep / (segs * 2);
  45551. var theta2 = theta * 2;
  45552. var cTheta = Math.cos(theta);
  45553. var sTheta = Math.sin(theta);
  45554. var segMinus = segs - 1;
  45555. var remainder = (segMinus % 1) / segMinus;
  45556. for (var i = 0; i <= segMinus; i++)
  45557. {
  45558. var real = i + remainder * i;
  45559. var angle = ((theta) + startAngle + (theta2 * real));
  45560. var c = Math.cos(angle);
  45561. var s = -Math.sin(angle);
  45562. points.push(( (cTheta * c) + (sTheta * s) ) * radius + cx,
  45563. ( (cTheta * -s) + (sTheta * c) ) * radius + cy);
  45564. }
  45565. this.dirty = true;
  45566. this._boundsDirty = true;
  45567. return this;
  45568. };
  45569. /**
  45570. * Specifies a simple one-color fill that subsequent calls to other Graphics methods
  45571. * (such as lineTo() or drawCircle()) use when drawing.
  45572. *
  45573. * @method Phaser.Graphics#beginFill
  45574. * @param color {Number} the color of the fill
  45575. * @param alpha {Number} the alpha of the fill
  45576. * @return {Graphics}
  45577. */
  45578. Phaser.Graphics.prototype.beginFill = function (color, alpha) {
  45579. this.filling = true;
  45580. this.fillColor = color || 0;
  45581. this.fillAlpha = (alpha === undefined) ? 1 : alpha;
  45582. if (this.currentPath)
  45583. {
  45584. if (this.currentPath.shape.points.length <= 2)
  45585. {
  45586. this.currentPath.fill = this.filling;
  45587. this.currentPath.fillColor = this.fillColor;
  45588. this.currentPath.fillAlpha = this.fillAlpha;
  45589. }
  45590. }
  45591. return this;
  45592. };
  45593. /**
  45594. * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method.
  45595. *
  45596. * @method Phaser.Graphics#endFill
  45597. * @return {Graphics}
  45598. */
  45599. Phaser.Graphics.prototype.endFill = function () {
  45600. this.filling = false;
  45601. this.fillColor = null;
  45602. this.fillAlpha = 1;
  45603. return this;
  45604. };
  45605. /**
  45606. * @method Phaser.Graphics#drawRect
  45607. *
  45608. * @param x {Number} The X coord of the top-left of the rectangle
  45609. * @param y {Number} The Y coord of the top-left of the rectangle
  45610. * @param width {Number} The width of the rectangle
  45611. * @param height {Number} The height of the rectangle
  45612. * @return {Graphics}
  45613. */
  45614. Phaser.Graphics.prototype.drawRect = function (x, y, width, height) {
  45615. this.drawShape(new Phaser.Rectangle(x, y, width, height));
  45616. return this;
  45617. };
  45618. /**
  45619. * @method Phaser.Graphics#drawRoundedRect
  45620. * @param x {Number} The X coord of the top-left of the rectangle
  45621. * @param y {Number} The Y coord of the top-left of the rectangle
  45622. * @param width {Number} The width of the rectangle
  45623. * @param height {Number} The height of the rectangle
  45624. * @param radius {Number} Radius of the rectangle corners. In WebGL this must be a value between 0 and 9.
  45625. */
  45626. Phaser.Graphics.prototype.drawRoundedRect = function (x, y, width, height, radius) {
  45627. this.drawShape(new Phaser.RoundedRectangle(x, y, width, height, radius));
  45628. return this;
  45629. };
  45630. /**
  45631. * Draws a circle.
  45632. *
  45633. * @method Phaser.Graphics#drawCircle
  45634. * @param x {Number} The X coordinate of the center of the circle
  45635. * @param y {Number} The Y coordinate of the center of the circle
  45636. * @param diameter {Number} The diameter of the circle
  45637. * @return {Graphics}
  45638. */
  45639. Phaser.Graphics.prototype.drawCircle = function (x, y, diameter) {
  45640. this.drawShape(new Phaser.Circle(x, y, diameter));
  45641. return this;
  45642. };
  45643. /**
  45644. * Draws an ellipse.
  45645. *
  45646. * @method Phaser.Graphics#drawEllipse
  45647. * @param x {Number} The X coordinate of the center of the ellipse
  45648. * @param y {Number} The Y coordinate of the center of the ellipse
  45649. * @param width {Number} The half width of the ellipse
  45650. * @param height {Number} The half height of the ellipse
  45651. * @return {Graphics}
  45652. */
  45653. Phaser.Graphics.prototype.drawEllipse = function (x, y, width, height) {
  45654. this.drawShape(new Phaser.Ellipse(x, y, width, height));
  45655. return this;
  45656. };
  45657. /**
  45658. * Draws a polygon using the given path.
  45659. *
  45660. * @method Phaser.Graphics#drawPolygon
  45661. * @param path {Array|Phaser.Polygon} The path data used to construct the polygon. Can either be an array of points or a Phaser.Polygon object.
  45662. * @return {Graphics}
  45663. */
  45664. Phaser.Graphics.prototype.drawPolygon = function (path) {
  45665. if (path instanceof Phaser.Polygon)
  45666. {
  45667. path = path.points;
  45668. }
  45669. // prevents an argument assignment deopt
  45670. // see section 3.1: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments
  45671. var points = path;
  45672. if (!Array.isArray(points))
  45673. {
  45674. // prevents an argument leak deopt
  45675. // see section 3.2: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments
  45676. points = new Array(arguments.length);
  45677. for (var i = 0; i < points.length; ++i)
  45678. {
  45679. points[i] = arguments[i];
  45680. }
  45681. }
  45682. this.drawShape(new Phaser.Polygon(points));
  45683. return this;
  45684. };
  45685. /**
  45686. * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings.
  45687. *
  45688. * @method Phaser.Graphics#clear
  45689. * @return {Graphics}
  45690. */
  45691. Phaser.Graphics.prototype.clear = function () {
  45692. this.lineWidth = 0;
  45693. this.filling = false;
  45694. this.dirty = true;
  45695. this._boundsDirty = true;
  45696. this.clearDirty = true;
  45697. this.graphicsData = [];
  45698. this.updateLocalBounds();
  45699. return this;
  45700. };
  45701. /**
  45702. * Useful function that returns a texture of the graphics object that can then be used to create sprites
  45703. * This can be quite useful if your geometry is complicated and needs to be reused multiple times.
  45704. *
  45705. * Transparent areas adjoining the edges may be removed ({@link https://github.com/photonstorm/phaser-ce/issues/283 #283}).
  45706. *
  45707. * @method Phaser.Graphics#generateTexture
  45708. * @param [resolution=1] {Number} The resolution of the texture being generated
  45709. * @param [scaleMode=0] {Number} Should be one of the PIXI.scaleMode consts
  45710. * @param [padding=0] {Number} Add optional extra padding to the generated texture (default 0)
  45711. * @return {Texture} a texture of the graphics object
  45712. */
  45713. Phaser.Graphics.prototype.generateTexture = function (resolution, scaleMode, padding) {
  45714. if (resolution === undefined) { resolution = 1; }
  45715. if (scaleMode === undefined) { scaleMode = PIXI.scaleModes.DEFAULT; }
  45716. if (padding === undefined) { padding = 0; }
  45717. var bounds = this.getBounds();
  45718. bounds.width += padding;
  45719. bounds.height += padding;
  45720. var canvasBuffer = new PIXI.CanvasBuffer(bounds.width * resolution, bounds.height * resolution);
  45721. var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas, scaleMode);
  45722. texture.baseTexture.resolution = resolution;
  45723. canvasBuffer.context.scale(resolution, resolution);
  45724. canvasBuffer.context.translate(-bounds.x, -bounds.y);
  45725. PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context);
  45726. return texture;
  45727. };
  45728. /**
  45729. * Renders the object using the WebGL renderer
  45730. *
  45731. * @method Phaser.Graphics#_renderWebGL
  45732. * @param renderSession {RenderSession}
  45733. * @private
  45734. */
  45735. Phaser.Graphics.prototype._renderWebGL = function (renderSession) {
  45736. // if the sprite is not visible or the alpha is 0 then no need to render this element
  45737. if (this.visible === false || this.alpha === 0 || this.isMask === true)
  45738. {
  45739. return;
  45740. }
  45741. if (this._cacheAsBitmap)
  45742. {
  45743. if (this.dirty || this.cachedSpriteDirty)
  45744. {
  45745. this._generateCachedSprite();
  45746. // we will also need to update the texture on the gpu too!
  45747. this.updateCachedSpriteTexture();
  45748. this.cachedSpriteDirty = false;
  45749. this.dirty = false;
  45750. }
  45751. this._cachedSprite.worldAlpha = this.worldAlpha;
  45752. PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession);
  45753. return;
  45754. }
  45755. else
  45756. {
  45757. renderSession.spriteBatch.stop();
  45758. renderSession.blendModeManager.setBlendMode(this.blendMode);
  45759. if (this._mask)
  45760. {
  45761. renderSession.maskManager.pushMask(this._mask, renderSession);
  45762. }
  45763. if (this._filters)
  45764. {
  45765. renderSession.filterManager.pushFilter(this._filterBlock);
  45766. }
  45767. // check blend mode
  45768. if (this.blendMode !== renderSession.spriteBatch.currentBlendMode)
  45769. {
  45770. renderSession.spriteBatch.currentBlendMode = this.blendMode;
  45771. var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode];
  45772. renderSession.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
  45773. }
  45774. // check if the webgl graphic needs to be updated
  45775. if (this.webGLDirty)
  45776. {
  45777. this.dirty = true;
  45778. this.webGLDirty = false;
  45779. }
  45780. PIXI.WebGLGraphics.renderGraphics(this, renderSession);
  45781. // only render if it has children!
  45782. if (this.children.length)
  45783. {
  45784. renderSession.spriteBatch.start();
  45785. // simple render children!
  45786. for (var i = 0; i < this.children.length; i++)
  45787. {
  45788. this.children[i]._renderWebGL(renderSession);
  45789. }
  45790. renderSession.spriteBatch.stop();
  45791. }
  45792. if (this._filters)
  45793. {
  45794. renderSession.filterManager.popFilter();
  45795. }
  45796. if (this._mask)
  45797. {
  45798. renderSession.maskManager.popMask(this.mask, renderSession);
  45799. }
  45800. renderSession.drawCount++;
  45801. renderSession.spriteBatch.start();
  45802. }
  45803. };
  45804. /**
  45805. * Renders the object using the Canvas renderer
  45806. *
  45807. * @method Phaser.Graphics#_renderCanvas
  45808. * @param renderSession {RenderSession}
  45809. * @private
  45810. */
  45811. Phaser.Graphics.prototype._renderCanvas = function (renderSession) {
  45812. // if the sprite is not visible or the alpha is 0 then no need to render this element
  45813. if (this.visible === false || this.alpha === 0 || this.isMask === true)
  45814. {
  45815. return;
  45816. }
  45817. // if the tint has changed, set the graphics object to dirty.
  45818. if (this._prevTint !== this.tint)
  45819. {
  45820. this.dirty = true;
  45821. this._prevTint = this.tint;
  45822. }
  45823. if (this._cacheAsBitmap)
  45824. {
  45825. if (this.dirty || this.cachedSpriteDirty)
  45826. {
  45827. this._generateCachedSprite();
  45828. // we will also need to update the texture
  45829. this.updateCachedSpriteTexture();
  45830. this.cachedSpriteDirty = false;
  45831. this.dirty = false;
  45832. }
  45833. this._cachedSprite.alpha = this.alpha;
  45834. PIXI.Sprite.prototype._renderCanvas.call(this._cachedSprite, renderSession);
  45835. return;
  45836. }
  45837. else
  45838. {
  45839. var context = renderSession.context;
  45840. var transform = this.worldTransform;
  45841. if (this.blendMode !== renderSession.currentBlendMode)
  45842. {
  45843. renderSession.currentBlendMode = this.blendMode;
  45844. context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
  45845. }
  45846. if (this._mask)
  45847. {
  45848. renderSession.maskManager.pushMask(this._mask, renderSession);
  45849. }
  45850. var resolution = renderSession.resolution;
  45851. var tx = (transform.tx * renderSession.resolution) + renderSession.shakeX;
  45852. var ty = (transform.ty * renderSession.resolution) + renderSession.shakeY;
  45853. context.setTransform(transform.a * resolution,
  45854. transform.b * resolution,
  45855. transform.c * resolution,
  45856. transform.d * resolution,
  45857. tx,
  45858. ty);
  45859. PIXI.CanvasGraphics.renderGraphics(this, context);
  45860. // simple render children!
  45861. for (var i = 0; i < this.children.length; i++)
  45862. {
  45863. this.children[i]._renderCanvas(renderSession);
  45864. }
  45865. if (this._mask)
  45866. {
  45867. renderSession.maskManager.popMask(renderSession);
  45868. }
  45869. }
  45870. };
  45871. /**
  45872. * Retrieves the bounds of the graphic shape as a rectangle object
  45873. *
  45874. * @method Phaser.Graphics#getBounds
  45875. * @return {Rectangle} the rectangular bounding area
  45876. */
  45877. Phaser.Graphics.prototype.getBounds = function (matrix) {
  45878. if (this._currentBounds)
  45879. {
  45880. return this._currentBounds;
  45881. }
  45882. // Return an empty object if the item is a mask!
  45883. if (!this.renderable)
  45884. {
  45885. return Phaser.EmptyRectangle;
  45886. }
  45887. if (this.dirty)
  45888. {
  45889. this.updateLocalBounds();
  45890. this.webGLDirty = true;
  45891. this.cachedSpriteDirty = true;
  45892. this.dirty = false;
  45893. }
  45894. var bounds = this._localBounds;
  45895. var w0 = bounds.x;
  45896. var w1 = bounds.width + bounds.x;
  45897. var h0 = bounds.y;
  45898. var h1 = bounds.height + bounds.y;
  45899. var worldTransform = matrix || this.worldTransform;
  45900. var a = worldTransform.a;
  45901. var b = worldTransform.b;
  45902. var c = worldTransform.c;
  45903. var d = worldTransform.d;
  45904. var tx = worldTransform.tx;
  45905. var ty = worldTransform.ty;
  45906. var x1 = a * w1 + c * h1 + tx;
  45907. var y1 = d * h1 + b * w1 + ty;
  45908. var x2 = a * w0 + c * h1 + tx;
  45909. var y2 = d * h1 + b * w0 + ty;
  45910. var x3 = a * w0 + c * h0 + tx;
  45911. var y3 = d * h0 + b * w0 + ty;
  45912. var x4 = a * w1 + c * h0 + tx;
  45913. var y4 = d * h0 + b * w1 + ty;
  45914. var maxX = x1;
  45915. var maxY = y1;
  45916. var minX = x1;
  45917. var minY = y1;
  45918. minX = x2 < minX ? x2 : minX;
  45919. minX = x3 < minX ? x3 : minX;
  45920. minX = x4 < minX ? x4 : minX;
  45921. minY = y2 < minY ? y2 : minY;
  45922. minY = y3 < minY ? y3 : minY;
  45923. minY = y4 < minY ? y4 : minY;
  45924. maxX = x2 > maxX ? x2 : maxX;
  45925. maxX = x3 > maxX ? x3 : maxX;
  45926. maxX = x4 > maxX ? x4 : maxX;
  45927. maxY = y2 > maxY ? y2 : maxY;
  45928. maxY = y3 > maxY ? y3 : maxY;
  45929. maxY = y4 > maxY ? y4 : maxY;
  45930. this._bounds.x = minX;
  45931. this._bounds.width = maxX - minX;
  45932. this._bounds.y = minY;
  45933. this._bounds.height = maxY - minY;
  45934. this._currentBounds = this._bounds;
  45935. return this._currentBounds;
  45936. };
  45937. /**
  45938. * Retrieves the non-global local bounds of the graphic shape as a rectangle. The calculation takes all visible children into consideration.
  45939. *
  45940. * @method Phaser.Graphics#getLocalBounds
  45941. * @return {Rectangle} The rectangular bounding area
  45942. */
  45943. Phaser.Graphics.prototype.getLocalBounds = function () {
  45944. var matrixCache = this.worldTransform;
  45945. this.worldTransform = Phaser.identityMatrix;
  45946. for (var i = 0; i < this.children.length; i++)
  45947. {
  45948. this.children[i].updateTransform();
  45949. }
  45950. var bounds = this.getBounds();
  45951. this.worldTransform = matrixCache;
  45952. for (i = 0; i < this.children.length; i++)
  45953. {
  45954. this.children[i].updateTransform();
  45955. }
  45956. return bounds;
  45957. };
  45958. /**
  45959. * Tests if a point is inside this graphics object
  45960. *
  45961. * @param point {Point} the point to test
  45962. * @return {boolean} the result of the test
  45963. */
  45964. Phaser.Graphics.prototype.containsPoint = function (point, tempPoint) {
  45965. if (tempPoint === undefined) { tempPoint = new Phaser.Point(); }
  45966. this.worldTransform.applyInverse(point, tempPoint);
  45967. var graphicsData = this.graphicsData;
  45968. for (var i = 0; i < graphicsData.length; i++)
  45969. {
  45970. var data = graphicsData[i];
  45971. if (!data.fill)
  45972. {
  45973. continue;
  45974. }
  45975. // only deal with fills..
  45976. if (data.shape)
  45977. {
  45978. if (data.shape.contains(tempPoint.x, tempPoint.y))
  45979. {
  45980. return true;
  45981. }
  45982. }
  45983. }
  45984. return false;
  45985. };
  45986. /**
  45987. * Update the bounds of the object
  45988. *
  45989. * @method Phaser.Graphics#updateLocalBounds
  45990. */
  45991. Phaser.Graphics.prototype.updateLocalBounds = function () {
  45992. var minX = Infinity;
  45993. var maxX = -Infinity;
  45994. var minY = Infinity;
  45995. var maxY = -Infinity;
  45996. if (this.graphicsData.length)
  45997. {
  45998. var shape, points, x, y, w, h;
  45999. for (var i = 0; i < this.graphicsData.length; i++)
  46000. {
  46001. var data = this.graphicsData[i];
  46002. var type = data.type;
  46003. var lineWidth = data.lineWidth;
  46004. shape = data.shape;
  46005. if (type === Phaser.RECTANGLE || type === Phaser.ROUNDEDRECTANGLE)
  46006. {
  46007. x = shape.x - lineWidth / 2;
  46008. y = shape.y - lineWidth / 2;
  46009. w = shape.width + lineWidth;
  46010. h = shape.height + lineWidth;
  46011. minX = x < minX ? x : minX;
  46012. maxX = x + w > maxX ? x + w : maxX;
  46013. minY = y < minY ? y : minY;
  46014. maxY = y + h > maxY ? y + h : maxY;
  46015. }
  46016. else if (type === Phaser.CIRCLE)
  46017. {
  46018. x = shape.x;
  46019. y = shape.y;
  46020. w = shape.radius + lineWidth / 2;
  46021. h = shape.radius + lineWidth / 2;
  46022. minX = x - w < minX ? x - w : minX;
  46023. maxX = x + w > maxX ? x + w : maxX;
  46024. minY = y - h < minY ? y - h : minY;
  46025. maxY = y + h > maxY ? y + h : maxY;
  46026. }
  46027. else if (type === Phaser.ELLIPSE)
  46028. {
  46029. x = shape.x;
  46030. y = shape.y;
  46031. w = shape.width + lineWidth / 2;
  46032. h = shape.height + lineWidth / 2;
  46033. minX = x - w < minX ? x - w : minX;
  46034. maxX = x + w > maxX ? x + w : maxX;
  46035. minY = y - h < minY ? y - h : minY;
  46036. maxY = y + h > maxY ? y + h : maxY;
  46037. }
  46038. else
  46039. {
  46040. // POLY - assumes points are sequential, not Point objects
  46041. points = shape.points;
  46042. for (var j = 0; j < points.length; j++)
  46043. {
  46044. if (points[j] instanceof Phaser.Point)
  46045. {
  46046. x = points[j].x;
  46047. y = points[j].y;
  46048. }
  46049. else
  46050. {
  46051. x = points[j];
  46052. y = points[j + 1];
  46053. if (j < points.length - 1)
  46054. {
  46055. j++;
  46056. }
  46057. }
  46058. minX = x - lineWidth < minX ? x - lineWidth : minX;
  46059. maxX = x + lineWidth > maxX ? x + lineWidth : maxX;
  46060. minY = y - lineWidth < minY ? y - lineWidth : minY;
  46061. maxY = y + lineWidth > maxY ? y + lineWidth : maxY;
  46062. }
  46063. }
  46064. }
  46065. }
  46066. else
  46067. {
  46068. minX = 0;
  46069. maxX = 0;
  46070. minY = 0;
  46071. maxY = 0;
  46072. }
  46073. var padding = this.boundsPadding;
  46074. this._localBounds.x = minX - padding;
  46075. this._localBounds.width = (maxX - minX) + padding * 2;
  46076. this._localBounds.y = minY - padding;
  46077. this._localBounds.height = (maxY - minY) + padding * 2;
  46078. };
  46079. /**
  46080. * Generates the cached sprite when the sprite has cacheAsBitmap = true
  46081. *
  46082. * @method Phaser.Graphics#_generateCachedSprite
  46083. * @private
  46084. */
  46085. Phaser.Graphics.prototype._generateCachedSprite = function () {
  46086. var bounds = this.getLocalBounds();
  46087. if (!this._cachedSprite)
  46088. {
  46089. var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height);
  46090. var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas);
  46091. this._cachedSprite = new PIXI.Sprite(texture);
  46092. this._cachedSprite.buffer = canvasBuffer;
  46093. this._cachedSprite.worldTransform = this.worldTransform;
  46094. }
  46095. else
  46096. {
  46097. this._cachedSprite.buffer.resize(bounds.width, bounds.height);
  46098. }
  46099. // leverage the anchor to account for the offset of the element
  46100. this._cachedSprite.anchor.x = -(bounds.x / bounds.width);
  46101. this._cachedSprite.anchor.y = -(bounds.y / bounds.height);
  46102. // this._cachedSprite.buffer.context.save();
  46103. this._cachedSprite.buffer.context.translate(-bounds.x, -bounds.y);
  46104. // make sure we set the alpha of the graphics to 1 for the render..
  46105. this.worldAlpha = 1;
  46106. // now render the graphic..
  46107. PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context);
  46108. this._cachedSprite.alpha = this.alpha;
  46109. };
  46110. /**
  46111. * Updates texture size based on canvas size
  46112. *
  46113. * @method Phaser.Graphics#updateCachedSpriteTexture
  46114. * @private
  46115. */
  46116. Phaser.Graphics.prototype.updateCachedSpriteTexture = function () {
  46117. var cachedSprite = this._cachedSprite;
  46118. var texture = cachedSprite.texture;
  46119. var canvas = cachedSprite.buffer.canvas;
  46120. texture.baseTexture.width = canvas.width;
  46121. texture.baseTexture.height = canvas.height;
  46122. texture.crop.width = texture.frame.width = canvas.width;
  46123. texture.crop.height = texture.frame.height = canvas.height;
  46124. cachedSprite._width = canvas.width;
  46125. cachedSprite._height = canvas.height;
  46126. // update the dirty base textures
  46127. texture.baseTexture.dirty();
  46128. };
  46129. /**
  46130. * Destroys a previous cached sprite.
  46131. *
  46132. * @method Phaser.Graphics#destroyCachedSprite
  46133. */
  46134. Phaser.Graphics.prototype.destroyCachedSprite = function () {
  46135. this._cachedSprite.texture.destroy(true);
  46136. this._cachedSprite = null;
  46137. };
  46138. /**
  46139. * Draws the given shape to this Graphics object. Can be any of Circle, Rectangle, Ellipse, Line or Polygon.
  46140. *
  46141. * @method Phaser.Graphics#drawShape
  46142. * @param {Circle|Rectangle|Ellipse|Line|Polygon} shape The Shape object to draw.
  46143. * @return {GraphicsData} The generated GraphicsData object.
  46144. */
  46145. Phaser.Graphics.prototype.drawShape = function (shape) {
  46146. if (this.currentPath)
  46147. {
  46148. // check current path!
  46149. if (this.currentPath.shape.points.length <= 2)
  46150. {
  46151. this.graphicsData.pop();
  46152. }
  46153. }
  46154. this.currentPath = null;
  46155. // Handle mixed-type polygons
  46156. if (shape instanceof Phaser.Polygon)
  46157. {
  46158. shape = shape.clone();
  46159. shape.flatten();
  46160. }
  46161. var data = new Phaser.GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape);
  46162. this.graphicsData.push(data);
  46163. if (data.type === Phaser.POLYGON)
  46164. {
  46165. data.shape.closed = this.filling;
  46166. this.currentPath = data;
  46167. }
  46168. this.dirty = true;
  46169. this._boundsDirty = true;
  46170. return data;
  46171. };
  46172. /**
  46173. * When cacheAsBitmap is set to true the graphics object will be rendered as if it was a sprite. Transparent areas adjoining the edges may be removed ({@link https://github.com/photonstorm/phaser-ce/issues/283 #283}).
  46174. * This is useful if your graphics element does not change often, as it will speed up the rendering of the object in exchange for taking up texture memory.
  46175. * It is also useful if you need the graphics object to be anti-aliased, because it will be rendered using canvas.
  46176. * This is not recommended if you are constantly redrawing the graphics element.
  46177. *
  46178. * @property cacheAsBitmap
  46179. * @type Boolean
  46180. * @default false
  46181. * @private
  46182. */
  46183. Object.defineProperty(Phaser.Graphics.prototype, 'cacheAsBitmap', {
  46184. get: function () {
  46185. return this._cacheAsBitmap;
  46186. },
  46187. set: function (value) {
  46188. this._cacheAsBitmap = value;
  46189. if (this._cacheAsBitmap)
  46190. {
  46191. this._generateCachedSprite();
  46192. }
  46193. else
  46194. {
  46195. this.destroyCachedSprite();
  46196. }
  46197. this.dirty = true;
  46198. this.webGLDirty = true;
  46199. }
  46200. });
  46201. /**
  46202. * @author Richard Davey <rich@photonstorm.com>
  46203. * @copyright 2016 Photon Storm Ltd.
  46204. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  46205. */
  46206. /**
  46207. * A RenderTexture is a special texture that allows any displayObject to be rendered to it. It allows you to take many complex objects and
  46208. * render them down into a single quad (on WebGL) which can then be used to texture other display objects with. A way of generating textures at run-time.
  46209. *
  46210. * @class Phaser.RenderTexture
  46211. * @constructor
  46212. * @extends PIXI.Texture
  46213. * @param {Phaser.Game} game - Current game instance.
  46214. * @param {number} [width=100] - The width of the render texture.
  46215. * @param {number} [height=100] - The height of the render texture.
  46216. * @param {string} [key=''] - The key of the RenderTexture in the Cache, if stored there.
  46217. * @param {number} [scaleMode=Phaser.scaleModes.DEFAULT] - One of the Phaser.scaleModes consts.
  46218. * @param {number} [resolution=1] - The resolution of the texture being generated.
  46219. */
  46220. Phaser.RenderTexture = function (game, width, height, key, scaleMode, resolution, renderer, textureUnit) {
  46221. if (width === undefined) { width = 100; }
  46222. if (height === undefined) { height = 100; }
  46223. if (key === undefined) { key = ''; }
  46224. if (scaleMode === undefined) { scaleMode = Phaser.scaleModes.DEFAULT; }
  46225. if (resolution === undefined) { resolution = 1; }
  46226. if (renderer === undefined) { renderer = PIXI.defaultRenderer; }
  46227. if (textureUnit === undefined) { textureUnit = 0; }
  46228. /**
  46229. * @property {Phaser.Game} game - A reference to the currently running game.
  46230. */
  46231. this.game = game;
  46232. /**
  46233. * @property {string} key - The key of the RenderTexture in the Cache, if stored there.
  46234. */
  46235. this.key = key;
  46236. /**
  46237. * @property {number} type - Base Phaser object type.
  46238. */
  46239. this.type = Phaser.RENDERTEXTURE;
  46240. /**
  46241. * @property {Phaser.Matrix} _tempMatrix - The matrix that is applied when display objects are rendered to this RenderTexture.
  46242. * @private
  46243. */
  46244. this._tempMatrix = new Phaser.Matrix();
  46245. this.width = width;
  46246. this.height = height;
  46247. this.resolution = resolution;
  46248. this.frame = new Phaser.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution);
  46249. this.crop = this.frame.clone();
  46250. /**
  46251. * The base texture object that this texture uses
  46252. *
  46253. * @property baseTexture
  46254. * @type BaseTexture
  46255. */
  46256. this.baseTexture = new PIXI.BaseTexture();
  46257. this.baseTexture.width = this.width * this.resolution;
  46258. this.baseTexture.height = this.height * this.resolution;
  46259. this.baseTexture._glTextures = [];
  46260. this.baseTexture.resolution = this.resolution;
  46261. this.baseTexture.scaleMode = scaleMode;
  46262. this.baseTexture.hasLoaded = true;
  46263. PIXI.Texture.call(this, this.baseTexture, this.frame.clone());
  46264. /**
  46265. * The renderer this RenderTexture uses. A RenderTexture can only belong to one renderer at the moment if its webGL.
  46266. *
  46267. * @property renderer
  46268. * @type CanvasRenderer|WebGLRenderer
  46269. */
  46270. this.renderer = renderer;
  46271. if (this.renderer.type === Phaser.WEBGL)
  46272. {
  46273. var gl = this.renderer.gl;
  46274. this.baseTexture.textureIndex = textureUnit;
  46275. this.baseTexture._dirty[gl.id] = false;
  46276. this.textureBuffer = new PIXI.FilterTexture(gl, this.width, this.height, this.baseTexture.scaleMode, textureUnit);
  46277. this.baseTexture._glTextures[gl.id] = this.textureBuffer.texture;
  46278. this.projection = new Phaser.Point(this.width * 0.5, -this.height * 0.5);
  46279. }
  46280. else
  46281. {
  46282. this.textureBuffer = new PIXI.CanvasBuffer(this.width * this.resolution, this.height * this.resolution);
  46283. this.baseTexture.source = this.textureBuffer.canvas;
  46284. }
  46285. /**
  46286. * @property valid
  46287. * @type Boolean
  46288. */
  46289. this.valid = true;
  46290. this.tempMatrix = new Phaser.Matrix();
  46291. this._updateUvs();
  46292. };
  46293. Phaser.RenderTexture.prototype = Object.create(PIXI.Texture.prototype);
  46294. Phaser.RenderTexture.prototype.constructor = Phaser.RenderTexture;
  46295. /**
  46296. * This function will draw the display object to the RenderTexture at the given coordinates.
  46297. *
  46298. * When the display object is drawn it takes into account scale and rotation.
  46299. *
  46300. * If you don't want those then use RenderTexture.renderRawXY instead.
  46301. *
  46302. * @method Phaser.RenderTexture.prototype.renderXY
  46303. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Group} displayObject - The display object to render to this texture.
  46304. * @param {number} x - The x position to render the object at.
  46305. * @param {number} y - The y position to render the object at.
  46306. * @param {boolean} [clear=false] - If true the texture will be cleared before the display object is drawn.
  46307. */
  46308. Phaser.RenderTexture.prototype.renderXY = function (displayObject, x, y, clear) {
  46309. displayObject.updateTransform();
  46310. this._tempMatrix.copyFrom(displayObject.worldTransform);
  46311. this._tempMatrix.tx = x;
  46312. this._tempMatrix.ty = y;
  46313. if (this.renderer.type === Phaser.WEBGL)
  46314. {
  46315. this._renderWebGL(displayObject, this._tempMatrix, clear);
  46316. }
  46317. else
  46318. {
  46319. this._renderCanvas(displayObject, this._tempMatrix, clear);
  46320. }
  46321. };
  46322. /**
  46323. * This function will draw the display object to the RenderTexture at the given coordinates.
  46324. *
  46325. * When the display object is drawn it doesn't take into account scale, rotation or translation.
  46326. *
  46327. * If you need those then use RenderTexture.renderXY instead.
  46328. *
  46329. * @method Phaser.RenderTexture.prototype.renderRawXY
  46330. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Group} displayObject - The display object to render to this texture.
  46331. * @param {number} x - The x position to render the object at.
  46332. * @param {number} y - The y position to render the object at.
  46333. * @param {boolean} [clear=false] - If true the texture will be cleared before the display object is drawn.
  46334. */
  46335. Phaser.RenderTexture.prototype.renderRawXY = function (displayObject, x, y, clear) {
  46336. this._tempMatrix.identity().translate(x, y);
  46337. if (this.renderer.type === Phaser.WEBGL)
  46338. {
  46339. this._renderWebGL(displayObject, this._tempMatrix, clear);
  46340. }
  46341. else
  46342. {
  46343. this._renderCanvas(displayObject, this._tempMatrix, clear);
  46344. }
  46345. };
  46346. /**
  46347. * This function will draw the display object to the RenderTexture.
  46348. *
  46349. * In versions of Phaser prior to 2.4.0 the second parameter was a Phaser.Point object.
  46350. * This is now a Matrix allowing you much more control over how the Display Object is rendered.
  46351. * If you need to replicate the earlier behavior please use Phaser.RenderTexture.renderXY instead.
  46352. *
  46353. * If you wish for the displayObject to be rendered taking its current scale, rotation and translation into account then either
  46354. * pass `null`, leave it undefined or pass `displayObject.worldTransform` as the matrix value.
  46355. *
  46356. * @method Phaser.RenderTexture.prototype.render
  46357. * @param {Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Group} displayObject - The display object to render to this texture.
  46358. * @param {Phaser.Matrix} [matrix] - Optional matrix to apply to the display object before rendering. If null or undefined it will use the worldTransform matrix of the given display object.
  46359. * @param {boolean} [clear=false] - If true the texture will be cleared before the display object is drawn.
  46360. */
  46361. Phaser.RenderTexture.prototype.render = function (displayObject, matrix, clear) {
  46362. if (matrix === undefined || matrix === null)
  46363. {
  46364. this._tempMatrix.copyFrom(displayObject.worldTransform);
  46365. }
  46366. else
  46367. {
  46368. this._tempMatrix.copyFrom(matrix);
  46369. }
  46370. if (this.renderer.type === Phaser.WEBGL)
  46371. {
  46372. this._renderWebGL(displayObject, this._tempMatrix, clear);
  46373. }
  46374. else
  46375. {
  46376. this._renderCanvas(displayObject, this._tempMatrix, clear);
  46377. }
  46378. };
  46379. /**
  46380. * Resizes the RenderTexture.
  46381. *
  46382. * @method Phaser.RenderTexture.prototype.resize
  46383. * @param {number} width - The width to resize to.
  46384. * @param {number} height - The height to resize to.
  46385. * @param {boolean} updateBase - Should the baseTexture.width and height values be resized as well?
  46386. */
  46387. Phaser.RenderTexture.prototype.resize = function (width, height, updateBase) {
  46388. if (width === this.width && height === this.height)
  46389. {
  46390. return;
  46391. }
  46392. this.valid = (width > 0 && height > 0);
  46393. this.width = width;
  46394. this.height = height;
  46395. this.frame.width = this.crop.width = width * this.resolution;
  46396. this.frame.height = this.crop.height = height * this.resolution;
  46397. if (updateBase)
  46398. {
  46399. this.baseTexture.width = this.width * this.resolution;
  46400. this.baseTexture.height = this.height * this.resolution;
  46401. }
  46402. if (this.renderer.type === Phaser.WEBGL)
  46403. {
  46404. this.projection.x = this.width / 2;
  46405. this.projection.y = -this.height / 2;
  46406. }
  46407. if (!this.valid)
  46408. {
  46409. return;
  46410. }
  46411. this.textureBuffer.resize(this.width, this.height);
  46412. };
  46413. /**
  46414. * Clears the RenderTexture.
  46415. *
  46416. * @method Phaser.RenderTexture.prototype.clear
  46417. */
  46418. Phaser.RenderTexture.prototype.clear = function () {
  46419. if (!this.valid)
  46420. {
  46421. return;
  46422. }
  46423. if (this.renderer.type === Phaser.WEBGL)
  46424. {
  46425. this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
  46426. }
  46427. this.textureBuffer.clear();
  46428. };
  46429. /**
  46430. * This function will draw the display object to the texture.
  46431. *
  46432. * @private
  46433. * @method Phaser.RenderTexture.prototype._renderWebGL
  46434. * @param displayObject {DisplayObject} The display object to render this texture on
  46435. * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
  46436. * @param [clear] {Boolean} If true the texture will be cleared before the displayObject is drawn
  46437. * @private
  46438. */
  46439. Phaser.RenderTexture.prototype._renderWebGL = function (displayObject, matrix, clear) {
  46440. if (!this.valid || displayObject.alpha === 0)
  46441. {
  46442. return;
  46443. }
  46444. // Let's create a nice matrix to apply to our display object.
  46445. // Frame buffers come in upside down so we need to flip the matrix.
  46446. var wt = displayObject.worldTransform;
  46447. wt.identity();
  46448. wt.translate(0, this.projection.y * 2);
  46449. if (matrix)
  46450. {
  46451. wt.append(matrix);
  46452. }
  46453. wt.scale(1, -1);
  46454. // Time to update all the children of the displayObject with the new matrix.
  46455. for (var i = 0; i < displayObject.children.length; i++)
  46456. {
  46457. displayObject.children[i].updateTransform();
  46458. }
  46459. // Time for the webGL fun stuff!
  46460. var gl = this.renderer.gl;
  46461. gl.viewport(0, 0, this.width * this.resolution, this.height * this.resolution);
  46462. gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
  46463. if (clear)
  46464. {
  46465. this.textureBuffer.clear();
  46466. }
  46467. this.renderer.spriteBatch.dirty = true;
  46468. this.renderer.renderDisplayObject(displayObject, this.projection, this.textureBuffer.frameBuffer, matrix);
  46469. this.renderer.spriteBatch.dirty = true;
  46470. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  46471. };
  46472. /**
  46473. * This function will draw the display object to the texture.
  46474. *
  46475. * @private
  46476. * @method Phaser.RenderTexture.prototype._renderCanvas
  46477. * @param displayObject {DisplayObject} The display object to render this texture on
  46478. * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
  46479. * @param [clear] {Boolean} If true the texture will be cleared before the displayObject is drawn
  46480. */
  46481. Phaser.RenderTexture.prototype._renderCanvas = function (displayObject, matrix, clear) {
  46482. if (!this.valid || displayObject.alpha === 0)
  46483. {
  46484. return;
  46485. }
  46486. // Let's create a nice matrix to apply to our display object.
  46487. // Frame buffers come in upside down so we need to flip the matrix.
  46488. var wt = displayObject.worldTransform;
  46489. wt.identity();
  46490. if (matrix)
  46491. {
  46492. wt.append(matrix);
  46493. }
  46494. // Time to update all the children of the displayObject with the new matrix (what new matrix? there isn't one!)
  46495. for (var i = 0; i < displayObject.children.length; i++)
  46496. {
  46497. displayObject.children[i].updateTransform();
  46498. }
  46499. if (clear)
  46500. {
  46501. this.textureBuffer.clear();
  46502. }
  46503. var realResolution = this.renderer.resolution;
  46504. this.renderer.resolution = this.resolution;
  46505. this.renderer.renderDisplayObject(displayObject, this.textureBuffer.context, matrix);
  46506. this.renderer.resolution = realResolution;
  46507. };
  46508. /**
  46509. * Will return a HTML Image of the texture
  46510. *
  46511. * @method Phaser.RenderTexture.prototype.getImage
  46512. * @return {Image}
  46513. */
  46514. Phaser.RenderTexture.prototype.getImage = function () {
  46515. var image = new Image();
  46516. image.src = this.getBase64();
  46517. return image;
  46518. };
  46519. /**
  46520. * Will return a base64 encoded string of this texture. It works by calling RenderTexture.getCanvas and then running toDataURL on that.
  46521. *
  46522. * @method Phaser.RenderTexture.prototype.getBase64
  46523. * @return {String} A base64 encoded string of the texture.
  46524. */
  46525. Phaser.RenderTexture.prototype.getBase64 = function () {
  46526. return this.getCanvas().toDataURL();
  46527. };
  46528. /**
  46529. * Creates a Canvas element, renders this RenderTexture to it and then returns it.
  46530. *
  46531. * @method Phaser.RenderTexture.prototype.getCanvas
  46532. * @return {HTMLCanvasElement} A Canvas element with the texture rendered on.
  46533. */
  46534. Phaser.RenderTexture.prototype.getCanvas = function () {
  46535. if (this.renderer.type === Phaser.WEBGL)
  46536. {
  46537. var gl = this.renderer.gl;
  46538. var width = this.textureBuffer.width;
  46539. var height = this.textureBuffer.height;
  46540. var webGLPixels = new Uint8Array(4 * width * height);
  46541. gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
  46542. gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels);
  46543. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  46544. var tempCanvas = new PIXI.CanvasBuffer(width, height);
  46545. var canvasData = tempCanvas.context.getImageData(0, 0, width, height);
  46546. canvasData.data.set(webGLPixels);
  46547. tempCanvas.context.putImageData(canvasData, 0, 0);
  46548. return tempCanvas.canvas;
  46549. }
  46550. else
  46551. {
  46552. return this.textureBuffer.canvas;
  46553. }
  46554. };
  46555. /**
  46556. * @author Richard Davey <rich@photonstorm.com>
  46557. * @copyright 2016 Photon Storm Ltd.
  46558. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  46559. */
  46560. /**
  46561. * Create a new game object for displaying Text.
  46562. *
  46563. * This uses a local hidden Canvas object and renders the type into it. It then makes a texture from this for rendering to the view.
  46564. * Because of this you can only display fonts that are currently loaded and available to the browser: fonts must be pre-loaded.
  46565. *
  46566. * See {@link http://www.jordanm.co.uk/tinytype this compatibility table} for the available default fonts across mobile browsers.
  46567. *
  46568. * @class Phaser.Text
  46569. * @extends Phaser.Sprite
  46570. * @constructor
  46571. * @param {Phaser.Game} game - Current game instance.
  46572. * @param {number} x - X position of the new text object.
  46573. * @param {number} y - Y position of the new text object.
  46574. * @param {string} text - The actual text that will be written.
  46575. * @param {object} [style] - The style properties to be set on the Text.
  46576. * @param {string} [style.font='bold 20pt Arial'] - The style and size of the font.
  46577. * @param {string} [style.fontStyle=(from font)] - The style of the font (eg. 'italic'): overrides the value in `style.font`.
  46578. * @param {string} [style.fontVariant=(from font)] - The variant of the font (eg. 'small-caps'): overrides the value in `style.font`.
  46579. * @param {string} [style.fontWeight=(from font)] - The weight of the font (eg. 'bold'): overrides the value in `style.font`.
  46580. * @param {string|number} [style.fontSize=(from font)] - The size of the font (eg. 32 or '32px'): overrides the value in `style.font`.
  46581. * @param {string} [style.backgroundColor=null] - A canvas fillstyle that will be used as the background for the whole Text object. Set to `null` to disable.
  46582. * @param {string} [style.fill='black'] - A canvas fillstyle that will be used on the text eg 'red', '#00FF00'.
  46583. * @param {string} [style.align='left'] - Horizontal alignment of each line in multiline text. Can be: 'left', 'center' or 'right'. Does not affect single lines of text (see `textBounds` and `boundsAlignH` for that).
  46584. * @param {string} [style.boundsAlignH='left'] - Horizontal alignment of the text within the `textBounds`. Can be: 'left', 'center' or 'right'.
  46585. * @param {string} [style.boundsAlignV='top'] - Vertical alignment of the text within the `textBounds`. Can be: 'top', 'middle' or 'bottom'.
  46586. * @param {string} [style.stroke='black'] - A canvas stroke style that will be used on the text stroke eg 'blue', '#FCFF00'.
  46587. * @param {number} [style.strokeThickness=0] - A number that represents the thickness of the stroke. Default is 0 (no stroke).
  46588. * @param {boolean} [style.wordWrap=false] - Indicates if word wrap should be used.
  46589. * @param {number} [style.wordWrapWidth=100] - The width in pixels at which text will wrap.
  46590. * @param {number} [style.maxLines=0] - The maximum number of lines to be shown for wrapped text.
  46591. * @param {number} [style.tabs=0] - The size (in pixels) of the tabs, for when text includes tab characters. 0 disables. Can be an array of varying tab sizes, one per tab stop.
  46592. */
  46593. Phaser.Text = function (game, x, y, text, style) {
  46594. x = x || 0;
  46595. y = y || 0;
  46596. if (text === undefined || text === null)
  46597. {
  46598. text = '';
  46599. }
  46600. else
  46601. {
  46602. text = text.toString();
  46603. }
  46604. style = Phaser.Utils.extend({}, style);
  46605. /**
  46606. * @property {number} type - The const type of this object.
  46607. * @default
  46608. */
  46609. this.type = Phaser.TEXT;
  46610. /**
  46611. * @property {number} physicsType - The const physics body type of this object.
  46612. * @readonly
  46613. */
  46614. this.physicsType = Phaser.SPRITE;
  46615. /**
  46616. * Specify a padding value which is added to the line width and height when calculating the Text size.
  46617. * ALlows you to add extra spacing if Phaser is unable to accurately determine the true font dimensions.
  46618. * @property {Phaser.Point} padding
  46619. */
  46620. this.padding = new Phaser.Point();
  46621. /**
  46622. * The textBounds property allows you to specify a rectangular region upon which text alignment is based.
  46623. * See `Text.setTextBounds` for more details.
  46624. * @property {Phaser.Rectangle} textBounds
  46625. * @readOnly
  46626. */
  46627. this.textBounds = null;
  46628. /**
  46629. * @property {HTMLCanvasElement} canvas - The canvas element that the text is rendered.
  46630. */
  46631. this.canvas = Phaser.CanvasPool.create(this);
  46632. /**
  46633. * @property {HTMLCanvasElement} context - The context of the canvas element that the text is rendered to.
  46634. */
  46635. this.context = this.canvas.getContext('2d');
  46636. /**
  46637. * @property {array} colors - An array of the color values as specified by {@link Phaser.Text#addColor addColor}.
  46638. */
  46639. this.colors = [];
  46640. /**
  46641. * @property {array} strokeColors - An array of the stroke color values as specified by {@link Phaser.Text#addStrokeColor addStrokeColor}.
  46642. */
  46643. this.strokeColors = [];
  46644. /**
  46645. * @property {array} fontStyles - An array of the font styles values as specified by {@link Phaser.Text#addFontStyle addFontStyle}.
  46646. */
  46647. this.fontStyles = [];
  46648. /**
  46649. * @property {array} fontWeights - An array of the font weights values as specified by {@link Phaser.Text#addFontWeight addFontWeight}.
  46650. */
  46651. this.fontWeights = [];
  46652. /**
  46653. * Should the linePositionX and Y values be automatically rounded before rendering the Text?
  46654. * You may wish to enable this if you want to remove the effect of sub-pixel aliasing from text.
  46655. * @property {boolean} autoRound
  46656. * @default
  46657. */
  46658. this.autoRound = false;
  46659. /**
  46660. * Will this Text object use Basic or Advanced Word Wrapping?
  46661. *
  46662. * Advanced wrapping breaks long words if they are the first of a line, and repeats the process as necessary.
  46663. * White space is condensed (e.g., consecutive spaces are replaced with one).
  46664. * Lines are trimmed of white space before processing.
  46665. *
  46666. * It throws an error if wordWrapWidth is less than a single character.
  46667. * @property {boolean} useAdvancedWrap
  46668. * @default
  46669. */
  46670. this.useAdvancedWrap = false;
  46671. /**
  46672. * The Regular Expression that is used to split the text up into lines, in
  46673. * multi-line text. By default this is `/(?:\r\n|\r|\n)/`.
  46674. * You can change this RegExp to be anything else that you may need.
  46675. * @property {Object} splitRegExp
  46676. */
  46677. this.splitRegExp = /(?:\r\n|\r|\n)/;
  46678. /** The maximum number of characters that can be set.
  46679. * @property {number} characterLimitSize
  46680. */
  46681. this.characterLimitSize = -1;
  46682. /** The suffix that is applied to truncated text that is longer than the
  46683. * characterLimitSize.
  46684. * @property {string} characterLimitSuffix
  46685. */
  46686. this.characterLimitSuffix = '';
  46687. /**
  46688. * @property {number} _res - Internal canvas resolution var.
  46689. * @private
  46690. */
  46691. this._res = game.renderer.resolution;
  46692. /**
  46693. * @property {string} _text - Internal cache var.
  46694. * @private
  46695. */
  46696. this._text = text;
  46697. /**
  46698. * @property {object} _fontComponents - The font, broken down into components, set in `setStyle`.
  46699. * @private
  46700. */
  46701. this._fontComponents = null;
  46702. /**
  46703. * @property {number} lineSpacing - Additional spacing (in pixels) between each line of text if multi-line.
  46704. * @private
  46705. */
  46706. this._lineSpacing = 0;
  46707. /**
  46708. * @property {number} _charCount - Internal character counter used by the text coloring.
  46709. * @private
  46710. */
  46711. this._charCount = 0;
  46712. /**
  46713. * @property {number} _width - Internal width var.
  46714. * @private
  46715. */
  46716. this._width = 0;
  46717. /**
  46718. * @property {number} _height - Internal height var.
  46719. * @private
  46720. */
  46721. this._height = 0;
  46722. Phaser.Sprite.call(this, game, x, y, PIXI.Texture.fromCanvas(this.canvas));
  46723. this.setStyle(style);
  46724. if (text !== '')
  46725. {
  46726. this.updateText();
  46727. }
  46728. };
  46729. Phaser.Text.prototype = Object.create(Phaser.Sprite.prototype);
  46730. Phaser.Text.prototype.constructor = Phaser.Text;
  46731. /**
  46732. * Automatically called by World.preUpdate.
  46733. *
  46734. * @method Phaser.Text#preUpdate
  46735. * @protected
  46736. */
  46737. Phaser.Text.prototype.preUpdate = function () {
  46738. if (!this.preUpdatePhysics() || !this.preUpdateLifeSpan() || !this.preUpdateInWorld())
  46739. {
  46740. return false;
  46741. }
  46742. return this.preUpdateCore();
  46743. };
  46744. /**
  46745. * Override this function to handle any special update requirements.
  46746. *
  46747. * @method Phaser.Text#update
  46748. * @protected
  46749. */
  46750. Phaser.Text.prototype.update = function() {
  46751. };
  46752. /**
  46753. * Destroy this Text object, removing it from the group it belongs to.
  46754. *
  46755. * @method Phaser.Text#destroy
  46756. * @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
  46757. */
  46758. Phaser.Text.prototype.destroy = function (destroyChildren) {
  46759. this.texture.destroy(true);
  46760. Phaser.Component.Destroy.prototype.destroy.call(this, destroyChildren);
  46761. };
  46762. /**
  46763. * Sets a drop shadow effect on the Text. You can specify the horizontal and vertical distance of the drop shadow with the `x` and `y` parameters.
  46764. * The color controls the shade of the shadow (default is black) and can be either an `rgba` or `hex` value.
  46765. * The blur is the strength of the shadow. A value of zero means a hard shadow, a value of 10 means a very soft shadow.
  46766. * To remove a shadow already in place you can call this method with no parameters set.
  46767. *
  46768. * @method Phaser.Text#setShadow
  46769. * @param {number} [x=0] - The shadowOffsetX value in pixels. This is how far offset horizontally the shadow effect will be.
  46770. * @param {number} [y=0] - The shadowOffsetY value in pixels. This is how far offset vertically the shadow effect will be.
  46771. * @param {string} [color='rgba(0,0,0,1)'] - The color of the shadow, as given in CSS rgba or hex format. Set the alpha component to 0 to disable the shadow.
  46772. * @param {number} [blur=0] - The shadowBlur value. Make the shadow softer by applying a Gaussian blur to it. A number from 0 (no blur) up to approx. 10 (depending on scene).
  46773. * @param {boolean} [shadowStroke=true] - Apply the drop shadow to the Text stroke (if set).
  46774. * @param {boolean} [shadowFill=true] - Apply the drop shadow to the Text fill (if set).
  46775. * @return {Phaser.Text} This Text instance.
  46776. */
  46777. Phaser.Text.prototype.setShadow = function (x, y, color, blur, shadowStroke, shadowFill) {
  46778. if (x === undefined) { x = 0; }
  46779. if (y === undefined) { y = 0; }
  46780. if (color === undefined) { color = 'rgba(0, 0, 0, 1)'; }
  46781. if (blur === undefined) { blur = 0; }
  46782. if (shadowStroke === undefined) { shadowStroke = true; }
  46783. if (shadowFill === undefined) { shadowFill = true; }
  46784. this.style.shadowOffsetX = x;
  46785. this.style.shadowOffsetY = y;
  46786. this.style.shadowColor = color;
  46787. this.style.shadowBlur = blur;
  46788. this.style.shadowStroke = shadowStroke;
  46789. this.style.shadowFill = shadowFill;
  46790. this.dirty = true;
  46791. return this;
  46792. };
  46793. /**
  46794. * Set the style of the text by passing a single style object to it.
  46795. *
  46796. * @method Phaser.Text#setStyle
  46797. * @param {object} [style] - The style properties to be set on the Text.
  46798. * @param {string} [style.font='bold 20pt Arial'] - The style and size of the font.
  46799. * @param {string} [style.fontStyle=(from font)] - The style of the font (eg. 'italic'): overrides the value in `style.font`.
  46800. * @param {string} [style.fontVariant=(from font)] - The variant of the font (eg. 'small-caps'): overrides the value in `style.font`.
  46801. * @param {string} [style.fontWeight=(from font)] - The weight of the font (eg. 'bold'): overrides the value in `style.font`.
  46802. * @param {string|number} [style.fontSize=(from font)] - The size of the font (eg. 32 or '32px'): overrides the value in `style.font`.
  46803. * @param {string} [style.backgroundColor=null] - A canvas fillstyle that will be used as the background for the whole Text object. Set to `null` to disable.
  46804. * @param {string} [style.fill='black'] - A canvas fillstyle that will be used on the text eg 'red', '#00FF00'.
  46805. * @param {string} [style.align='left'] - Horizontal alignment of each line in multiline text. Can be: 'left', 'center' or 'right'. Does not affect single lines of text (see `textBounds` and `boundsAlignH` for that).
  46806. * @param {string} [style.boundsAlignH='left'] - Horizontal alignment of the text within the `textBounds`. Can be: 'left', 'center' or 'right'.
  46807. * @param {string} [style.boundsAlignV='top'] - Vertical alignment of the text within the `textBounds`. Can be: 'top', 'middle' or 'bottom'.
  46808. * @param {string} [style.stroke='black'] - A canvas stroke style that will be used on the text stroke eg 'blue', '#FCFF00'.
  46809. * @param {number} [style.strokeThickness=0] - A number that represents the thickness of the stroke. Default is 0 (no stroke).
  46810. * @param {boolean} [style.wordWrap=false] - Indicates if word wrap should be used.
  46811. * @param {number} [style.wordWrapWidth=100] - The width in pixels at which text will wrap.
  46812. * @param {number} [style.maxLines=0] - The maximum number of lines to be shown for wrapped text.
  46813. * @param {number|array} [style.tabs=0] - The size (in pixels) of the tabs, for when text includes tab characters. 0 disables. Can be an array of varying tab sizes, one per tab stop.
  46814. * @param {boolean} [update=false] - Immediately update the Text object after setting the new style? Or wait for the next frame.
  46815. * @return {Phaser.Text} This Text instance.
  46816. */
  46817. Phaser.Text.prototype.setStyle = function (style, update) {
  46818. if (update === undefined) { update = false; }
  46819. var newStyle = Object.assign({}, style);
  46820. newStyle.font = style.font || 'bold 20pt Arial';
  46821. newStyle.backgroundColor = style.backgroundColor || null;
  46822. newStyle.fill = style.fill || 'black';
  46823. newStyle.align = (style.align || 'left').toLowerCase();
  46824. newStyle.boundsAlignH = (style.boundsAlignH || 'left').toLowerCase();
  46825. newStyle.boundsAlignV = (style.boundsAlignV || 'top').toLowerCase();
  46826. newStyle.stroke = style.stroke || 'black'; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136
  46827. newStyle.strokeThickness = Number(style.strokeThickness) || 0;
  46828. newStyle.wordWrap = style.wordWrap || false;
  46829. newStyle.wordWrapWidth = style.wordWrapWidth || 100;
  46830. newStyle.maxLines = style.maxLines || 0;
  46831. newStyle.shadowOffsetX = style.shadowOffsetX || 0;
  46832. newStyle.shadowOffsetY = style.shadowOffsetY || 0;
  46833. newStyle.shadowColor = style.shadowColor || 'rgba(0,0,0,0)';
  46834. newStyle.shadowBlur = style.shadowBlur || 0;
  46835. newStyle.tabs = style.tabs || 0;
  46836. var components = this.fontToComponents(newStyle.font);
  46837. if (newStyle.fontStyle)
  46838. {
  46839. components.fontStyle = newStyle.fontStyle;
  46840. }
  46841. if (newStyle.fontVariant)
  46842. {
  46843. components.fontVariant = newStyle.fontVariant;
  46844. }
  46845. if (newStyle.fontWeight)
  46846. {
  46847. components.fontWeight = newStyle.fontWeight;
  46848. }
  46849. if (newStyle.fontSize)
  46850. {
  46851. if (typeof newStyle.fontSize === 'number')
  46852. {
  46853. newStyle.fontSize = newStyle.fontSize + 'px';
  46854. }
  46855. components.fontSize = newStyle.fontSize;
  46856. }
  46857. this._fontComponents = components;
  46858. newStyle.font = this.componentsToFont(this._fontComponents);
  46859. this.style = newStyle;
  46860. this.dirty = true;
  46861. if (update)
  46862. {
  46863. this.updateText();
  46864. }
  46865. return this;
  46866. };
  46867. /**
  46868. * Renders text to the internal canvas.
  46869. *
  46870. * @method Phaser.Text#updateText
  46871. * @private
  46872. */
  46873. Phaser.Text.prototype.updateText = function () {
  46874. this.texture.baseTexture.resolution = this._res;
  46875. this.context.font = this.style.font;
  46876. var outputText = this.text;
  46877. if (this.characterLimitSize > -1 && this.characterLimitSize < outputText.length) {
  46878. outputText = this.text.substring(0, this.characterLimitSize) + this.characterLimitSuffix;
  46879. }
  46880. if (this.style.wordWrap)
  46881. {
  46882. outputText = this.runWordWrap(this.text);
  46883. }
  46884. // Split text into lines
  46885. var lines = outputText.split(this.splitRegExp);
  46886. // Calculate text width
  46887. var tabs = this.style.tabs;
  46888. var lineWidths = [];
  46889. var maxLineWidth = 0;
  46890. var fontProperties = this.determineFontProperties(this.style.font);
  46891. var drawnLines = lines.length;
  46892. if (this.style.maxLines > 0 && this.style.maxLines < lines.length)
  46893. {
  46894. drawnLines = this.style.maxLines;
  46895. }
  46896. this._charCount = 0;
  46897. for (var i = 0; i < drawnLines; i++)
  46898. {
  46899. if (tabs === 0)
  46900. {
  46901. // Simple layout (no tabs)
  46902. var lineWidth = this.style.strokeThickness + this.padding.x;
  46903. if (this.colors.length > 0 || this.strokeColors.length > 0 || this.fontWeights.length > 0 || this.fontStyles.length > 0)
  46904. {
  46905. lineWidth += this.measureLine(lines[i]);
  46906. }
  46907. else
  46908. {
  46909. lineWidth += this.context.measureText(lines[i]).width;
  46910. }
  46911. // Adjust for wrapped text
  46912. if (this.style.wordWrap)
  46913. {
  46914. lineWidth -= this.context.measureText(' ').width;
  46915. }
  46916. }
  46917. else
  46918. {
  46919. // Complex layout (tabs)
  46920. var line = lines[i].split(/(?:\t)/);
  46921. var lineWidth = this.padding.x + this.style.strokeThickness;
  46922. if (Array.isArray(tabs))
  46923. {
  46924. var tab = 0;
  46925. for (var c = 0; c < line.length; c++)
  46926. {
  46927. var section = 0;
  46928. if (this.colors.length > 0 || this.strokeColors.length > 0 || this.fontWeights.length > 0 || this.fontStyles.length > 0)
  46929. {
  46930. section = this.measureLine(line[c]);
  46931. }
  46932. else
  46933. {
  46934. section = Math.ceil(this.context.measureText(line[c]).width);
  46935. }
  46936. if (c > 0)
  46937. {
  46938. tab += tabs[c - 1];
  46939. }
  46940. lineWidth = tab + section;
  46941. }
  46942. }
  46943. else
  46944. {
  46945. for (var c = 0; c < line.length; c++)
  46946. {
  46947. // How far to the next tab?
  46948. if (this.colors.length > 0 || this.strokeColors.length > 0 || this.fontWeights.length > 0 || this.fontStyles.length > 0)
  46949. {
  46950. lineWidth += this.measureLine(line[c]);
  46951. }
  46952. else
  46953. {
  46954. lineWidth += Math.ceil(this.context.measureText(line[c]).width);
  46955. }
  46956. var diff = this.game.math.snapToCeil(lineWidth, tabs) - lineWidth;
  46957. lineWidth += diff;
  46958. }
  46959. }
  46960. }
  46961. lineWidths[i] = Math.ceil(lineWidth);
  46962. maxLineWidth = Math.max(maxLineWidth, lineWidths[i]);
  46963. }
  46964. this.canvas.width = maxLineWidth * this._res;
  46965. // Calculate text height
  46966. var lineHeight = fontProperties.fontSize + this.style.strokeThickness + this.padding.y;
  46967. var height = lineHeight * drawnLines;
  46968. var lineSpacing = this._lineSpacing;
  46969. if (lineSpacing < 0 && Math.abs(lineSpacing) > lineHeight)
  46970. {
  46971. lineSpacing = -lineHeight;
  46972. }
  46973. // Adjust for line spacing
  46974. if (lineSpacing !== 0)
  46975. {
  46976. height += (lineSpacing > 0) ? lineSpacing * lines.length : lineSpacing * (lines.length - 1);
  46977. }
  46978. this.canvas.height = height * this._res;
  46979. this.context.scale(this._res, this._res);
  46980. if (navigator.isCocoonJS)
  46981. {
  46982. this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  46983. }
  46984. if (this.style.backgroundColor)
  46985. {
  46986. this.context.fillStyle = this.style.backgroundColor;
  46987. this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
  46988. }
  46989. this.context.fillStyle = this.style.fill;
  46990. this.context.font = this.style.font;
  46991. this.context.strokeStyle = this.style.stroke;
  46992. this.context.textBaseline = 'alphabetic';
  46993. this.context.lineWidth = this.style.strokeThickness;
  46994. this.context.lineCap = 'round';
  46995. this.context.lineJoin = 'round';
  46996. var linePositionX;
  46997. var linePositionY;
  46998. this._charCount = 0;
  46999. // Draw text line by line
  47000. for (i = 0; i < drawnLines; i++)
  47001. {
  47002. // Split the line by
  47003. linePositionX = this.style.strokeThickness / 2;
  47004. linePositionY = (this.style.strokeThickness / 2 + i * lineHeight) + fontProperties.ascent;
  47005. if (i > 0)
  47006. {
  47007. linePositionY += (lineSpacing * i);
  47008. }
  47009. if (this.style.align === 'right')
  47010. {
  47011. linePositionX += maxLineWidth - lineWidths[i];
  47012. }
  47013. else if (this.style.align === 'center')
  47014. {
  47015. linePositionX += (maxLineWidth - lineWidths[i]) / 2;
  47016. }
  47017. if (this.autoRound)
  47018. {
  47019. linePositionX = Math.round(linePositionX);
  47020. linePositionY = Math.round(linePositionY);
  47021. }
  47022. if (this.colors.length > 0 || this.strokeColors.length > 0 || this.fontWeights.length > 0 || this.fontStyles.length > 0)
  47023. {
  47024. this.updateLine(lines[i], linePositionX, linePositionY);
  47025. }
  47026. else
  47027. {
  47028. if (this.style.stroke && this.style.strokeThickness)
  47029. {
  47030. this.updateShadow(this.style.shadowStroke);
  47031. if (tabs === 0)
  47032. {
  47033. this.context.strokeText(lines[i], linePositionX, linePositionY);
  47034. }
  47035. else
  47036. {
  47037. this.renderTabLine(lines[i], linePositionX, linePositionY, false);
  47038. }
  47039. }
  47040. if (this.style.fill)
  47041. {
  47042. this.updateShadow(this.style.shadowFill);
  47043. if (tabs === 0)
  47044. {
  47045. this.context.fillText(lines[i], linePositionX, linePositionY);
  47046. }
  47047. else
  47048. {
  47049. this.renderTabLine(lines[i], linePositionX, linePositionY, true);
  47050. }
  47051. }
  47052. }
  47053. }
  47054. this.updateTexture();
  47055. this.dirty = false;
  47056. };
  47057. /**
  47058. * Renders a line of text that contains tab characters if Text.tab > 0.
  47059. * Called automatically by updateText.
  47060. *
  47061. * @method Phaser.Text#renderTabLine
  47062. * @private
  47063. * @param {string} line - The line of text to render.
  47064. * @param {integer} x - The x position to start rendering from.
  47065. * @param {integer} y - The y position to start rendering from.
  47066. * @param {boolean} fill - If true uses fillText, if false uses strokeText.
  47067. */
  47068. Phaser.Text.prototype.renderTabLine = function (line, x, y, fill) {
  47069. var text = line.split(/(?:\t)/);
  47070. var tabs = this.style.tabs;
  47071. var snap = 0;
  47072. if (Array.isArray(tabs))
  47073. {
  47074. var tab = 0;
  47075. for (var c = 0; c < text.length; c++)
  47076. {
  47077. if (c > 0)
  47078. {
  47079. tab += tabs[c - 1];
  47080. }
  47081. snap = x + tab;
  47082. if (fill)
  47083. {
  47084. this.context.fillText(text[c], snap, y);
  47085. }
  47086. else
  47087. {
  47088. this.context.strokeText(text[c], snap, y);
  47089. }
  47090. }
  47091. }
  47092. else
  47093. {
  47094. for (var c = 0; c < text.length; c++)
  47095. {
  47096. var section = Math.ceil(this.context.measureText(text[c]).width);
  47097. // How far to the next tab?
  47098. snap = this.game.math.snapToCeil(x, tabs);
  47099. if (fill)
  47100. {
  47101. this.context.fillText(text[c], snap, y);
  47102. }
  47103. else
  47104. {
  47105. this.context.strokeText(text[c], snap, y);
  47106. }
  47107. x = snap + section;
  47108. }
  47109. }
  47110. };
  47111. /**
  47112. * Sets the Shadow on the Text.context based on the Style settings, or disables it if not enabled.
  47113. * This is called automatically by Text.updateText.
  47114. *
  47115. * @method Phaser.Text#updateShadow
  47116. * @param {boolean} state - If true the shadow will be set to the Style values, otherwise it will be set to zero.
  47117. */
  47118. Phaser.Text.prototype.updateShadow = function (state) {
  47119. if (state)
  47120. {
  47121. this.context.shadowOffsetX = this.style.shadowOffsetX;
  47122. this.context.shadowOffsetY = this.style.shadowOffsetY;
  47123. this.context.shadowColor = this.style.shadowColor;
  47124. this.context.shadowBlur = this.style.shadowBlur;
  47125. }
  47126. else
  47127. {
  47128. this.context.shadowOffsetX = 0;
  47129. this.context.shadowOffsetY = 0;
  47130. this.context.shadowColor = 0;
  47131. this.context.shadowBlur = 0;
  47132. }
  47133. };
  47134. /**
  47135. * Measures a line of text character by character taking into the account the specified character styles.
  47136. *
  47137. * @method Phaser.Text#measureLine
  47138. * @private
  47139. * @param {string} line - The line of text to measure.
  47140. * @return {integer} length of the line.
  47141. */
  47142. Phaser.Text.prototype.measureLine = function (line) {
  47143. var lineLength = 0;
  47144. for (var i = 0; i < line.length; i++)
  47145. {
  47146. var letter = line[i];
  47147. if (this.fontWeights.length > 0 || this.fontStyles.length > 0)
  47148. {
  47149. var components = this.fontToComponents(this.context.font);
  47150. if (this.fontStyles[this._charCount])
  47151. {
  47152. components.fontStyle = this.fontStyles[this._charCount];
  47153. }
  47154. if (this.fontWeights[this._charCount])
  47155. {
  47156. components.fontWeight = this.fontWeights[this._charCount];
  47157. }
  47158. this.context.font = this.componentsToFont(components);
  47159. }
  47160. if (this.style.stroke && this.style.strokeThickness)
  47161. {
  47162. if (this.strokeColors[this._charCount])
  47163. {
  47164. this.context.strokeStyle = this.strokeColors[this._charCount];
  47165. }
  47166. this.updateShadow(this.style.shadowStroke);
  47167. }
  47168. if (this.style.fill)
  47169. {
  47170. if (this.colors[this._charCount])
  47171. {
  47172. this.context.fillStyle = this.colors[this._charCount];
  47173. }
  47174. this.updateShadow(this.style.shadowFill);
  47175. }
  47176. lineLength += this.context.measureText(letter).width;
  47177. this._charCount++;
  47178. }
  47179. return Math.ceil(lineLength);
  47180. };
  47181. /**
  47182. * Updates a line of text, applying fill and stroke per-character colors or style and weight per-character font if applicable.
  47183. *
  47184. * @method Phaser.Text#updateLine
  47185. * @private
  47186. */
  47187. Phaser.Text.prototype.updateLine = function (line, x, y) {
  47188. for (var i = 0; i < line.length; i++)
  47189. {
  47190. var letter = line[i];
  47191. if (this.fontWeights.length > 0 || this.fontStyles.length > 0)
  47192. {
  47193. var components = this.fontToComponents(this.context.font);
  47194. if (this.fontStyles[this._charCount])
  47195. {
  47196. components.fontStyle = this.fontStyles[this._charCount];
  47197. }
  47198. if (this.fontWeights[this._charCount])
  47199. {
  47200. components.fontWeight = this.fontWeights[this._charCount];
  47201. }
  47202. this.context.font = this.componentsToFont(components);
  47203. }
  47204. if (this.style.stroke && this.style.strokeThickness)
  47205. {
  47206. if (this.strokeColors[this._charCount])
  47207. {
  47208. this.context.strokeStyle = this.strokeColors[this._charCount];
  47209. }
  47210. this.updateShadow(this.style.shadowStroke);
  47211. this.context.strokeText(letter, x, y);
  47212. }
  47213. if (this.style.fill)
  47214. {
  47215. if (this.colors[this._charCount])
  47216. {
  47217. this.context.fillStyle = this.colors[this._charCount];
  47218. }
  47219. this.updateShadow(this.style.shadowFill);
  47220. this.context.fillText(letter, x, y);
  47221. }
  47222. x += this.context.measureText(letter).width;
  47223. this._charCount++;
  47224. }
  47225. };
  47226. /**
  47227. * Clears any text fill or stroke colors that were set by `addColor` or `addStrokeColor`.
  47228. *
  47229. * @method Phaser.Text#clearColors
  47230. * @return {Phaser.Text} This Text instance.
  47231. */
  47232. Phaser.Text.prototype.clearColors = function () {
  47233. this.colors = [];
  47234. this.strokeColors = [];
  47235. this.dirty = true;
  47236. return this;
  47237. };
  47238. /**
  47239. * Clears any text styles or weights font that were set by `addFontStyle` or `addFontWeight`.
  47240. *
  47241. * @method Phaser.Text#clearFontValues
  47242. * @return {Phaser.Text} This Text instance.
  47243. */
  47244. Phaser.Text.prototype.clearFontValues = function () {
  47245. this.fontStyles = [];
  47246. this.fontWeights = [];
  47247. this.dirty = true;
  47248. return this;
  47249. };
  47250. /**
  47251. * Set specific colors for certain characters within the Text.
  47252. *
  47253. * It works by taking a color value, which is a typical HTML string such as `#ff0000` or `rgb(255,0,0)` and a position.
  47254. * The position value is the index of the character in the Text string to start applying this color to.
  47255. * Once set the color remains in use until either another color or the end of the string is encountered.
  47256. * For example if the Text was `Photon Storm` and you did `Text.addColor('#ffff00', 6)` it would color in the word `Storm` in yellow.
  47257. *
  47258. * If you wish to change the stroke color see addStrokeColor instead.
  47259. *
  47260. * @method Phaser.Text#addColor
  47261. * @param {string} color - A canvas fillstyle that will be used on the text eg `red`, `#00FF00`, `rgba()`.
  47262. * @param {number} position - The index of the character in the string to start applying this color value from.
  47263. * @return {Phaser.Text} This Text instance.
  47264. */
  47265. Phaser.Text.prototype.addColor = function (color, position) {
  47266. this.colors[position] = color;
  47267. this.dirty = true;
  47268. return this;
  47269. };
  47270. /**
  47271. * Set specific stroke colors for certain characters within the Text.
  47272. *
  47273. * It works by taking a color value, which is a typical HTML string such as `#ff0000` or `rgb(255,0,0)` and a position.
  47274. * The position value is the index of the character in the Text string to start applying this color to.
  47275. * Once set the color remains in use until either another color or the end of the string is encountered.
  47276. * For example if the Text was `Photon Storm` and you did `Text.addColor('#ffff00', 6)` it would color in the word `Storm` in yellow.
  47277. *
  47278. * This has no effect if stroke is disabled or has a thickness of 0.
  47279. *
  47280. * If you wish to change the text fill color see addColor instead.
  47281. *
  47282. * @method Phaser.Text#addStrokeColor
  47283. * @param {string} color - A canvas fillstyle that will be used on the text stroke eg `red`, `#00FF00`, `rgba()`.
  47284. * @param {number} position - The index of the character in the string to start applying this color value from.
  47285. * @return {Phaser.Text} This Text instance.
  47286. */
  47287. Phaser.Text.prototype.addStrokeColor = function (color, position) {
  47288. this.strokeColors[position] = color;
  47289. this.dirty = true;
  47290. return this;
  47291. };
  47292. /**
  47293. * Set specific font styles for certain characters within the Text.
  47294. *
  47295. * It works by taking a font style value, which is a typical string such as `normal`, `italic` or `oblique`.
  47296. * The position value is the index of the character in the Text string to start applying this font style to.
  47297. * Once set the font style remains in use until either another font style or the end of the string is encountered.
  47298. * For example if the Text was `Photon Storm` and you did `Text.addFontStyle('italic', 6)` it would font style in the word `Storm` in italic.
  47299. *
  47300. * If you wish to change the text font weight see addFontWeight instead.
  47301. *
  47302. * @method Phaser.Text#addFontStyle
  47303. * @param {string} style - A canvas font-style that will be used on the text style eg `normal`, `italic`, `oblique`.
  47304. * @param {number} position - The index of the character in the string to start applying this font style value from.
  47305. * @return {Phaser.Text} This Text instance.
  47306. */
  47307. Phaser.Text.prototype.addFontStyle = function (style, position) {
  47308. this.fontStyles[position] = style;
  47309. this.dirty = true;
  47310. return this;
  47311. };
  47312. /**
  47313. * Set specific font weights for certain characters within the Text.
  47314. *
  47315. * It works by taking a font weight value, which is a typical string such as `normal`, `bold`, `bolder`, etc.
  47316. * The position value is the index of the character in the Text string to start applying this font weight to.
  47317. * Once set the font weight remains in use until either another font weight or the end of the string is encountered.
  47318. * For example if the Text was `Photon Storm` and you did `Text.addFontWeight('bold', 6)` it would font weight in the word `Storm` in bold.
  47319. *
  47320. * If you wish to change the text font style see addFontStyle instead.
  47321. *
  47322. * @method Phaser.Text#addFontWeight
  47323. * @param {string} style - A canvas font-weight that will be used on the text weight eg `normal`, `bold`, `bolder`, `lighter`, etc.
  47324. * @param {number} position - The index of the character in the string to start applying this font weight value from.
  47325. * @return {Phaser.Text} This Text instance.
  47326. */
  47327. Phaser.Text.prototype.addFontWeight = function (weight, position) {
  47328. this.fontWeights[position] = weight;
  47329. this.dirty = true;
  47330. return this;
  47331. };
  47332. /**
  47333. * Runs the given text through the Text.runWordWrap function and returns
  47334. * the results as an array, where each element of the array corresponds to a wrapped
  47335. * line of text.
  47336. *
  47337. * Useful if you wish to control pagination on long pieces of content.
  47338. *
  47339. * @method Phaser.Text#precalculateWordWrap
  47340. * @param {string} text - The text for which the wrapping will be calculated.
  47341. * @return {array} An array of strings with the pieces of wrapped text.
  47342. */
  47343. Phaser.Text.prototype.precalculateWordWrap = function (text) {
  47344. this.texture.baseTexture.resolution = this._res;
  47345. this.context.font = this.style.font;
  47346. var wrappedLines = this.runWordWrap(text);
  47347. return wrappedLines.split(/(?:\r\n|\r|\n)/);
  47348. };
  47349. /**
  47350. * Greedy wrapping algorithm that will wrap words as the line grows longer than its horizontal bounds.
  47351. *
  47352. * @method Phaser.Text#runWordWrap
  47353. * @param {string} text - The text to perform word wrap detection against.
  47354. * @private
  47355. */
  47356. Phaser.Text.prototype.runWordWrap = function (text) {
  47357. if (this.useAdvancedWrap)
  47358. {
  47359. return this.advancedWordWrap(text);
  47360. }
  47361. else
  47362. {
  47363. return this.basicWordWrap(text);
  47364. }
  47365. };
  47366. /**
  47367. * Advanced wrapping algorithm that will wrap words as the line grows longer than its horizontal bounds.
  47368. * White space is condensed (e.g., consecutive spaces are replaced with one).
  47369. * Lines are trimmed of white space before processing.
  47370. * Throws an error if the user was smart enough to specify a wordWrapWidth less than a single character.
  47371. *
  47372. * @method Phaser.Text#advancedWordWrap
  47373. * @param {string} text - The text to perform word wrap detection against.
  47374. * @private
  47375. */
  47376. Phaser.Text.prototype.advancedWordWrap = function (text) {
  47377. var context = this.context;
  47378. var wordWrapWidth = this.style.wordWrapWidth;
  47379. var output = '';
  47380. // (1) condense whitespace
  47381. // (2) split into lines
  47382. var lines = text
  47383. .replace(/ +/gi, ' ')
  47384. .split(/\r?\n/gi);
  47385. var linesCount = lines.length;
  47386. for (var i = 0; i < linesCount; i++)
  47387. {
  47388. var line = lines[i];
  47389. var out = '';
  47390. // trim whitespace
  47391. line = line.replace(/^ *|\s*$/gi, '');
  47392. // if entire line is less than wordWrapWidth
  47393. // append the entire line and exit early
  47394. var lineWidth = context.measureText(line).width;
  47395. if (lineWidth < wordWrapWidth)
  47396. {
  47397. output += line + '\n';
  47398. continue;
  47399. }
  47400. // otherwise, calculate new lines
  47401. var currentLineWidth = wordWrapWidth;
  47402. // split into words
  47403. var words = line.split(' ');
  47404. for (var j = 0; j < words.length; j++)
  47405. {
  47406. var word = words[j];
  47407. var wordWithSpace = word + ' ';
  47408. var wordWidth = context.measureText(wordWithSpace).width;
  47409. if (wordWidth > currentLineWidth)
  47410. {
  47411. // break word
  47412. if (j === 0)
  47413. {
  47414. // shave off letters from word until it's small enough
  47415. var newWord = wordWithSpace;
  47416. while (newWord.length)
  47417. {
  47418. newWord = newWord.slice(0, -1);
  47419. wordWidth = context.measureText(newWord).width;
  47420. if (wordWidth <= currentLineWidth)
  47421. {
  47422. break;
  47423. }
  47424. }
  47425. // if wordWrapWidth is too small for even a single
  47426. // letter, shame user failure with a fatal error
  47427. if (!newWord.length)
  47428. {
  47429. throw new Error('This text\'s wordWrapWidth setting is less than a single character!');
  47430. }
  47431. // replace current word in array with remainder
  47432. var secondPart = word.substr(newWord.length);
  47433. words[j] = secondPart;
  47434. // append first piece to output
  47435. out += newWord;
  47436. }
  47437. // if existing word length is 0, don't include it
  47438. var offset = (words[j].length) ? j : j + 1;
  47439. // collapse rest of sentence
  47440. var remainder = words.slice(offset).join(' ')
  47441. // remove any trailing white space
  47442. .replace(/[ \n]*$/gi, '');
  47443. // prepend remainder to next line
  47444. lines[i + 1] = remainder + ' ' + (lines[i + 1] || '');
  47445. linesCount = lines.length;
  47446. break; // processing on this line
  47447. // append word with space to output
  47448. }
  47449. else
  47450. {
  47451. out += wordWithSpace;
  47452. currentLineWidth -= wordWidth;
  47453. }
  47454. }
  47455. // append processed line to output
  47456. output += out.replace(/[ \n]*$/gi, '') + '\n';
  47457. }
  47458. // trim the end of the string
  47459. output = output.replace(/[\s|\n]*$/gi, '');
  47460. return output;
  47461. };
  47462. /**
  47463. * Greedy wrapping algorithm that will wrap words as the line grows longer than its horizontal bounds.
  47464. *
  47465. * @method Phaser.Text#basicWordWrap
  47466. * @param {string} text - The text to perform word wrap detection against.
  47467. * @private
  47468. */
  47469. Phaser.Text.prototype.basicWordWrap = function (text) {
  47470. var result = '';
  47471. var lines = text.split('\n');
  47472. for (var i = 0; i < lines.length; i++)
  47473. {
  47474. var spaceLeft = this.style.wordWrapWidth;
  47475. var words = lines[i].split(' ');
  47476. for (var j = 0; j < words.length; j++)
  47477. {
  47478. var wordWidth = this.context.measureText(words[j]).width;
  47479. var wordWidthWithSpace = wordWidth + this.context.measureText(' ').width;
  47480. if (wordWidthWithSpace > spaceLeft)
  47481. {
  47482. // Skip printing the newline if it's the first word of the line that is greater than the word wrap width.
  47483. if (j > 0)
  47484. {
  47485. result += '\n';
  47486. }
  47487. result += words[j] + ' ';
  47488. spaceLeft = this.style.wordWrapWidth - wordWidth;
  47489. }
  47490. else
  47491. {
  47492. spaceLeft -= wordWidthWithSpace;
  47493. result += words[j] + ' ';
  47494. }
  47495. }
  47496. if (i < lines.length-1)
  47497. {
  47498. result += '\n';
  47499. }
  47500. }
  47501. return result;
  47502. };
  47503. /**
  47504. * Updates the internal `style.font` if it now differs according to generation from components.
  47505. *
  47506. * @method Phaser.Text#updateFont
  47507. * @private
  47508. * @param {object} components - Font components.
  47509. */
  47510. Phaser.Text.prototype.updateFont = function (components) {
  47511. var font = this.componentsToFont(components);
  47512. if (this.style.font !== font)
  47513. {
  47514. this.style.font = font;
  47515. this.dirty = true;
  47516. if (this.parent)
  47517. {
  47518. this.updateTransform();
  47519. }
  47520. }
  47521. };
  47522. /**
  47523. * Converting a short CSS-font string into the relevant components.
  47524. *
  47525. * @method Phaser.Text#fontToComponents
  47526. * @private
  47527. * @param {string} font - a CSS font string
  47528. */
  47529. Phaser.Text.prototype.fontToComponents = function (font) {
  47530. // The format is specified in http://www.w3.org/TR/CSS2/fonts.html#font-shorthand:
  47531. // style - normal | italic | oblique | inherit
  47532. // variant - normal | small-caps | inherit
  47533. // weight - normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
  47534. // size - xx-small | x-small | small | medium | large | x-large | xx-large,
  47535. // larger | smaller
  47536. // {number} (em | ex | ch | rem | vh | vw | vmin | vmax | px | mm | cm | in | pt | pc | %)
  47537. // font-family - rest (but identifiers or quoted with comma separation)
  47538. var m = font.match(/^\s*(?:\b(normal|italic|oblique|inherit)?\b)\s*(?:\b(normal|small-caps|inherit)?\b)\s*(?:\b(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit)?\b)\s*(?:\b(xx-small|x-small|small|medium|large|x-large|xx-large|larger|smaller|0|\d*(?:[.]\d*)?(?:%|[a-z]{2,5}))?\b)\s*(.*)\s*$/);
  47539. if (m)
  47540. {
  47541. var family = m[5].trim();
  47542. // If it looks like the value should be quoted, but isn't, then quote it.
  47543. if (!/^(?:inherit|serif|sans-serif|cursive|fantasy|monospace)$/.exec(family) && !/['",]/.exec(family))
  47544. {
  47545. family = "'" + family + "'";
  47546. }
  47547. return {
  47548. font: font,
  47549. fontStyle: m[1] || 'normal',
  47550. fontVariant: m[2] || 'normal',
  47551. fontWeight: m[3] || 'normal',
  47552. fontSize: m[4] || 'medium',
  47553. fontFamily: family
  47554. };
  47555. }
  47556. else
  47557. {
  47558. console.warn("Phaser.Text - unparsable CSS font: " + font);
  47559. return {
  47560. font: font
  47561. };
  47562. }
  47563. };
  47564. /**
  47565. * Converts individual font components (see `fontToComponents`) to a short CSS font string.
  47566. *
  47567. * @method Phaser.Text#componentsToFont
  47568. * @private
  47569. * @param {object} components - Font components.
  47570. */
  47571. Phaser.Text.prototype.componentsToFont = function (components) {
  47572. var parts = [];
  47573. var v;
  47574. v = components.fontStyle;
  47575. if (v && v !== 'normal') { parts.push(v); }
  47576. v = components.fontVariant;
  47577. if (v && v !== 'normal') { parts.push(v); }
  47578. v = components.fontWeight;
  47579. if (v && v !== 'normal') { parts.push(v); }
  47580. v = components.fontSize;
  47581. if (v && v !== 'medium') { parts.push(v); }
  47582. v = components.fontFamily;
  47583. if (v) { parts.push(v); }
  47584. if (!parts.length)
  47585. {
  47586. // Fallback to whatever value the 'font' was
  47587. parts.push(components.font);
  47588. }
  47589. return parts.join(" ");
  47590. };
  47591. /**
  47592. * The text to be displayed by this Text object.
  47593. * Use a \n to insert a carriage return and split the text.
  47594. * The text will be rendered with any style currently set.
  47595. *
  47596. * Use the optional `immediate` argument if you need the Text display to update immediately.
  47597. *
  47598. * If not it will re-create the texture of this Text object during the next time the render
  47599. * loop is called.
  47600. *
  47601. * @method Phaser.Text#setText
  47602. * @param {string} [text] - The text to be displayed. Set to an empty string to clear text that is already present.
  47603. * @param {boolean} [immediate=false] - Update the texture used by this Text object immediately (true) or automatically during the next render loop (false).
  47604. * @return {Phaser.Text} This Text instance.
  47605. */
  47606. Phaser.Text.prototype.setText = function (text, immediate) {
  47607. if (immediate === undefined) { immediate = false; }
  47608. this.text = text.toString() || '';
  47609. if (immediate)
  47610. {
  47611. this.updateText();
  47612. }
  47613. else
  47614. {
  47615. this.dirty = true;
  47616. }
  47617. return this;
  47618. };
  47619. /**
  47620. * Converts the given array into a tab delimited string and then updates this Text object.
  47621. * This is mostly used when you want to display external data using tab stops.
  47622. *
  47623. * The array can be either single or multi dimensional depending on the result you need:
  47624. *
  47625. * `[ 'a', 'b', 'c' ]` would convert in to `"a\tb\tc"`.
  47626. *
  47627. * Where as:
  47628. *
  47629. * `[
  47630. * [ 'a', 'b', 'c' ],
  47631. * [ 'd', 'e', 'f']
  47632. * ]`
  47633. *
  47634. * would convert in to: `"a\tb\tc\nd\te\tf"`
  47635. *
  47636. * @method Phaser.Text#parseList
  47637. * @param {array} list - The array of data to convert into a string.
  47638. * @return {Phaser.Text} This Text instance.
  47639. */
  47640. Phaser.Text.prototype.parseList = function (list) {
  47641. if (!Array.isArray(list))
  47642. {
  47643. return this;
  47644. }
  47645. else
  47646. {
  47647. var s = "";
  47648. for (var i = 0; i < list.length; i++)
  47649. {
  47650. if (Array.isArray(list[i]))
  47651. {
  47652. s += list[i].join("\t");
  47653. if (i < list.length - 1)
  47654. {
  47655. s += "\n";
  47656. }
  47657. }
  47658. else
  47659. {
  47660. s += list[i];
  47661. if (i < list.length - 1)
  47662. {
  47663. s += "\t";
  47664. }
  47665. }
  47666. }
  47667. }
  47668. this.text = s;
  47669. this.dirty = true;
  47670. return this;
  47671. };
  47672. /**
  47673. * The Text Bounds is a rectangular region that you control the dimensions of into which the Text object itself is positioned,
  47674. * regardless of the number of lines in the text, the font size or any other attribute.
  47675. *
  47676. * Alignment is controlled via the properties `boundsAlignH` and `boundsAlignV` within the Text.style object, or can be directly
  47677. * set through the setters `Text.boundsAlignH` and `Text.boundsAlignV`. Bounds alignment is independent of text alignment.
  47678. *
  47679. * For example: If your game is 800x600 in size and you set the text bounds to be 0,0,800,600 then by setting boundsAlignH to
  47680. * 'center' and boundsAlignV to 'bottom' the text will render in the center and at the bottom of your game window, regardless of
  47681. * how many lines of text there may be. Even if you adjust the text content or change the style it will remain at the bottom center
  47682. * of the text bounds.
  47683. *
  47684. * This is especially powerful when you need to align text against specific coordinates in your game, but the actual text dimensions
  47685. * may vary based on font (say for multi-lingual games).
  47686. *
  47687. * If `Text.wordWrapWidth` is greater than the width of the text bounds it is clamped to match the bounds width.
  47688. *
  47689. * Call this method with no arguments given to reset an existing textBounds.
  47690. *
  47691. * It works by calculating the final position based on the Text.canvas size, which is modified as the text is updated. Some fonts
  47692. * have additional padding around them which you can mitigate by tweaking the Text.padding property. It then adjusts the `pivot`
  47693. * property based on the given bounds and canvas size. This means if you need to set the pivot property directly in your game then
  47694. * you either cannot use `setTextBounds` or you must place the Text object inside another DisplayObject on which you set the pivot.
  47695. *
  47696. * @method Phaser.Text#setTextBounds
  47697. * @param {number} [x] - The x coordinate of the Text Bounds region.
  47698. * @param {number} [y] - The y coordinate of the Text Bounds region.
  47699. * @param {number} [width] - The width of the Text Bounds region.
  47700. * @param {number} [height] - The height of the Text Bounds region.
  47701. * @return {Phaser.Text} This Text instance.
  47702. */
  47703. Phaser.Text.prototype.setTextBounds = function (x, y, width, height) {
  47704. if (x === undefined)
  47705. {
  47706. this.textBounds = null;
  47707. }
  47708. else
  47709. {
  47710. if (!this.textBounds)
  47711. {
  47712. this.textBounds = new Phaser.Rectangle(x, y, width, height);
  47713. }
  47714. else
  47715. {
  47716. this.textBounds.setTo(x, y, width, height);
  47717. }
  47718. if (this.style.wordWrapWidth > width)
  47719. {
  47720. this.style.wordWrapWidth = width;
  47721. }
  47722. }
  47723. this.updateTexture();
  47724. return this;
  47725. };
  47726. /**
  47727. * Updates the texture based on the canvas dimensions.
  47728. *
  47729. * @method Phaser.Text#updateTexture
  47730. * @private
  47731. */
  47732. Phaser.Text.prototype.updateTexture = function () {
  47733. var base = this.texture.baseTexture;
  47734. var crop = this.texture.crop;
  47735. var frame = this.texture.frame;
  47736. var w = this.canvas.width;
  47737. var h = this.canvas.height;
  47738. base.width = w;
  47739. base.height = h;
  47740. crop.width = w;
  47741. crop.height = h;
  47742. frame.width = w;
  47743. frame.height = h;
  47744. this.texture.width = w;
  47745. this.texture.height = h;
  47746. this._width = w;
  47747. this._height = h;
  47748. if (this.textBounds)
  47749. {
  47750. var x = this.textBounds.x;
  47751. var y = this.textBounds.y;
  47752. // Align the canvas based on the bounds
  47753. if (this.style.boundsAlignH === 'right')
  47754. {
  47755. x += this.textBounds.width - this.canvas.width / this.resolution;
  47756. }
  47757. else if (this.style.boundsAlignH === 'center')
  47758. {
  47759. x += this.textBounds.halfWidth - (this.canvas.width / this.resolution / 2);
  47760. }
  47761. if (this.style.boundsAlignV === 'bottom')
  47762. {
  47763. y += this.textBounds.height - this.canvas.height / this.resolution;
  47764. }
  47765. else if (this.style.boundsAlignV === 'middle')
  47766. {
  47767. y += this.textBounds.halfHeight - (this.canvas.height / this.resolution / 2);
  47768. }
  47769. this.pivot.x = -x;
  47770. this.pivot.y = -y;
  47771. }
  47772. // Can't render something with a zero sized dimension
  47773. this.renderable = (w !== 0 && h !== 0);
  47774. this.texture.requiresReTint = true;
  47775. this.texture.baseTexture.dirty();
  47776. };
  47777. /**
  47778. * Renders the object using the WebGL renderer
  47779. *
  47780. * @method Phaser.Text#_renderWebGL
  47781. * @private
  47782. * @param {RenderSession} renderSession - The Render Session to render the Text on.
  47783. */
  47784. Phaser.Text.prototype._renderWebGL = function (renderSession) {
  47785. if (this.dirty)
  47786. {
  47787. this.updateText();
  47788. this.dirty = false;
  47789. }
  47790. PIXI.Sprite.prototype._renderWebGL.call(this, renderSession);
  47791. };
  47792. /**
  47793. * Renders the object using the Canvas renderer.
  47794. *
  47795. * @method Phaser.Text#_renderCanvas
  47796. * @private
  47797. * @param {RenderSession} renderSession - The Render Session to render the Text on.
  47798. */
  47799. Phaser.Text.prototype._renderCanvas = function (renderSession) {
  47800. if (this.dirty)
  47801. {
  47802. this.updateText();
  47803. this.dirty = false;
  47804. }
  47805. PIXI.Sprite.prototype._renderCanvas.call(this, renderSession);
  47806. };
  47807. /**
  47808. * Calculates the ascent, descent and fontSize of a given font style.
  47809. *
  47810. * @method Phaser.Text#determineFontProperties
  47811. * @private
  47812. * @param {object} fontStyle
  47813. */
  47814. Phaser.Text.prototype.determineFontProperties = function (fontStyle) {
  47815. var properties = Phaser.Text.fontPropertiesCache[fontStyle];
  47816. if (!properties)
  47817. {
  47818. properties = {};
  47819. var canvas = Phaser.Text.fontPropertiesCanvas;
  47820. var context = Phaser.Text.fontPropertiesContext;
  47821. context.font = fontStyle;
  47822. var width = Math.ceil(context.measureText('|MÉq').width);
  47823. var baseline = Math.ceil(context.measureText('|MÉq').width);
  47824. var height = 2 * baseline;
  47825. baseline = baseline * 1.4 | 0;
  47826. canvas.width = width;
  47827. canvas.height = height;
  47828. context.fillStyle = '#f00';
  47829. context.fillRect(0, 0, width, height);
  47830. context.font = fontStyle;
  47831. context.textBaseline = 'alphabetic';
  47832. context.fillStyle = '#000';
  47833. context.fillText('|MÉq', 0, baseline);
  47834. if (!context.getImageData(0, 0, width, height))
  47835. {
  47836. properties.ascent = baseline;
  47837. properties.descent = baseline + 6;
  47838. properties.fontSize = properties.ascent + properties.descent;
  47839. Phaser.Text.fontPropertiesCache[fontStyle] = properties;
  47840. return properties;
  47841. }
  47842. var imagedata = context.getImageData(0, 0, width, height).data;
  47843. var pixels = imagedata.length;
  47844. var line = width * 4;
  47845. var i, j;
  47846. var idx = 0;
  47847. var stop = false;
  47848. // ascent. scan from top to bottom until we find a non red pixel
  47849. for (i = 0; i < baseline; i++)
  47850. {
  47851. for (j = 0; j < line; j += 4)
  47852. {
  47853. if (imagedata[idx + j] !== 255)
  47854. {
  47855. stop = true;
  47856. break;
  47857. }
  47858. }
  47859. if (!stop)
  47860. {
  47861. idx += line;
  47862. }
  47863. else
  47864. {
  47865. break;
  47866. }
  47867. }
  47868. properties.ascent = baseline - i;
  47869. idx = pixels - line;
  47870. stop = false;
  47871. // descent. scan from bottom to top until we find a non red pixel
  47872. for (i = height; i > baseline; i--)
  47873. {
  47874. for (j = 0; j < line; j += 4)
  47875. {
  47876. if (imagedata[idx + j] !== 255)
  47877. {
  47878. stop = true;
  47879. break;
  47880. }
  47881. }
  47882. if (!stop)
  47883. {
  47884. idx -= line;
  47885. }
  47886. else
  47887. {
  47888. break;
  47889. }
  47890. }
  47891. properties.descent = i - baseline;
  47892. //TODO might need a tweak. kind of a temp fix!
  47893. properties.descent += 6;
  47894. properties.fontSize = properties.ascent + properties.descent;
  47895. Phaser.Text.fontPropertiesCache[fontStyle] = properties;
  47896. }
  47897. return properties;
  47898. };
  47899. /**
  47900. * Returns the bounds of the Text as a rectangle.
  47901. * The bounds calculation takes the worldTransform into account.
  47902. *
  47903. * @method Phaser.Text#getBounds
  47904. * @param {Phaser.Matrix} matrix - The transformation matrix of the Text.
  47905. * @return {Phaser.Rectangle} The framing rectangle
  47906. */
  47907. Phaser.Text.prototype.getBounds = function (matrix) {
  47908. if (this.dirty)
  47909. {
  47910. this.updateText();
  47911. this.dirty = false;
  47912. }
  47913. return PIXI.Sprite.prototype.getBounds.call(this, matrix);
  47914. };
  47915. /**
  47916. * Sets the character limit of the text, with a suffix.
  47917. * If the text is longer than this limit, it is truncated and the suffix is appended.
  47918. *
  47919. * @method Phaser.Text#setCharacterLimit
  47920. * @param {number} [characterLimit] - The x coordinate of the Text Bounds region.
  47921. * @param {string} [suffix] - The suffix to append to the truncated text.
  47922. */
  47923. Phaser.Text.prototype.setCharacterLimit = function (characterLimit, suffix) {
  47924. this.characterLimitSuffix = (suffix === undefined) ? '' : suffix;
  47925. this.characterLimitSize = characterLimit;
  47926. this.updateText();
  47927. };
  47928. /**
  47929. * The text to be displayed by this Text object.
  47930. * Use a \n to insert a carriage return and split the text.
  47931. * The text will be rendered with any style currently set.
  47932. *
  47933. * @name Phaser.Text#text
  47934. * @property {string} text
  47935. */
  47936. Object.defineProperty(Phaser.Text.prototype, 'text', {
  47937. get: function() {
  47938. return this._text;
  47939. },
  47940. set: function(value) {
  47941. if (value !== this._text)
  47942. {
  47943. this._text = value.toString() || '';
  47944. this.dirty = true;
  47945. if (this.parent)
  47946. {
  47947. this.updateTransform();
  47948. }
  47949. }
  47950. }
  47951. });
  47952. /**
  47953. * Change the font used.
  47954. *
  47955. * This is equivalent of the `font` property specified to {@link Phaser.Text#setStyle setStyle}, except
  47956. * that unlike using `setStyle` this will not change any current font fill/color settings.
  47957. *
  47958. * The CSS font string can also be individually altered with the `font`, `fontSize`, `fontWeight`, `fontStyle`, and `fontVariant` properties.
  47959. *
  47960. * @name Phaser.Text#cssFont
  47961. * @property {string} cssFont
  47962. */
  47963. Object.defineProperty(Phaser.Text.prototype, 'cssFont', {
  47964. get: function() {
  47965. return this.componentsToFont(this._fontComponents);
  47966. },
  47967. set: function (value)
  47968. {
  47969. value = value || 'bold 20pt Arial';
  47970. this._fontComponents = this.fontToComponents(value);
  47971. this.updateFont(this._fontComponents);
  47972. }
  47973. });
  47974. /**
  47975. * Change the font family that the text will be rendered in, such as 'Arial'.
  47976. *
  47977. * Multiple CSS font families and generic fallbacks can be specified as long as
  47978. * {@link http://www.w3.org/TR/CSS2/fonts.html#propdef-font-family CSS font-family rules} are followed.
  47979. *
  47980. * To change the entire font string use {@link Phaser.Text#cssFont cssFont} instead: eg. `text.cssFont = 'bold 20pt Arial'`.
  47981. *
  47982. * @name Phaser.Text#font
  47983. * @property {string} font
  47984. */
  47985. Object.defineProperty(Phaser.Text.prototype, 'font', {
  47986. get: function() {
  47987. return this._fontComponents.fontFamily;
  47988. },
  47989. set: function(value) {
  47990. value = value || 'Arial';
  47991. value = value.trim();
  47992. // If it looks like the value should be quoted, but isn't, then quote it.
  47993. if (!/^(?:inherit|serif|sans-serif|cursive|fantasy|monospace)$/.exec(value) && !/['",]/.exec(value))
  47994. {
  47995. value = "'" + value + "'";
  47996. }
  47997. this._fontComponents.fontFamily = value;
  47998. this.updateFont(this._fontComponents);
  47999. }
  48000. });
  48001. /**
  48002. * The size of the font.
  48003. *
  48004. * If the font size is specified in pixels (eg. `32` or `'32px`') then a number (ie. `32`) representing
  48005. * the font size in pixels is returned; otherwise the value with CSS unit is returned as a string (eg. `'12pt'`).
  48006. *
  48007. * @name Phaser.Text#fontSize
  48008. * @property {number|string} fontSize
  48009. */
  48010. Object.defineProperty(Phaser.Text.prototype, 'fontSize', {
  48011. get: function() {
  48012. var size = this._fontComponents.fontSize;
  48013. if (size && /(?:^0$|px$)/.exec(size))
  48014. {
  48015. return parseInt(size, 10);
  48016. }
  48017. else
  48018. {
  48019. return size;
  48020. }
  48021. },
  48022. set: function(value) {
  48023. value = value || '0';
  48024. if (typeof value === 'number')
  48025. {
  48026. value = value + 'px';
  48027. }
  48028. this._fontComponents.fontSize = value;
  48029. this.updateFont(this._fontComponents);
  48030. }
  48031. });
  48032. /**
  48033. * The weight of the font: 'normal', 'bold', or {@link http://www.w3.org/TR/CSS2/fonts.html#propdef-font-weight a valid CSS font weight}.
  48034. * @name Phaser.Text#fontWeight
  48035. * @property {string} fontWeight
  48036. */
  48037. Object.defineProperty(Phaser.Text.prototype, 'fontWeight', {
  48038. get: function() {
  48039. return this._fontComponents.fontWeight || 'normal';
  48040. },
  48041. set: function(value) {
  48042. value = value || 'normal';
  48043. this._fontComponents.fontWeight = value;
  48044. this.updateFont(this._fontComponents);
  48045. }
  48046. });
  48047. /**
  48048. * The style of the font: 'normal', 'italic', 'oblique'
  48049. * @name Phaser.Text#fontStyle
  48050. * @property {string} fontStyle
  48051. */
  48052. Object.defineProperty(Phaser.Text.prototype, 'fontStyle', {
  48053. get: function() {
  48054. return this._fontComponents.fontStyle || 'normal';
  48055. },
  48056. set: function(value) {
  48057. value = value || 'normal';
  48058. this._fontComponents.fontStyle = value;
  48059. this.updateFont(this._fontComponents);
  48060. }
  48061. });
  48062. /**
  48063. * The variant the font: 'normal', 'small-caps'
  48064. * @name Phaser.Text#fontVariant
  48065. * @property {string} fontVariant
  48066. */
  48067. Object.defineProperty(Phaser.Text.prototype, 'fontVariant', {
  48068. get: function() {
  48069. return this._fontComponents.fontVariant || 'normal';
  48070. },
  48071. set: function(value) {
  48072. value = value || 'normal';
  48073. this._fontComponents.fontVariant = value;
  48074. this.updateFont(this._fontComponents);
  48075. }
  48076. });
  48077. /**
  48078. * @name Phaser.Text#fill
  48079. * @property {object} fill - A canvas fillstyle that will be used on the text eg 'red', '#00FF00'.
  48080. */
  48081. Object.defineProperty(Phaser.Text.prototype, 'fill', {
  48082. get: function() {
  48083. return this.style.fill;
  48084. },
  48085. set: function(value) {
  48086. if (value !== this.style.fill)
  48087. {
  48088. this.style.fill = value;
  48089. this.dirty = true;
  48090. }
  48091. }
  48092. });
  48093. /**
  48094. * Controls the horizontal alignment for multiline text.
  48095. * Can be: 'left', 'center' or 'right'.
  48096. * Does not affect single lines of text. For that please see `setTextBounds`.
  48097. * @name Phaser.Text#align
  48098. * @property {string} align
  48099. */
  48100. Object.defineProperty(Phaser.Text.prototype, 'align', {
  48101. get: function() {
  48102. return this.style.align;
  48103. },
  48104. set: function(value) {
  48105. value = value.toLowerCase();
  48106. if (value !== this.style.align)
  48107. {
  48108. this.style.align = value;
  48109. this.dirty = true;
  48110. }
  48111. }
  48112. });
  48113. /**
  48114. * The resolution of the canvas the text is rendered to.
  48115. * This defaults to match the resolution of the renderer, but can be changed on a per Text object basis.
  48116. * @name Phaser.Text#resolution
  48117. * @property {integer} resolution
  48118. */
  48119. Object.defineProperty(Phaser.Text.prototype, 'resolution', {
  48120. get: function() {
  48121. return this._res;
  48122. },
  48123. set: function(value) {
  48124. if (value !== this._res)
  48125. {
  48126. this._res = value;
  48127. this.dirty = true;
  48128. }
  48129. }
  48130. });
  48131. /**
  48132. * The size (in pixels) of the tabs, for when text includes tab characters. 0 disables.
  48133. * Can be an integer or an array of varying tab sizes, one tab per element.
  48134. * For example if you set tabs to 100 then when Text encounters a tab it will jump ahead 100 pixels.
  48135. * If you set tabs to be `[100,200]` then it will set the first tab at 100px and the second at 200px.
  48136. *
  48137. * @name Phaser.Text#tabs
  48138. * @property {integer|array} tabs
  48139. */
  48140. Object.defineProperty(Phaser.Text.prototype, 'tabs', {
  48141. get: function() {
  48142. return this.style.tabs;
  48143. },
  48144. set: function(value) {
  48145. if (value !== this.style.tabs)
  48146. {
  48147. this.style.tabs = value;
  48148. this.dirty = true;
  48149. }
  48150. }
  48151. });
  48152. /**
  48153. * Horizontal alignment of the text within the `textBounds`. Can be: 'left', 'center' or 'right'.
  48154. * @name Phaser.Text#boundsAlignH
  48155. * @property {string} boundsAlignH
  48156. */
  48157. Object.defineProperty(Phaser.Text.prototype, 'boundsAlignH', {
  48158. get: function() {
  48159. return this.style.boundsAlignH;
  48160. },
  48161. set: function(value) {
  48162. value = value.toLowerCase();
  48163. if (value !== this.style.boundsAlignH)
  48164. {
  48165. this.style.boundsAlignH = value;
  48166. this.dirty = true;
  48167. }
  48168. }
  48169. });
  48170. /**
  48171. * Vertical alignment of the text within the `textBounds`. Can be: 'top', 'middle' or 'bottom'.
  48172. * @name Phaser.Text#boundsAlignV
  48173. * @property {string} boundsAlignV
  48174. */
  48175. Object.defineProperty(Phaser.Text.prototype, 'boundsAlignV', {
  48176. get: function() {
  48177. return this.style.boundsAlignV;
  48178. },
  48179. set: function(value) {
  48180. value = value.toLowerCase();
  48181. if (value !== this.style.boundsAlignV)
  48182. {
  48183. this.style.boundsAlignV = value;
  48184. this.dirty = true;
  48185. }
  48186. }
  48187. });
  48188. /**
  48189. * @name Phaser.Text#stroke
  48190. * @property {string} stroke - A canvas fillstyle that will be used on the text stroke eg 'blue', '#FCFF00'.
  48191. */
  48192. Object.defineProperty(Phaser.Text.prototype, 'stroke', {
  48193. get: function() {
  48194. return this.style.stroke;
  48195. },
  48196. set: function(value) {
  48197. if (value !== this.style.stroke)
  48198. {
  48199. this.style.stroke = value;
  48200. this.dirty = true;
  48201. }
  48202. }
  48203. });
  48204. /**
  48205. * @name Phaser.Text#strokeThickness
  48206. * @property {number} strokeThickness - A number that represents the thickness of the stroke. Default is 0 (no stroke)
  48207. */
  48208. Object.defineProperty(Phaser.Text.prototype, 'strokeThickness', {
  48209. get: function() {
  48210. return this.style.strokeThickness;
  48211. },
  48212. set: function(value) {
  48213. if (value !== this.style.strokeThickness)
  48214. {
  48215. this.style.strokeThickness = Number(value);
  48216. this.dirty = true;
  48217. }
  48218. }
  48219. });
  48220. /**
  48221. * @name Phaser.Text#wordWrap
  48222. * @property {boolean} wordWrap - Indicates if word wrap should be used.
  48223. */
  48224. Object.defineProperty(Phaser.Text.prototype, 'wordWrap', {
  48225. get: function() {
  48226. return this.style.wordWrap;
  48227. },
  48228. set: function(value) {
  48229. if (value !== this.style.wordWrap)
  48230. {
  48231. this.style.wordWrap = value;
  48232. this.dirty = true;
  48233. }
  48234. }
  48235. });
  48236. /**
  48237. * @name Phaser.Text#wordWrapWidth
  48238. * @property {number} wordWrapWidth - The width at which text will wrap.
  48239. */
  48240. Object.defineProperty(Phaser.Text.prototype, 'wordWrapWidth', {
  48241. get: function() {
  48242. return this.style.wordWrapWidth;
  48243. },
  48244. set: function(value) {
  48245. if (value !== this.style.wordWrapWidth)
  48246. {
  48247. this.style.wordWrapWidth = value;
  48248. this.dirty = true;
  48249. }
  48250. }
  48251. });
  48252. /**
  48253. * @name Phaser.Text#lineSpacing
  48254. * @property {number} lineSpacing - Additional spacing (in pixels) between each line of text if multi-line.
  48255. */
  48256. Object.defineProperty(Phaser.Text.prototype, 'lineSpacing', {
  48257. get: function() {
  48258. return this._lineSpacing;
  48259. },
  48260. set: function(value) {
  48261. if (value !== this._lineSpacing)
  48262. {
  48263. this._lineSpacing = parseFloat(value);
  48264. this.dirty = true;
  48265. if (this.parent)
  48266. {
  48267. this.updateTransform();
  48268. }
  48269. }
  48270. }
  48271. });
  48272. /**
  48273. * @name Phaser.Text#shadowOffsetX
  48274. * @property {number} shadowOffsetX - The shadowOffsetX value in pixels. This is how far offset horizontally the shadow effect will be.
  48275. */
  48276. Object.defineProperty(Phaser.Text.prototype, 'shadowOffsetX', {
  48277. get: function() {
  48278. return this.style.shadowOffsetX;
  48279. },
  48280. set: function(value) {
  48281. if (value !== this.style.shadowOffsetX)
  48282. {
  48283. this.style.shadowOffsetX = value;
  48284. this.dirty = true;
  48285. }
  48286. }
  48287. });
  48288. /**
  48289. * @name Phaser.Text#shadowOffsetY
  48290. * @property {number} shadowOffsetY - The shadowOffsetY value in pixels. This is how far offset vertically the shadow effect will be.
  48291. */
  48292. Object.defineProperty(Phaser.Text.prototype, 'shadowOffsetY', {
  48293. get: function() {
  48294. return this.style.shadowOffsetY;
  48295. },
  48296. set: function(value) {
  48297. if (value !== this.style.shadowOffsetY)
  48298. {
  48299. this.style.shadowOffsetY = value;
  48300. this.dirty = true;
  48301. }
  48302. }
  48303. });
  48304. /**
  48305. * @name Phaser.Text#shadowColor
  48306. * @property {string} shadowColor - The color of the shadow, as given in CSS rgba format. Set the alpha component to 0 to disable the shadow.
  48307. */
  48308. Object.defineProperty(Phaser.Text.prototype, 'shadowColor', {
  48309. get: function() {
  48310. return this.style.shadowColor;
  48311. },
  48312. set: function(value) {
  48313. if (value !== this.style.shadowColor)
  48314. {
  48315. this.style.shadowColor = value;
  48316. this.dirty = true;
  48317. }
  48318. }
  48319. });
  48320. /**
  48321. * @name Phaser.Text#shadowBlur
  48322. * @property {number} shadowBlur - The shadowBlur value. Make the shadow softer by applying a Gaussian blur to it. A number from 0 (no blur) up to approx. 10 (depending on scene).
  48323. */
  48324. Object.defineProperty(Phaser.Text.prototype, 'shadowBlur', {
  48325. get: function() {
  48326. return this.style.shadowBlur;
  48327. },
  48328. set: function(value) {
  48329. if (value !== this.style.shadowBlur)
  48330. {
  48331. this.style.shadowBlur = value;
  48332. this.dirty = true;
  48333. }
  48334. }
  48335. });
  48336. /**
  48337. * @name Phaser.Text#shadowStroke
  48338. * @property {boolean} shadowStroke - Sets if the drop shadow is applied to the Text stroke.
  48339. */
  48340. Object.defineProperty(Phaser.Text.prototype, 'shadowStroke', {
  48341. get: function() {
  48342. return this.style.shadowStroke;
  48343. },
  48344. set: function(value) {
  48345. if (value !== this.style.shadowStroke)
  48346. {
  48347. this.style.shadowStroke = value;
  48348. this.dirty = true;
  48349. }
  48350. }
  48351. });
  48352. /**
  48353. * @name Phaser.Text#shadowFill
  48354. * @property {boolean} shadowFill - Sets if the drop shadow is applied to the Text fill.
  48355. */
  48356. Object.defineProperty(Phaser.Text.prototype, 'shadowFill', {
  48357. get: function() {
  48358. return this.style.shadowFill;
  48359. },
  48360. set: function(value) {
  48361. if (value !== this.style.shadowFill)
  48362. {
  48363. this.style.shadowFill = value;
  48364. this.dirty = true;
  48365. }
  48366. }
  48367. });
  48368. /**
  48369. * The width of the Text object in pixels. This is width of the Texture frame / the Text.resolution.
  48370. * @name Phaser.Text#width
  48371. * @property {number} width - The width of the Text. Setting this will modify the scale to achieve the value requested.
  48372. */
  48373. Object.defineProperty(Phaser.Text.prototype, 'width', {
  48374. get: function() {
  48375. if (this.dirty)
  48376. {
  48377. this.updateText();
  48378. this.dirty = false;
  48379. }
  48380. return this.scale.x * (this.texture.frame.width / this.resolution);
  48381. },
  48382. set: function(value) {
  48383. this.scale.x = value / this.texture.frame.width;
  48384. this._width = value;
  48385. }
  48386. });
  48387. /**
  48388. * The height of the Text object in pixels. This is height of the Texture frame / the Text.resolution.
  48389. * @name Phaser.Text#height
  48390. * @property {number} height - The height of the Text. Setting this will modify the scale to achieve the value requested.
  48391. */
  48392. Object.defineProperty(Phaser.Text.prototype, 'height', {
  48393. get: function() {
  48394. if (this.dirty)
  48395. {
  48396. this.updateText();
  48397. this.dirty = false;
  48398. }
  48399. return this.scale.y * (this.texture.frame.height / this.resolution);
  48400. },
  48401. set: function(value) {
  48402. this.scale.y = value / this.texture.frame.height;
  48403. this._height = value;
  48404. }
  48405. });
  48406. Phaser.Text.fontPropertiesCache = {};
  48407. Phaser.Text.fontPropertiesCanvas = document.createElement('canvas');
  48408. Phaser.Text.fontPropertiesContext = Phaser.Text.fontPropertiesCanvas.getContext('2d');
  48409. /**
  48410. * @author Richard Davey <rich@photonstorm.com>
  48411. * @copyright 2016 Photon Storm Ltd.
  48412. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  48413. */
  48414. /**
  48415. * BitmapText objects work by taking a texture file and an XML or JSON file that describes the font structure.
  48416. * It then generates a new Sprite object for each letter of the text, proportionally spaced out and aligned to
  48417. * match the font structure.
  48418. *
  48419. * BitmapText objects are less flexible than Text objects, in that they have less features such as shadows, fills and the ability
  48420. * to use Web Fonts, however you trade this flexibility for rendering speed. You can also create visually compelling BitmapTexts by
  48421. * processing the font texture in an image editor, applying fills and any other effects required.
  48422. *
  48423. * To create multi-line text insert \r, \n or \r\n escape codes into the text string.
  48424. *
  48425. * If you are having performance issues due to the volume of sprites being rendered, and do not require the text to be constantly
  48426. * updating, you can use BitmapText.generateTexture to create a static texture from this BitmapText.
  48427. *
  48428. * To create a BitmapText data files you can use:
  48429. *
  48430. * BMFont (Windows, free): http://www.angelcode.com/products/bmfont/
  48431. * Glyph Designer (OS X, commercial): http://www.71squared.com/en/glyphdesigner
  48432. * Littera (Web-based, free): http://kvazars.com/littera/
  48433. *
  48434. * For most use cases it is recommended to use XML. If you wish to use JSON, the formatting should be equal to the result of
  48435. * converting a valid XML file through the popular X2JS library. An online tool for conversion can be found here: http://codebeautify.org/xmltojson
  48436. *
  48437. * If you were using an older version of Phaser (< 2.4) and using the DOMish parser hack, please remove this. It isn't required any longer.
  48438. *
  48439. * @class Phaser.BitmapText
  48440. * @constructor
  48441. * @extends PIXI.DisplayObjectContainer
  48442. * @extends Phaser.Component.Core
  48443. * @extends Phaser.Component.Angle
  48444. * @extends Phaser.Component.AutoCull
  48445. * @extends Phaser.Component.Bounds
  48446. * @extends Phaser.Component.Destroy
  48447. * @extends Phaser.Component.FixedToCamera
  48448. * @extends Phaser.Component.InputEnabled
  48449. * @extends Phaser.Component.InWorld
  48450. * @extends Phaser.Component.LifeSpan
  48451. * @extends Phaser.Component.PhysicsBody
  48452. * @extends Phaser.Component.Reset
  48453. * @param {Phaser.Game} game - A reference to the currently running game.
  48454. * @param {number} x - X coordinate to display the BitmapText object at.
  48455. * @param {number} y - Y coordinate to display the BitmapText object at.
  48456. * @param {string} font - The key of the BitmapText as stored in Phaser.Cache.
  48457. * @param {string} [text=''] - The text that will be rendered. This can also be set later via BitmapText.text.
  48458. * @param {number} [size=32] - The size the font will be rendered at in pixels.
  48459. * @param {string} [align='left'] - The alignment of multi-line text. Has no effect if there is only one line of text.
  48460. */
  48461. Phaser.BitmapText = function (game, x, y, font, text, size, align) {
  48462. x = x || 0;
  48463. y = y || 0;
  48464. font = font || '';
  48465. text = text || '';
  48466. size = size || 32;
  48467. align = align || 'left';
  48468. PIXI.DisplayObjectContainer.call(this);
  48469. /**
  48470. * @property {number} type - The const type of this object.
  48471. * @readonly
  48472. */
  48473. this.type = Phaser.BITMAPTEXT;
  48474. /**
  48475. * @property {number} physicsType - The const physics body type of this object.
  48476. * @readonly
  48477. */
  48478. this.physicsType = Phaser.SPRITE;
  48479. /**
  48480. * @property {number} textWidth - The width in pixels of the overall text area, taking into consideration multi-line text.
  48481. * @readOnly
  48482. */
  48483. this.textWidth = 0;
  48484. /**
  48485. * @property {number} textHeight - The height in pixels of the overall text area, taking into consideration multi-line text.
  48486. * @readOnly
  48487. */
  48488. this.textHeight = 0;
  48489. /**
  48490. * @property {Phaser.Point} anchor - The anchor value of this BitmapText.
  48491. */
  48492. this.anchor = new Phaser.Point();
  48493. /**
  48494. * @property {Phaser.Point} _prevAnchor - The previous anchor value.
  48495. * @private
  48496. */
  48497. this._prevAnchor = new Phaser.Point();
  48498. /**
  48499. * @property {array} _glyphs - Private tracker for the letter sprite pool.
  48500. * @private
  48501. */
  48502. this._glyphs = [];
  48503. /**
  48504. * @property {number} _maxWidth - Internal cache var.
  48505. * @private
  48506. */
  48507. this._maxWidth = 0;
  48508. /**
  48509. * @property {string} _text - Internal cache var.
  48510. * @private
  48511. */
  48512. this._text = text.toString() || '';
  48513. /**
  48514. * @property {string} _data - Internal cache var.
  48515. * @private
  48516. */
  48517. this._data = game.cache.getBitmapFont(font);
  48518. /**
  48519. * @property {string} _font - Internal cache var.
  48520. * @private
  48521. */
  48522. this._font = font;
  48523. /**
  48524. * @property {number} _fontSize - Internal cache var.
  48525. * @private
  48526. */
  48527. this._fontSize = size;
  48528. /**
  48529. * @property {string} _align - Internal cache var.
  48530. * @private
  48531. */
  48532. this._align = align;
  48533. /**
  48534. * @property {number} _tint - Internal cache var.
  48535. * @private
  48536. */
  48537. this._tint = 0xFFFFFF;
  48538. this.updateText();
  48539. /**
  48540. * @property {boolean} dirty - The dirty state of this object.
  48541. */
  48542. this.dirty = false;
  48543. Phaser.Component.Core.init.call(this, game, x, y, '', null);
  48544. };
  48545. Phaser.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  48546. Phaser.BitmapText.prototype.constructor = Phaser.BitmapText;
  48547. Phaser.Component.Core.install.call(Phaser.BitmapText.prototype, [
  48548. 'Angle',
  48549. 'AutoCull',
  48550. 'Bounds',
  48551. 'Destroy',
  48552. 'FixedToCamera',
  48553. 'InputEnabled',
  48554. 'InWorld',
  48555. 'LifeSpan',
  48556. 'PhysicsBody',
  48557. 'Reset'
  48558. ]);
  48559. Phaser.BitmapText.prototype.preUpdatePhysics = Phaser.Component.PhysicsBody.preUpdate;
  48560. Phaser.BitmapText.prototype.preUpdateLifeSpan = Phaser.Component.LifeSpan.preUpdate;
  48561. Phaser.BitmapText.prototype.preUpdateInWorld = Phaser.Component.InWorld.preUpdate;
  48562. Phaser.BitmapText.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
  48563. /**
  48564. * Automatically called by World.preUpdate.
  48565. *
  48566. * @method
  48567. * @memberof Phaser.BitmapText
  48568. * @return {boolean} True if the BitmapText was rendered, otherwise false.
  48569. */
  48570. Phaser.BitmapText.prototype.preUpdate = function () {
  48571. if (!this.preUpdatePhysics() || !this.preUpdateLifeSpan() || !this.preUpdateInWorld())
  48572. {
  48573. return false;
  48574. }
  48575. return this.preUpdateCore();
  48576. };
  48577. /**
  48578. * Automatically called by World.preUpdate.
  48579. * @method Phaser.BitmapText.prototype.postUpdate
  48580. */
  48581. Phaser.BitmapText.prototype.postUpdate = function () {
  48582. Phaser.Component.PhysicsBody.postUpdate.call(this);
  48583. Phaser.Component.FixedToCamera.postUpdate.call(this);
  48584. if (this.body && this.body.type === Phaser.Physics.ARCADE)
  48585. {
  48586. if ((this.textWidth !== this.body.sourceWidth) || (this.textHeight !== this.body.sourceHeight))
  48587. {
  48588. this.body.setSize(this.textWidth, this.textHeight);
  48589. }
  48590. }
  48591. };
  48592. /**
  48593. * The text to be displayed by this BitmapText object.
  48594. *
  48595. * It's faster to use `BitmapText.text = string`, but this is kept for backwards compatibility.
  48596. *
  48597. * @method Phaser.BitmapText.prototype.setText
  48598. * @param {string} text - The text to be displayed by this BitmapText object.
  48599. */
  48600. Phaser.BitmapText.prototype.setText = function (text) {
  48601. this.text = text;
  48602. };
  48603. /**
  48604. * Given the input text this will scan the characters until either a newline is encountered,
  48605. * or the line exceeds maxWidth, taking into account kerning, character widths and scaling.
  48606. *
  48607. * @method Phaser.BitmapText.prototype.scanLine
  48608. * @private
  48609. * @param {object} data - A reference to the font object in the Phaser.Cache.
  48610. * @param {float} scale - The scale of the font in relation to the texture.
  48611. * @param {string} text - The text to parse.
  48612. * @return {object} An object containing the parsed characters, total pixel width and x offsets.
  48613. */
  48614. Phaser.BitmapText.prototype.scanLine = function (data, scale, text) {
  48615. var x = 0;
  48616. var w = 0;
  48617. var lastSpace = -1;
  48618. var wrappedWidth = 0;
  48619. var prevCharCode = null;
  48620. var maxWidth = (this._maxWidth > 0) ? this._maxWidth : null;
  48621. var chars = [];
  48622. // Let's scan the text and work out if any of the lines are > maxWidth
  48623. for (var i = 0; i < text.length; i++)
  48624. {
  48625. var end = (i === text.length - 1) ? true : false;
  48626. if (/(?:\r\n|\r|\n)/.test(text.charAt(i)))
  48627. {
  48628. return { width: w, text: text.substr(0, i), end: end, chars: chars };
  48629. }
  48630. else
  48631. {
  48632. var charCode = text.charCodeAt(i);
  48633. var charData = data.chars[charCode];
  48634. var c = 0;
  48635. // If the character data isn't found in the data array
  48636. // then we replace it with a blank space
  48637. if (charData === undefined)
  48638. {
  48639. charCode = 32;
  48640. charData = data.chars[charCode];
  48641. }
  48642. // Adjust for kerning from previous character to this one
  48643. var kerning = (prevCharCode && charData.kerning[prevCharCode]) ? charData.kerning[prevCharCode] : 0;
  48644. // Record the last space in the string and the current width
  48645. if (/(\s)/.test(text.charAt(i)))
  48646. {
  48647. lastSpace = i;
  48648. wrappedWidth = w;
  48649. }
  48650. // What will the line width be if we add this character to it?
  48651. c = (kerning + charData.texture.width + charData.xOffset) * scale;
  48652. // Do we need to line-wrap?
  48653. if (maxWidth && ((w + c) >= maxWidth) && lastSpace > -1)
  48654. {
  48655. // The last space was at "lastSpace" which was "i - lastSpace" characters ago
  48656. return { width: wrappedWidth || w, text: text.substr(0, i - (i - lastSpace)), end: end, chars: chars };
  48657. }
  48658. else
  48659. {
  48660. w += (charData.xAdvance + kerning) * scale;
  48661. chars.push(x + (charData.xOffset + kerning) * scale);
  48662. x += (charData.xAdvance + kerning) * scale;
  48663. prevCharCode = charCode;
  48664. }
  48665. }
  48666. }
  48667. return { width: w, text: text, end: end, chars: chars };
  48668. };
  48669. /**
  48670. * Given a text string this will scan each character in the string to ensure it exists
  48671. * in the BitmapText font data. If it doesn't the character is removed, or replaced with the `replace` argument.
  48672. *
  48673. * If no font data has been loaded at all this returns an empty string, as nothing can be rendered.
  48674. *
  48675. * @method Phaser.BitmapText.prototype.cleanText
  48676. * @param {string} text - The text to parse.
  48677. * @param {string} [replace=''] - The replacement string for any missing characters.
  48678. * @return {string} The cleaned text string.
  48679. */
  48680. Phaser.BitmapText.prototype.cleanText = function (text, replace) {
  48681. if (replace === undefined)
  48682. {
  48683. replace = '';
  48684. }
  48685. var data = this._data.font;
  48686. if (!data)
  48687. {
  48688. return '';
  48689. }
  48690. var re = /\r\n|\n\r|\n|\r/g;
  48691. var lines = text.replace(re, "\n").split("\n");
  48692. for (var i = 0; i < lines.length; i++)
  48693. {
  48694. var output = '';
  48695. var line = lines[i];
  48696. for (var c = 0; c < line.length; c++)
  48697. {
  48698. if (data.chars[line.charCodeAt(c)])
  48699. {
  48700. output = output.concat(line[c]);
  48701. }
  48702. else
  48703. {
  48704. output = output.concat(replace);
  48705. }
  48706. }
  48707. lines[i] = output;
  48708. }
  48709. return lines.join("\n");
  48710. };
  48711. /**
  48712. * Renders text and updates it when needed.
  48713. *
  48714. * @method Phaser.BitmapText.prototype.updateText
  48715. * @private
  48716. */
  48717. Phaser.BitmapText.prototype.updateText = function () {
  48718. var data = this._data.font;
  48719. if (!data)
  48720. {
  48721. return;
  48722. }
  48723. var text = this.text;
  48724. var scale = this._fontSize / data.size;
  48725. var lines = [];
  48726. var y = 0;
  48727. this.textWidth = 0;
  48728. do
  48729. {
  48730. var line = this.scanLine(data, scale, text);
  48731. line.y = y;
  48732. lines.push(line);
  48733. if (line.width > this.textWidth)
  48734. {
  48735. this.textWidth = line.width;
  48736. }
  48737. y += (data.lineHeight * scale);
  48738. text = text.substr(line.text.length + 1);
  48739. } while (line.end === false);
  48740. this.textHeight = y;
  48741. var t = 0;
  48742. var align = 0;
  48743. var ax = this.textWidth * this.anchor.x;
  48744. var ay = this.textHeight * this.anchor.y;
  48745. for (var i = 0; i < lines.length; i++)
  48746. {
  48747. var line = lines[i];
  48748. if (this._align === 'right')
  48749. {
  48750. align = this.textWidth - line.width;
  48751. }
  48752. else if (this._align === 'center')
  48753. {
  48754. align = (this.textWidth - line.width) / 2;
  48755. }
  48756. for (var c = 0; c < line.text.length; c++)
  48757. {
  48758. var charCode = line.text.charCodeAt(c);
  48759. var charData = data.chars[charCode];
  48760. if (charData === undefined)
  48761. {
  48762. charCode = 32;
  48763. charData = data.chars[charCode];
  48764. }
  48765. var g = this._glyphs[t];
  48766. if (g)
  48767. {
  48768. // Sprite already exists in the glyphs pool, so we'll reuse it for this letter
  48769. g.texture = charData.texture;
  48770. }
  48771. else
  48772. {
  48773. // We need a new sprite as the pool is empty or exhausted
  48774. g = new PIXI.Sprite(charData.texture);
  48775. g.name = line.text[c];
  48776. this._glyphs.push(g);
  48777. }
  48778. g.position.x = (line.chars[c] + align) - ax;
  48779. g.position.y = (line.y + (charData.yOffset * scale)) - ay;
  48780. g.scale.set(scale);
  48781. g.tint = this.tint;
  48782. g.texture.requiresReTint = true;
  48783. g.cachedTint = 0xFFFFFF;
  48784. if (!g.parent)
  48785. {
  48786. this.addChild(g);
  48787. }
  48788. t++;
  48789. }
  48790. }
  48791. // Remove unnecessary children
  48792. // This moves them from the display list (children array) but retains them in the _glyphs pool
  48793. for (i = t; i < this._glyphs.length; i++)
  48794. {
  48795. this.removeChild(this._glyphs[i]);
  48796. }
  48797. };
  48798. /**
  48799. * If a BitmapText changes from having a large number of characters to having very few characters it will cause lots of
  48800. * Sprites to be retained in the BitmapText._glyphs array. Although they are not attached to the display list they
  48801. * still take up memory while sat in the glyphs pool waiting to be re-used in the future.
  48802. *
  48803. * If you know that the BitmapText will not grow any larger then you can purge out the excess glyphs from the pool
  48804. * by calling this method.
  48805. *
  48806. * Calling this doesn't prevent you from increasing the length of the text again in the future.
  48807. *
  48808. * @method Phaser.BitmapText.prototype.purgeGlyphs
  48809. * @return {integer} The amount of glyphs removed from the pool.
  48810. */
  48811. Phaser.BitmapText.prototype.purgeGlyphs = function () {
  48812. var len = this._glyphs.length;
  48813. var kept = [];
  48814. for (var i = 0; i < this._glyphs.length; i++)
  48815. {
  48816. if (this._glyphs[i].parent !== this)
  48817. {
  48818. this._glyphs[i].destroy();
  48819. }
  48820. else
  48821. {
  48822. kept.push(this._glyphs[i]);
  48823. }
  48824. }
  48825. this._glyphs = [];
  48826. this._glyphs = kept;
  48827. this.updateText();
  48828. return len - kept.length;
  48829. };
  48830. /**
  48831. * Updates the transform of this object.
  48832. *
  48833. * @method Phaser.BitmapText.prototype.updateTransform
  48834. * @private
  48835. */
  48836. Phaser.BitmapText.prototype.updateTransform = function () {
  48837. if (this.dirty || !this.anchor.equals(this._prevAnchor))
  48838. {
  48839. this.updateText();
  48840. this.dirty = false;
  48841. this._prevAnchor.copyFrom(this.anchor);
  48842. }
  48843. PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
  48844. };
  48845. /**
  48846. * @name Phaser.BitmapText#align
  48847. * @property {string} align - Alignment for multi-line text ('left', 'center' or 'right'), does not affect single lines of text.
  48848. */
  48849. Object.defineProperty(Phaser.BitmapText.prototype, 'align', {
  48850. get: function() {
  48851. return this._align;
  48852. },
  48853. set: function(value) {
  48854. if (value !== this._align && (value === 'left' || value === 'center' || value === 'right'))
  48855. {
  48856. this._align = value;
  48857. this.updateText();
  48858. }
  48859. }
  48860. });
  48861. /**
  48862. * @name Phaser.BitmapText#tint
  48863. * @property {number} tint - The tint applied to the BitmapText. This is a hex value. Set to white to disable (0xFFFFFF)
  48864. */
  48865. Object.defineProperty(Phaser.BitmapText.prototype, 'tint', {
  48866. get: function() {
  48867. return this._tint;
  48868. },
  48869. set: function(value) {
  48870. if (value !== this._tint)
  48871. {
  48872. this._tint = value;
  48873. this.updateText();
  48874. }
  48875. }
  48876. });
  48877. /**
  48878. * @name Phaser.BitmapText#font
  48879. * @property {string} font - The font the text will be rendered in, i.e. 'Arial'. Must be loaded in the browser before use.
  48880. */
  48881. Object.defineProperty(Phaser.BitmapText.prototype, 'font', {
  48882. get: function() {
  48883. return this._font;
  48884. },
  48885. set: function(value) {
  48886. if (value !== this._font)
  48887. {
  48888. this._font = value.trim();
  48889. this._data = this.game.cache.getBitmapFont(this._font);
  48890. this.updateText();
  48891. }
  48892. }
  48893. });
  48894. /**
  48895. * @name Phaser.BitmapText#fontSize
  48896. * @property {number} fontSize - The size of the font in pixels.
  48897. */
  48898. Object.defineProperty(Phaser.BitmapText.prototype, 'fontSize', {
  48899. get: function() {
  48900. return this._fontSize;
  48901. },
  48902. set: function(value) {
  48903. value = parseInt(value, 10);
  48904. if (value !== this._fontSize && value > 0)
  48905. {
  48906. this._fontSize = value;
  48907. this.updateText();
  48908. }
  48909. }
  48910. });
  48911. /**
  48912. * @name Phaser.BitmapText#text
  48913. * @property {string} text - The text to be displayed by this BitmapText object.
  48914. */
  48915. Object.defineProperty(Phaser.BitmapText.prototype, 'text', {
  48916. get: function() {
  48917. return this._text;
  48918. },
  48919. set: function(value) {
  48920. if (value !== this._text)
  48921. {
  48922. this._text = value.toString() || '';
  48923. this.updateText();
  48924. }
  48925. }
  48926. });
  48927. /**
  48928. * The maximum display width of this BitmapText in pixels.
  48929. *
  48930. * If BitmapText.text is longer than maxWidth then the lines will be automatically wrapped
  48931. * based on the last whitespace character found in the line.
  48932. *
  48933. * If no whitespace was found then no wrapping will take place and consequently the maxWidth value will not be honored.
  48934. *
  48935. * Disable maxWidth by setting the value to 0.
  48936. *
  48937. * @name Phaser.BitmapText#maxWidth
  48938. * @property {number} maxWidth - The maximum width of this BitmapText in pixels.
  48939. */
  48940. Object.defineProperty(Phaser.BitmapText.prototype, 'maxWidth', {
  48941. get: function() {
  48942. return this._maxWidth;
  48943. },
  48944. set: function(value) {
  48945. if (value !== this._maxWidth)
  48946. {
  48947. this._maxWidth = value;
  48948. this.updateText();
  48949. }
  48950. }
  48951. });
  48952. /**
  48953. * Enable or disable texture smoothing for this BitmapText.
  48954. *
  48955. * The smoothing is applied to the BaseTexture of this font, which all letters of the text reference.
  48956. *
  48957. * Smoothing is enabled by default.
  48958. *
  48959. * @name Phaser.BitmapText#smoothed
  48960. * @property {boolean} smoothed
  48961. */
  48962. Object.defineProperty(Phaser.BitmapText.prototype, 'smoothed', {
  48963. get: function() {
  48964. return !this._data.base.scaleMode;
  48965. },
  48966. set: function(value) {
  48967. if (value)
  48968. {
  48969. this._data.base.scaleMode = 0;
  48970. }
  48971. else
  48972. {
  48973. this._data.base.scaleMode = 1;
  48974. }
  48975. }
  48976. });
  48977. /**
  48978. * @author Richard Davey <rich@photonstorm.com>
  48979. * @copyright 2016 Photon Storm Ltd.
  48980. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  48981. */
  48982. /**
  48983. * A Retro Font is similar to a BitmapFont, in that it uses a texture to render the text. However unlike a BitmapFont every character in a RetroFont
  48984. * is the same size. This makes it similar to a sprite sheet. You typically find font sheets like this from old 8/16-bit games and demos.
  48985. *
  48986. * @class Phaser.RetroFont
  48987. * @extends Phaser.RenderTexture
  48988. * @constructor
  48989. * @param {Phaser.Game} game - Current game instance.
  48990. * @param {string} key - The font set graphic set as stored in the Game.Cache.
  48991. * @param {number} characterWidth - The width of each character in the font set.
  48992. * @param {number} characterHeight - The height of each character in the font set.
  48993. * @param {string} chars - The characters used in the font set, in display order. You can use the TEXT_SET consts for common font set arrangements.
  48994. * @param {number} [charsPerRow] - The number of characters per row in the font set. If not given charsPerRow will be the image width / characterWidth.
  48995. * @param {number} [xSpacing=0] - If the characters in the font set have horizontal spacing between them set the required amount here.
  48996. * @param {number} [ySpacing=0] - If the characters in the font set have vertical spacing between them set the required amount here.
  48997. * @param {number} [xOffset=0] - If the font set doesn't start at the top left of the given image, specify the X coordinate offset here.
  48998. * @param {number} [yOffset=0] - If the font set doesn't start at the top left of the given image, specify the Y coordinate offset here.
  48999. */
  49000. Phaser.RetroFont = function (game, key, characterWidth, characterHeight, chars, charsPerRow, xSpacing, ySpacing, xOffset, yOffset) {
  49001. if (!game.cache.checkImageKey(key))
  49002. {
  49003. return false;
  49004. }
  49005. if (charsPerRow === undefined || charsPerRow === null)
  49006. {
  49007. charsPerRow = game.cache.getImage(key).width / characterWidth;
  49008. }
  49009. /**
  49010. * @property {number} characterWidth - The width of each character in the font set.
  49011. */
  49012. this.characterWidth = characterWidth;
  49013. /**
  49014. * @property {number} characterHeight - The height of each character in the font set.
  49015. */
  49016. this.characterHeight = characterHeight;
  49017. /**
  49018. * @property {number} characterSpacingX - If the characters in the font set have horizontal spacing between them set the required amount here.
  49019. */
  49020. this.characterSpacingX = xSpacing || 0;
  49021. /**
  49022. * @property {number} characterSpacingY - If the characters in the font set have vertical spacing between them set the required amount here.
  49023. */
  49024. this.characterSpacingY = ySpacing || 0;
  49025. /**
  49026. * @property {number} characterPerRow - The number of characters per row in the font set.
  49027. */
  49028. this.characterPerRow = charsPerRow;
  49029. /**
  49030. * @property {number} offsetX - If the font set doesn't start at the top left of the given image, specify the X coordinate offset here.
  49031. * @readonly
  49032. */
  49033. this.offsetX = xOffset || 0;
  49034. /**
  49035. * @property {number} offsetY - If the font set doesn't start at the top left of the given image, specify the Y coordinate offset here.
  49036. * @readonly
  49037. */
  49038. this.offsetY = yOffset || 0;
  49039. /**
  49040. * @property {string} align - Alignment of the text when multiLine = true or a fixedWidth is set. Set to RetroFont.ALIGN_LEFT (default), RetroFont.ALIGN_RIGHT or RetroFont.ALIGN_CENTER.
  49041. */
  49042. this.align = "left";
  49043. /**
  49044. * @property {boolean} multiLine - If set to true all carriage-returns in text will form new lines (see align). If false the font will only contain one single line of text (the default)
  49045. * @default
  49046. */
  49047. this.multiLine = false;
  49048. /**
  49049. * @property {boolean} autoUpperCase - Automatically convert any text to upper case. Lots of old bitmap fonts only contain upper-case characters, so the default is true.
  49050. * @default
  49051. */
  49052. this.autoUpperCase = true;
  49053. /**
  49054. * @property {number} customSpacingX - Adds horizontal spacing between each character of the font, in pixels.
  49055. * @default
  49056. */
  49057. this.customSpacingX = 0;
  49058. /**
  49059. * @property {number} customSpacingY - Adds vertical spacing between each line of multi-line text, set in pixels.
  49060. * @default
  49061. */
  49062. this.customSpacingY = 0;
  49063. /**
  49064. * If you need this RetroFont image to have a fixed width you can set the width in this value.
  49065. * If text is wider than the width specified it will be cropped off.
  49066. * @property {number} fixedWidth
  49067. */
  49068. this.fixedWidth = 0;
  49069. /**
  49070. * @property {Image} fontSet - A reference to the image stored in the Game.Cache that contains the font.
  49071. */
  49072. this.fontSet = game.cache.getImage(key);
  49073. /**
  49074. * @property {string} _text - The text of the font image.
  49075. * @private
  49076. */
  49077. this._text = '';
  49078. /**
  49079. * @property {array} grabData - An array of rects for faster character pasting.
  49080. * @private
  49081. */
  49082. this.grabData = [];
  49083. /**
  49084. * @property {Phaser.FrameData} frameData - The FrameData representing this Retro Font.
  49085. */
  49086. this.frameData = new Phaser.FrameData();
  49087. // Now generate our rects for faster copying later on
  49088. var currentX = this.offsetX;
  49089. var currentY = this.offsetY;
  49090. var r = 0;
  49091. for (var c = 0; c < chars.length; c++)
  49092. {
  49093. var frame = this.frameData.addFrame(new Phaser.Frame(c, currentX, currentY, this.characterWidth, this.characterHeight));
  49094. this.grabData[chars.charCodeAt(c)] = frame.index;
  49095. r++;
  49096. if (r === this.characterPerRow)
  49097. {
  49098. r = 0;
  49099. currentX = this.offsetX;
  49100. currentY += this.characterHeight + this.characterSpacingY;
  49101. }
  49102. else
  49103. {
  49104. currentX += this.characterWidth + this.characterSpacingX;
  49105. }
  49106. }
  49107. game.cache.updateFrameData(key, this.frameData);
  49108. /**
  49109. * @property {Phaser.Image} stamp - The image that is stamped to the RenderTexture for each character in the font.
  49110. * @readonly
  49111. */
  49112. this.stamp = new Phaser.Image(game, 0, 0, key, 0);
  49113. Phaser.RenderTexture.call(this, game, 100, 100, '', Phaser.scaleModes.NEAREST);
  49114. /**
  49115. * @property {number} type - Base Phaser object type.
  49116. */
  49117. this.type = Phaser.RETROFONT;
  49118. };
  49119. Phaser.RetroFont.prototype = Object.create(Phaser.RenderTexture.prototype);
  49120. Phaser.RetroFont.prototype.constructor = Phaser.RetroFont;
  49121. /**
  49122. * Align each line of multi-line text to the left.
  49123. * @constant
  49124. * @type {string}
  49125. */
  49126. Phaser.RetroFont.ALIGN_LEFT = "left";
  49127. /**
  49128. * Align each line of multi-line text to the right.
  49129. * @constant
  49130. * @type {string}
  49131. */
  49132. Phaser.RetroFont.ALIGN_RIGHT = "right";
  49133. /**
  49134. * Align each line of multi-line text in the center.
  49135. * @constant
  49136. * @type {string}
  49137. */
  49138. Phaser.RetroFont.ALIGN_CENTER = "center";
  49139. /**
  49140. * Text Set 1 = !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  49141. * @constant
  49142. * @type {string}
  49143. */
  49144. Phaser.RetroFont.TEXT_SET1 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
  49145. /**
  49146. * Text Set 2 = !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ
  49147. * @constant
  49148. * @type {string}
  49149. */
  49150. Phaser.RetroFont.TEXT_SET2 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  49151. /**
  49152. * Text Set 3 = ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
  49153. * @constant
  49154. * @type {string}
  49155. */
  49156. Phaser.RetroFont.TEXT_SET3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
  49157. /**
  49158. * Text Set 4 = ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789
  49159. * @constant
  49160. * @type {string}
  49161. */
  49162. Phaser.RetroFont.TEXT_SET4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789";
  49163. /**
  49164. * Text Set 5 = ABCDEFGHIJKLMNOPQRSTUVWXYZ.,/() '!?-*:0123456789
  49165. * @constant
  49166. * @type {string}
  49167. */
  49168. Phaser.RetroFont.TEXT_SET5 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,/() '!?-*:0123456789";
  49169. /**
  49170. * Text Set 6 = ABCDEFGHIJKLMNOPQRSTUVWXYZ!?:;0123456789"(),-.'
  49171. * @constant
  49172. * @type {string}
  49173. */
  49174. Phaser.RetroFont.TEXT_SET6 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!?:;0123456789\"(),-.' ";
  49175. /**
  49176. * Text Set 7 = AGMSY+:4BHNTZ!;5CIOU.?06DJPV,(17EKQW")28FLRX-'39
  49177. * @constant
  49178. * @type {string}
  49179. */
  49180. Phaser.RetroFont.TEXT_SET7 = "AGMSY+:4BHNTZ!;5CIOU.?06DJPV,(17EKQW\")28FLRX-'39";
  49181. /**
  49182. * Text Set 8 = 0123456789 .ABCDEFGHIJKLMNOPQRSTUVWXYZ
  49183. * @constant
  49184. * @type {string}
  49185. */
  49186. Phaser.RetroFont.TEXT_SET8 = "0123456789 .ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  49187. /**
  49188. * Text Set 9 = ABCDEFGHIJKLMNOPQRSTUVWXYZ()-0123456789.:,'"?!
  49189. * @constant
  49190. * @type {string}
  49191. */
  49192. Phaser.RetroFont.TEXT_SET9 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ()-0123456789.:,'\"?!";
  49193. /**
  49194. * Text Set 10 = ABCDEFGHIJKLMNOPQRSTUVWXYZ
  49195. * @constant
  49196. * @type {string}
  49197. */
  49198. Phaser.RetroFont.TEXT_SET10 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  49199. /**
  49200. * Text Set 11 = ABCDEFGHIJKLMNOPQRSTUVWXYZ.,"-+!?()':;0123456789
  49201. * @constant
  49202. * @type {string}
  49203. */
  49204. Phaser.RetroFont.TEXT_SET11 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,\"-+!?()':;0123456789";
  49205. /**
  49206. * If you need this RetroFont to have a fixed width and custom alignment you can set the width here.
  49207. * If text is wider than the width specified it will be cropped off.
  49208. *
  49209. * @method Phaser.RetroFont#setFixedWidth
  49210. * @memberof Phaser.RetroFont
  49211. * @param {number} width - Width in pixels of this RetroFont. Set to zero to disable and re-enable automatic resizing.
  49212. * @param {string} [lineAlignment='left'] - Align the text within this width. Set to RetroFont.ALIGN_LEFT (default), RetroFont.ALIGN_RIGHT or RetroFont.ALIGN_CENTER.
  49213. */
  49214. Phaser.RetroFont.prototype.setFixedWidth = function (width, lineAlignment) {
  49215. if (lineAlignment === undefined) { lineAlignment = 'left'; }
  49216. this.fixedWidth = width;
  49217. this.align = lineAlignment;
  49218. };
  49219. /**
  49220. * A helper function that quickly sets lots of variables at once, and then updates the text.
  49221. *
  49222. * @method Phaser.RetroFont#setText
  49223. * @memberof Phaser.RetroFont
  49224. * @param {string} content - The text of this sprite.
  49225. * @param {boolean} [multiLine=false] - Set to true if you want to support carriage-returns in the text and create a multi-line sprite instead of a single line.
  49226. * @param {number} [characterSpacing=0] - To add horizontal spacing between each character specify the amount in pixels.
  49227. * @param {number} [lineSpacing=0] - To add vertical spacing between each line of text, set the amount in pixels.
  49228. * @param {string} [lineAlignment='left'] - Align each line of multi-line text. Set to RetroFont.ALIGN_LEFT, RetroFont.ALIGN_RIGHT or RetroFont.ALIGN_CENTER.
  49229. * @param {boolean} [allowLowerCase=false] - Lots of bitmap font sets only include upper-case characters, if yours needs to support lower case then set this to true.
  49230. */
  49231. Phaser.RetroFont.prototype.setText = function (content, multiLine, characterSpacing, lineSpacing, lineAlignment, allowLowerCase) {
  49232. this.multiLine = multiLine || false;
  49233. this.customSpacingX = characterSpacing || 0;
  49234. this.customSpacingY = lineSpacing || 0;
  49235. this.align = lineAlignment || 'left';
  49236. if (allowLowerCase)
  49237. {
  49238. this.autoUpperCase = false;
  49239. }
  49240. else
  49241. {
  49242. this.autoUpperCase = true;
  49243. }
  49244. if (content.length > 0)
  49245. {
  49246. this.text = content;
  49247. }
  49248. };
  49249. /**
  49250. * Updates the texture with the new text.
  49251. *
  49252. * @method Phaser.RetroFont#buildRetroFontText
  49253. * @memberof Phaser.RetroFont
  49254. */
  49255. Phaser.RetroFont.prototype.buildRetroFontText = function () {
  49256. var cx = 0;
  49257. var cy = 0;
  49258. // Clears the textureBuffer
  49259. this.clear();
  49260. if (this.multiLine)
  49261. {
  49262. var lines = this._text.split("\n");
  49263. if (this.fixedWidth > 0)
  49264. {
  49265. this.resize(this.fixedWidth, (lines.length * (this.characterHeight + this.customSpacingY)) - this.customSpacingY, true);
  49266. }
  49267. else
  49268. {
  49269. this.resize(this.getLongestLine() * (this.characterWidth + this.customSpacingX), (lines.length * (this.characterHeight + this.customSpacingY)) - this.customSpacingY, true);
  49270. }
  49271. // Loop through each line of text
  49272. for (var i = 0; i < lines.length; i++)
  49273. {
  49274. // Phaser.RetroFont.ALIGN_LEFT
  49275. cx = 0;
  49276. // This line of text is held in lines[i] - need to work out the alignment
  49277. if (this.align === Phaser.RetroFont.ALIGN_RIGHT)
  49278. {
  49279. cx = this.width - (lines[i].length * (this.characterWidth + this.customSpacingX));
  49280. }
  49281. else if (this.align === Phaser.RetroFont.ALIGN_CENTER)
  49282. {
  49283. cx = (this.width / 2) - ((lines[i].length * (this.characterWidth + this.customSpacingX)) / 2);
  49284. cx += this.customSpacingX / 2;
  49285. }
  49286. // Sanity checks
  49287. if (cx < 0)
  49288. {
  49289. cx = 0;
  49290. }
  49291. this.pasteLine(lines[i], cx, cy, this.customSpacingX);
  49292. cy += this.characterHeight + this.customSpacingY;
  49293. }
  49294. }
  49295. else
  49296. {
  49297. if (this.fixedWidth > 0)
  49298. {
  49299. this.resize(this.fixedWidth, this.characterHeight, true);
  49300. }
  49301. else
  49302. {
  49303. this.resize(this._text.length * (this.characterWidth + this.customSpacingX), this.characterHeight, true);
  49304. }
  49305. // Phaser.RetroFont.ALIGN_LEFT
  49306. cx = 0;
  49307. if (this.align === Phaser.RetroFont.ALIGN_RIGHT)
  49308. {
  49309. cx = this.width - (this._text.length * (this.characterWidth + this.customSpacingX));
  49310. }
  49311. else if (this.align === Phaser.RetroFont.ALIGN_CENTER)
  49312. {
  49313. cx = (this.width / 2) - ((this._text.length * (this.characterWidth + this.customSpacingX)) / 2);
  49314. cx += this.customSpacingX / 2;
  49315. }
  49316. // Sanity checks
  49317. if (cx < 0)
  49318. {
  49319. cx = 0;
  49320. }
  49321. this.pasteLine(this._text, cx, 0, this.customSpacingX);
  49322. }
  49323. this.requiresReTint = true;
  49324. };
  49325. /**
  49326. * Internal function that takes a single line of text (2nd parameter) and pastes it into the BitmapData at the given coordinates.
  49327. * Used by getLine and getMultiLine
  49328. *
  49329. * @method Phaser.RetroFont#pasteLine
  49330. * @memberof Phaser.RetroFont
  49331. * @param {string} line - The single line of text to paste.
  49332. * @param {number} x - The x coordinate.
  49333. * @param {number} y - The y coordinate.
  49334. * @param {number} customSpacingX - Custom X spacing.
  49335. */
  49336. Phaser.RetroFont.prototype.pasteLine = function (line, x, y, customSpacingX) {
  49337. for (var c = 0; c < line.length; c++)
  49338. {
  49339. // If it's a space then there is no point copying, so leave a blank space
  49340. if (line.charAt(c) === " ")
  49341. {
  49342. x += this.characterWidth + customSpacingX;
  49343. }
  49344. else
  49345. {
  49346. // If the character doesn't exist in the font then we don't want a blank space, we just want to skip it
  49347. if (this.grabData[line.charCodeAt(c)] >= 0)
  49348. {
  49349. this.stamp.frame = this.grabData[line.charCodeAt(c)];
  49350. this.renderXY(this.stamp, x, y, false);
  49351. x += this.characterWidth + customSpacingX;
  49352. if (x > this.width)
  49353. {
  49354. break;
  49355. }
  49356. }
  49357. }
  49358. }
  49359. };
  49360. /**
  49361. * Works out the longest line of text in _text and returns its length
  49362. *
  49363. * @method Phaser.RetroFont#getLongestLine
  49364. * @memberof Phaser.RetroFont
  49365. * @return {number} The length of the longest line of text.
  49366. */
  49367. Phaser.RetroFont.prototype.getLongestLine = function () {
  49368. var longestLine = 0;
  49369. if (this._text.length > 0)
  49370. {
  49371. var lines = this._text.split("\n");
  49372. for (var i = 0; i < lines.length; i++)
  49373. {
  49374. if (lines[i].length > longestLine)
  49375. {
  49376. longestLine = lines[i].length;
  49377. }
  49378. }
  49379. }
  49380. return longestLine;
  49381. };
  49382. /**
  49383. * Internal helper function that removes all unsupported characters from the _text String, leaving only characters contained in the font set.
  49384. *
  49385. * @method Phaser.RetroFont#removeUnsupportedCharacters
  49386. * @memberof Phaser.RetroFont
  49387. * @protected
  49388. * @param {boolean} [stripCR=true] - Should it strip carriage returns as well?
  49389. * @return {string} A clean version of the string.
  49390. */
  49391. Phaser.RetroFont.prototype.removeUnsupportedCharacters = function (stripCR) {
  49392. var newString = "";
  49393. for (var c = 0; c < this._text.length; c++)
  49394. {
  49395. var aChar = this._text[c];
  49396. var code = aChar.charCodeAt(0);
  49397. if (this.grabData[code] >= 0 || (!stripCR && aChar === "\n"))
  49398. {
  49399. newString = newString.concat(aChar);
  49400. }
  49401. }
  49402. return newString;
  49403. };
  49404. /**
  49405. * Updates the x and/or y offset that the font is rendered from. This updates all of the texture frames, so be careful how often it is called.
  49406. * Note that the values given for the x and y properties are either ADDED to or SUBTRACTED from (if negative) the existing offsetX/Y values of the characters.
  49407. * So if the current offsetY is 8 and you want it to start rendering from y16 you would call updateOffset(0, 8) to add 8 to the current y offset.
  49408. *
  49409. * @method Phaser.RetroFont#updateOffset
  49410. * @memberof Phaser.RetroFont
  49411. * @param {number} [xOffset=0] - If the font set doesn't start at the top left of the given image, specify the X coordinate offset here.
  49412. * @param {number} [yOffset=0] - If the font set doesn't start at the top left of the given image, specify the Y coordinate offset here.
  49413. */
  49414. Phaser.RetroFont.prototype.updateOffset = function (x, y) {
  49415. if (this.offsetX === x && this.offsetY === y)
  49416. {
  49417. return;
  49418. }
  49419. var diffX = x - this.offsetX;
  49420. var diffY = y - this.offsetY;
  49421. var frames = this.game.cache.getFrameData(this.stamp.key).getFrames();
  49422. var i = frames.length;
  49423. while (i--)
  49424. {
  49425. frames[i].x += diffX;
  49426. frames[i].y += diffY;
  49427. }
  49428. this.buildRetroFontText();
  49429. };
  49430. /**
  49431. * @name Phaser.RetroFont#text
  49432. * @property {string} text - Set this value to update the text in this sprite. Carriage returns are automatically stripped out if multiLine is false. Text is converted to upper case if autoUpperCase is true.
  49433. */
  49434. Object.defineProperty(Phaser.RetroFont.prototype, "text", {
  49435. get: function () {
  49436. return this._text;
  49437. },
  49438. set: function (value) {
  49439. var newText;
  49440. if (this.autoUpperCase)
  49441. {
  49442. newText = value.toUpperCase();
  49443. }
  49444. else
  49445. {
  49446. newText = value;
  49447. }
  49448. if (newText !== this._text)
  49449. {
  49450. this._text = newText;
  49451. this.removeUnsupportedCharacters(this.multiLine);
  49452. this.buildRetroFontText();
  49453. }
  49454. }
  49455. });
  49456. /**
  49457. * @name Phaser.RetroFont#smoothed
  49458. * @property {boolean} smoothed - Sets if the stamp is smoothed or not.
  49459. */
  49460. Object.defineProperty(Phaser.RetroFont.prototype, "smoothed", {
  49461. get: function () {
  49462. return this.stamp.smoothed;
  49463. },
  49464. set: function (value) {
  49465. this.stamp.smoothed = value;
  49466. this.buildRetroFontText();
  49467. }
  49468. });
  49469. /**
  49470. * @author Richard Davey <rich@photonstorm.com>
  49471. * @author Mat Groves (@Doormat23)
  49472. * @author Rovanion Luckey
  49473. * @copyright 2016 Photon Storm Ltd, Richard Davey
  49474. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  49475. */
  49476. /**
  49477. * A Rope is a Sprite that has a repeating texture.
  49478. *
  49479. * The texture will automatically wrap on the edges as it moves.
  49480. *
  49481. * Please note that Ropes cannot have an input handler.
  49482. *
  49483. * @class Phaser.Rope
  49484. * @constructor
  49485. * @extends PIXI.DisplayObjectContainer
  49486. * @extends Phaser.Component.Core
  49487. * @extends Phaser.Component.Angle
  49488. * @extends Phaser.Component.Animation
  49489. * @extends Phaser.Component.AutoCull
  49490. * @extends Phaser.Component.Bounds
  49491. * @extends Phaser.Component.BringToTop
  49492. * @extends Phaser.Component.Crop
  49493. * @extends Phaser.Component.Delta
  49494. * @extends Phaser.Component.Destroy
  49495. * @extends Phaser.Component.FixedToCamera
  49496. * @extends Phaser.Component.InWorld
  49497. * @extends Phaser.Component.LifeSpan
  49498. * @extends Phaser.Component.LoadTexture
  49499. * @extends Phaser.Component.Overlap
  49500. * @extends Phaser.Component.PhysicsBody
  49501. * @extends Phaser.Component.Reset
  49502. * @extends Phaser.Component.ScaleMinMax
  49503. * @extends Phaser.Component.Smoothed
  49504. * @param {Phaser.Game} game - A reference to the currently running game.
  49505. * @param {number} x - The x coordinate (in world space) to position the Rope at.
  49506. * @param {number} y - The y coordinate (in world space) to position the Rope at.
  49507. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Rope during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture.
  49508. * @param {string|number} frame - If this Rope is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  49509. * @param {Array} points - An array of {Phaser.Point}.
  49510. */
  49511. Phaser.Rope = function (game, x, y, key, frame, points) {
  49512. this.points = [];
  49513. this.points = points;
  49514. this._hasUpdateAnimation = false;
  49515. this._updateAnimationCallback = null;
  49516. x = x || 0;
  49517. y = y || 0;
  49518. key = key || null;
  49519. frame = frame || null;
  49520. /**
  49521. * @property {number} type - The const type of this object.
  49522. * @readonly
  49523. */
  49524. this.type = Phaser.ROPE;
  49525. this.points = points;
  49526. PIXI.DisplayObjectContainer.call(this);
  49527. this.texture = Phaser.Cache.DEFAULT;
  49528. // set up the main bits..
  49529. this.uvs = new Float32Array([0, 1,
  49530. 1, 1,
  49531. 1, 0,
  49532. 0, 1]);
  49533. this.vertices = new Float32Array([0, 0,
  49534. 100, 0,
  49535. 100, 100,
  49536. 0, 100]);
  49537. this.colors = new Float32Array([1, 1, 1, 1]);
  49538. this.indices = new Uint16Array([0, 1, 2, 3]);
  49539. if (points)
  49540. {
  49541. this.vertices = new Float32Array(points.length * 4);
  49542. this.uvs = new Float32Array(points.length * 4);
  49543. this.colors = new Float32Array(points.length * 2);
  49544. this.indices = new Uint16Array(points.length * 2);
  49545. }
  49546. /**
  49547. * Whether the strip is dirty or not
  49548. *
  49549. * @property dirty
  49550. * @type Boolean
  49551. */
  49552. this.dirty = true;
  49553. /**
  49554. * Triangles in canvas mode are automatically antialiased, use this value to force triangles to overlap a bit with each other.
  49555. *
  49556. * @property canvasPadding
  49557. * @type Number
  49558. */
  49559. this.canvasPadding = 0;
  49560. this.drawMode = Phaser.Rope.TRIANGLE_STRIP;
  49561. Phaser.Component.Core.init.call(this, game, x, y, key, frame);
  49562. this.refresh();
  49563. };
  49564. Phaser.Rope.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  49565. Phaser.Rope.prototype.constructor = Phaser.Rope;
  49566. Phaser.Component.Core.install.call(Phaser.Rope.prototype, [
  49567. 'Angle',
  49568. 'Animation',
  49569. 'AutoCull',
  49570. 'Bounds',
  49571. 'BringToTop',
  49572. 'Crop',
  49573. 'Delta',
  49574. 'Destroy',
  49575. 'FixedToCamera',
  49576. 'InWorld',
  49577. 'LifeSpan',
  49578. 'LoadTexture',
  49579. 'Overlap',
  49580. 'PhysicsBody',
  49581. 'Reset',
  49582. 'ScaleMinMax',
  49583. 'Smoothed'
  49584. ]);
  49585. Phaser.Rope.prototype.preUpdatePhysics = Phaser.Component.PhysicsBody.preUpdate;
  49586. Phaser.Rope.prototype.preUpdateLifeSpan = Phaser.Component.LifeSpan.preUpdate;
  49587. Phaser.Rope.prototype.preUpdateInWorld = Phaser.Component.InWorld.preUpdate;
  49588. Phaser.Rope.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
  49589. Phaser.Rope.TRIANGLE_STRIP = 0;
  49590. Phaser.Rope.TRIANGLES = 1;
  49591. /**
  49592. * Automatically called by World.preUpdate.
  49593. *
  49594. * @method Phaser.Rope#preUpdate
  49595. * @memberof Phaser.Rope
  49596. */
  49597. Phaser.Rope.prototype.preUpdate = function () {
  49598. if (!this.preUpdatePhysics() || !this.preUpdateLifeSpan() || !this.preUpdateInWorld())
  49599. {
  49600. return false;
  49601. }
  49602. return this.preUpdateCore();
  49603. };
  49604. /**
  49605. * Override and use this function in your own custom objects to handle any update requirements you may have.
  49606. *
  49607. * @method Phaser.Rope#update
  49608. * @memberof Phaser.Rope
  49609. */
  49610. Phaser.Rope.prototype.update = function() {
  49611. if (this._hasUpdateAnimation)
  49612. {
  49613. this.updateAnimation.call(this);
  49614. }
  49615. };
  49616. /**
  49617. * Resets the Rope. This places the Rope at the given x/y world coordinates and then
  49618. * sets alive, exists, visible and renderable all to true. Also resets the outOfBounds state.
  49619. * If the Rope has a physics body that too is reset.
  49620. *
  49621. * @method Phaser.Rope#reset
  49622. * @memberof Phaser.Rope
  49623. * @param {number} x - The x coordinate (in world space) to position the Sprite at.
  49624. * @param {number} y - The y coordinate (in world space) to position the Sprite at.
  49625. * @return {Phaser.Rope} This instance.
  49626. */
  49627. Phaser.Rope.prototype.reset = function (x, y) {
  49628. Phaser.Component.Reset.prototype.reset.call(this, x, y);
  49629. return this;
  49630. };
  49631. /*
  49632. * Refreshes the rope texture and UV coordinates.
  49633. *
  49634. * @method Phaser.Rope#refresh
  49635. * @memberof Phaser.Rope
  49636. */
  49637. Phaser.Rope.prototype.refresh = function () {
  49638. var points = this.points;
  49639. if (points.length < 1)
  49640. {
  49641. return;
  49642. }
  49643. var uvs = this.uvs;
  49644. var indices = this.indices;
  49645. var colors = this.colors;
  49646. this.count -= 0.2;
  49647. uvs[0] = 0;
  49648. uvs[1] = 0;
  49649. uvs[2] = 0;
  49650. uvs[3] = 1;
  49651. colors[0] = 1;
  49652. colors[1] = 1;
  49653. indices[0] = 0;
  49654. indices[1] = 1;
  49655. var total = points.length;
  49656. var index;
  49657. var amount;
  49658. for (var i = 1; i < total; i++)
  49659. {
  49660. index = i * 4;
  49661. // time to do some smart drawing!
  49662. amount = i / (total - 1);
  49663. if (i % 2)
  49664. {
  49665. uvs[index] = amount;
  49666. uvs[index + 1] = 0;
  49667. uvs[index + 2] = amount;
  49668. uvs[index + 3] = 1;
  49669. }
  49670. else
  49671. {
  49672. uvs[index] = amount;
  49673. uvs[index + 1] = 0;
  49674. uvs[index + 2] = amount;
  49675. uvs[index + 3] = 1;
  49676. }
  49677. index = i * 2;
  49678. colors[index] = 1;
  49679. colors[index + 1] = 1;
  49680. index = i * 2;
  49681. indices[index] = index;
  49682. indices[index + 1] = index + 1;
  49683. }
  49684. };
  49685. /*
  49686. * Updates the Ropes transform ready for rendering.
  49687. *
  49688. * @method Phaser.Rope#updateTransform
  49689. * @memberof Phaser.Rope
  49690. */
  49691. Phaser.Rope.prototype.updateTransform = function () {
  49692. var points = this.points;
  49693. if (points.length < 1)
  49694. {
  49695. return;
  49696. }
  49697. var lastPoint = points[0];
  49698. var nextPoint;
  49699. var perp = { x:0, y:0 };
  49700. this.count -= 0.2;
  49701. var vertices = this.vertices;
  49702. var total = points.length;
  49703. var point;
  49704. var index;
  49705. var ratio;
  49706. var perpLength;
  49707. var num;
  49708. for (var i = 0; i < total; i++)
  49709. {
  49710. point = points[i];
  49711. index = i * 4;
  49712. if(i < points.length - 1)
  49713. {
  49714. nextPoint = points[i + 1];
  49715. }
  49716. else
  49717. {
  49718. nextPoint = point;
  49719. }
  49720. perp.y = -(nextPoint.x - lastPoint.x);
  49721. perp.x = nextPoint.y - lastPoint.y;
  49722. ratio = (1 - (i / (total - 1))) * 10;
  49723. if (ratio > 1)
  49724. {
  49725. ratio = 1;
  49726. }
  49727. perpLength = Math.sqrt((perp.x * perp.x) + (perp.y * perp.y));
  49728. num = this.texture.height / 2;
  49729. perp.x /= perpLength;
  49730. perp.y /= perpLength;
  49731. perp.x *= num;
  49732. perp.y *= num;
  49733. vertices[index] = point.x + perp.x;
  49734. vertices[index + 1] = point.y + perp.y;
  49735. vertices[index + 2] = point.x - perp.x;
  49736. vertices[index + 3] = point.y - perp.y;
  49737. lastPoint = point;
  49738. }
  49739. PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
  49740. };
  49741. /*
  49742. * Sets the Texture this Rope uses for rendering.
  49743. *
  49744. * @method Phaser.Rope#setTexture
  49745. * @memberof Phaser.Rope
  49746. * @param {Texture} texture - The texture that will be used.
  49747. */
  49748. Phaser.Rope.prototype.setTexture = function (texture) {
  49749. this.texture = texture;
  49750. };
  49751. /*
  49752. * Renders the Rope to WebGL.
  49753. *
  49754. * @private
  49755. * @method Phaser.Rope#_renderWebGL
  49756. * @memberof Phaser.Rope
  49757. */
  49758. Phaser.Rope.prototype._renderWebGL = function (renderSession) {
  49759. if (!this.visible || this.alpha <= 0)
  49760. {
  49761. return;
  49762. }
  49763. renderSession.spriteBatch.stop();
  49764. if (!this._vertexBuffer)
  49765. {
  49766. this._initWebGL(renderSession);
  49767. }
  49768. renderSession.shaderManager.setShader(renderSession.shaderManager.stripShader);
  49769. this._renderStrip(renderSession);
  49770. renderSession.spriteBatch.start();
  49771. };
  49772. /*
  49773. * Builds the Strip.
  49774. *
  49775. * @private
  49776. * @method Phaser.Rope#_initWebGL
  49777. * @memberof Phaser.Rope
  49778. */
  49779. Phaser.Rope.prototype._initWebGL = function (renderSession) {
  49780. // build the strip!
  49781. var gl = renderSession.gl;
  49782. this._vertexBuffer = gl.createBuffer();
  49783. this._indexBuffer = gl.createBuffer();
  49784. this._uvBuffer = gl.createBuffer();
  49785. this._colorBuffer = gl.createBuffer();
  49786. gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
  49787. gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
  49788. gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer);
  49789. gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW);
  49790. gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer);
  49791. gl.bufferData(gl.ARRAY_BUFFER, this.colors, gl.STATIC_DRAW);
  49792. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
  49793. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
  49794. };
  49795. /*
  49796. * Renders the Strip to WebGL.
  49797. *
  49798. * @private
  49799. * @method Phaser.Rope#_renderStrip
  49800. * @memberof Phaser.Rope
  49801. */
  49802. Phaser.Rope.prototype._renderStrip = function (renderSession) {
  49803. var gl = renderSession.gl;
  49804. var projection = renderSession.projection;
  49805. var offset = renderSession.offset;
  49806. var shader = renderSession.shaderManager.stripShader;
  49807. var drawMode = (this.drawMode === Phaser.Rope.TRIANGLE_STRIP) ? gl.TRIANGLE_STRIP : gl.TRIANGLES;
  49808. renderSession.blendModeManager.setBlendMode(this.blendMode);
  49809. // set uniforms
  49810. gl.uniformMatrix3fv(shader.translationMatrix, false, this.worldTransform.toArray(true));
  49811. gl.uniform2f(shader.projectionVector, projection.x, -projection.y);
  49812. gl.uniform2f(shader.offsetVector, -offset.x, -offset.y);
  49813. gl.uniform1f(shader.alpha, this.worldAlpha);
  49814. if (!this.dirty)
  49815. {
  49816. gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
  49817. gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
  49818. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
  49819. // update the uvs
  49820. gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer);
  49821. gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
  49822. gl.activeTexture(gl.TEXTURE0);
  49823. // check if a texture is dirty..
  49824. if (this.texture.baseTexture._dirty[gl.id])
  49825. {
  49826. renderSession.renderer.updateTexture(this.texture.baseTexture);
  49827. }
  49828. else
  49829. {
  49830. // bind the current texture
  49831. gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]);
  49832. }
  49833. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
  49834. }
  49835. else
  49836. {
  49837. this.dirty = false;
  49838. gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
  49839. gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.STATIC_DRAW);
  49840. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
  49841. // update the uvs
  49842. gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer);
  49843. gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW);
  49844. gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
  49845. gl.activeTexture(gl.TEXTURE0);
  49846. // check if a texture is dirty..
  49847. if (this.texture.baseTexture._dirty[gl.id])
  49848. {
  49849. renderSession.renderer.updateTexture(this.texture.baseTexture);
  49850. }
  49851. else
  49852. {
  49853. gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]);
  49854. }
  49855. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
  49856. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
  49857. }
  49858. gl.drawElements(drawMode, this.indices.length, gl.UNSIGNED_SHORT, 0);
  49859. };
  49860. /*
  49861. * Renders the Strip to Canvas.
  49862. *
  49863. * @private
  49864. * @method Phaser.Rope#_renderCanvas
  49865. * @memberof Phaser.Rope
  49866. */
  49867. Phaser.Rope.prototype._renderCanvas = function (renderSession) {
  49868. var context = renderSession.context;
  49869. var transform = this.worldTransform;
  49870. var tx = (transform.tx * renderSession.resolution) + renderSession.shakeX;
  49871. var ty = (transform.ty * renderSession.resolution) + renderSession.shakeY;
  49872. if (renderSession.roundPixels)
  49873. {
  49874. context.setTransform(transform.a, transform.b, transform.c, transform.d, tx | 0, ty | 0);
  49875. }
  49876. else
  49877. {
  49878. context.setTransform(transform.a, transform.b, transform.c, transform.d, tx, ty);
  49879. }
  49880. if (this.drawMode === Phaser.Rope.TRIANGLE_STRIP)
  49881. {
  49882. this._renderCanvasTriangleStrip(context);
  49883. }
  49884. else
  49885. {
  49886. this._renderCanvasTriangles(context);
  49887. }
  49888. };
  49889. /*
  49890. * Renders a Triangle Strip to Canvas.
  49891. *
  49892. * @private
  49893. * @method Phaser.Rope#_renderCanvasTriangleStrip
  49894. * @memberof Phaser.Rope
  49895. */
  49896. Phaser.Rope.prototype._renderCanvasTriangleStrip = function (context) {
  49897. // draw triangles!!
  49898. var vertices = this.vertices;
  49899. var uvs = this.uvs;
  49900. var length = vertices.length / 2;
  49901. this.count++;
  49902. for (var i = 0; i < length - 2; i++)
  49903. {
  49904. var index = i * 2;
  49905. this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4));
  49906. }
  49907. };
  49908. /*
  49909. * Renders a Triangle to Canvas.
  49910. *
  49911. * @private
  49912. * @method Phaser.Rope#_renderCanvasTriangles
  49913. * @memberof Phaser.Rope
  49914. */
  49915. Phaser.Rope.prototype._renderCanvasTriangles = function (context) {
  49916. var vertices = this.vertices;
  49917. var uvs = this.uvs;
  49918. var indices = this.indices;
  49919. var length = indices.length;
  49920. this.count++;
  49921. for (var i = 0; i < length; i += 3)
  49922. {
  49923. var index0 = indices[i] * 2;
  49924. var index1 = indices[i + 1] * 2;
  49925. var index2 = indices[i + 2] * 2;
  49926. this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2);
  49927. }
  49928. };
  49929. /*
  49930. * Renders a Triangle to Canvas.
  49931. *
  49932. * @private
  49933. * @method Phaser.Rope#_renderCanvasDrawTriangle
  49934. * @memberof Phaser.Rope
  49935. */
  49936. Phaser.Rope.prototype._renderCanvasDrawTriangle = function (context, vertices, uvs, index0, index1, index2) {
  49937. var textureSource = this.texture.baseTexture.source;
  49938. var textureWidth = this.texture.width;
  49939. var textureHeight = this.texture.height;
  49940. var x0 = vertices[index0];
  49941. var x1 = vertices[index1];
  49942. var x2 = vertices[index2];
  49943. var y0 = vertices[index0 + 1];
  49944. var y1 = vertices[index1 + 1];
  49945. var y2 = vertices[index2 + 1];
  49946. var u0 = uvs[index0] * textureWidth;
  49947. var u1 = uvs[index1] * textureWidth;
  49948. var u2 = uvs[index2] * textureWidth;
  49949. var v0 = uvs[index0 + 1] * textureHeight;
  49950. var v1 = uvs[index1 + 1] * textureHeight;
  49951. var v2 = uvs[index2 + 1] * textureHeight;
  49952. if (this.canvasPadding > 0)
  49953. {
  49954. var paddingX = this.canvasPadding / this.worldTransform.a;
  49955. var paddingY = this.canvasPadding / this.worldTransform.d;
  49956. var centerX = (x0 + x1 + x2) / 3;
  49957. var centerY = (y0 + y1 + y2) / 3;
  49958. var normX = x0 - centerX;
  49959. var normY = y0 - centerY;
  49960. var dist = Math.sqrt((normX * normX) + (normY * normY));
  49961. x0 = centerX + (normX / dist) * (dist + paddingX);
  49962. y0 = centerY + (normY / dist) * (dist + paddingY);
  49963. normX = x1 - centerX;
  49964. normY = y1 - centerY;
  49965. dist = Math.sqrt((normX * normX) + (normY * normY));
  49966. x1 = centerX + (normX / dist) * (dist + paddingX);
  49967. y1 = centerY + (normY / dist) * (dist + paddingY);
  49968. normX = x2 - centerX;
  49969. normY = y2 - centerY;
  49970. dist = Math.sqrt((normX * normX) + (normY * normY));
  49971. x2 = centerX + (normX / dist) * (dist + paddingX);
  49972. y2 = centerY + (normY / dist) * (dist + paddingY);
  49973. }
  49974. context.save();
  49975. context.beginPath();
  49976. context.moveTo(x0, y0);
  49977. context.lineTo(x1, y1);
  49978. context.lineTo(x2, y2);
  49979. context.closePath();
  49980. context.clip();
  49981. // Compute matrix transform
  49982. var delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2);
  49983. var deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2);
  49984. var deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2);
  49985. var deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2);
  49986. var deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2);
  49987. var deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2);
  49988. var deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2);
  49989. context.transform(
  49990. deltaA / delta,
  49991. deltaD / delta,
  49992. deltaB / delta,
  49993. deltaE / delta,
  49994. deltaC / delta,
  49995. deltaF / delta);
  49996. context.drawImage(textureSource, 0, 0);
  49997. context.restore();
  49998. };
  49999. /*
  50000. * Renders a flat strip.
  50001. *
  50002. * @method Phaser.Rope#renderStripFlat
  50003. * @memberof Phaser.Rope
  50004. */
  50005. Phaser.Rope.prototype.renderStripFlat = function (strip) {
  50006. var context = this.context;
  50007. var vertices = strip.vertices;
  50008. var length = vertices.length / 2;
  50009. this.count++;
  50010. context.beginPath();
  50011. for (var i = 1; i < length - 2; i++)
  50012. {
  50013. // draw some triangles!
  50014. var index = i * 2;
  50015. var x0 = vertices[index];
  50016. var x1 = vertices[index + 2];
  50017. var x2 = vertices[index + 4];
  50018. var y0 = vertices[index + 1];
  50019. var y1 = vertices[index + 3];
  50020. var y2 = vertices[index + 5];
  50021. context.moveTo(x0, y0);
  50022. context.lineTo(x1, y1);
  50023. context.lineTo(x2, y2);
  50024. }
  50025. context.fillStyle = '#FF0000';
  50026. context.fill();
  50027. context.closePath();
  50028. };
  50029. /*
  50030. * Returns the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account.
  50031. *
  50032. * @method Phaser.Rope#getBounds
  50033. * @memberof Phaser.Rope
  50034. * @param {Matrix} matrix - The transformation matrix of the Sprite.
  50035. * @return {Rectangle} The framing rectangle.
  50036. */
  50037. Phaser.Rope.prototype.getBounds = function (matrix) {
  50038. var worldTransform = matrix || this.worldTransform;
  50039. var a = worldTransform.a;
  50040. var b = worldTransform.b;
  50041. var c = worldTransform.c;
  50042. var d = worldTransform.d;
  50043. var tx = worldTransform.tx;
  50044. var ty = worldTransform.ty;
  50045. var maxX = -Infinity;
  50046. var maxY = -Infinity;
  50047. var minX = Infinity;
  50048. var minY = Infinity;
  50049. var vertices = this.vertices;
  50050. for (var i = 0; i < vertices.length; i += 2)
  50051. {
  50052. var rawX = vertices[i];
  50053. var rawY = vertices[i + 1];
  50054. var x = (a * rawX) + (c * rawY) + tx;
  50055. var y = (d * rawY) + (b * rawX) + ty;
  50056. minX = x < minX ? x : minX;
  50057. minY = y < minY ? y : minY;
  50058. maxX = x > maxX ? x : maxX;
  50059. maxY = y > maxY ? y : maxY;
  50060. }
  50061. if (minX === -Infinity || maxY === Infinity)
  50062. {
  50063. return PIXI.EmptyRectangle;
  50064. }
  50065. var bounds = this._bounds;
  50066. bounds.x = minX;
  50067. bounds.width = maxX - minX;
  50068. bounds.y = minY;
  50069. bounds.height = maxY - minY;
  50070. // Store a reference so that if this function gets called again in the render cycle we do not have to recalculate
  50071. this._currentBounds = bounds;
  50072. return bounds;
  50073. };
  50074. /**
  50075. * A Rope will call its updateAnimation function on each update loop if it has one.
  50076. *
  50077. * @name Phaser.Rope#updateAnimation
  50078. * @property {function} updateAnimation - Set to a function if you'd like the rope to animate during the update phase. Set to false or null to remove it.
  50079. */
  50080. Object.defineProperty(Phaser.Rope.prototype, "updateAnimation", {
  50081. get: function () {
  50082. return this._updateAnimation;
  50083. },
  50084. set: function (value) {
  50085. if (value && typeof value === 'function')
  50086. {
  50087. this._hasUpdateAnimation = true;
  50088. this._updateAnimation = value;
  50089. }
  50090. else
  50091. {
  50092. this._hasUpdateAnimation = false;
  50093. this._updateAnimation = null;
  50094. }
  50095. }
  50096. });
  50097. /**
  50098. * The segments that make up the rope body as an array of Phaser.Rectangles
  50099. *
  50100. * @name Phaser.Rope#segments
  50101. * @property {Phaser.Rectangles[]} updateAnimation - Returns an array of Phaser.Rectangles that represent the segments of the given rope
  50102. */
  50103. Object.defineProperty(Phaser.Rope.prototype, "segments", {
  50104. get: function () {
  50105. var segments = [];
  50106. var index, x1, y1, x2, y2, width, height, rect;
  50107. for (var i = 0; i < this.points.length; i++)
  50108. {
  50109. index = i * 4;
  50110. x1 = this.vertices[index] * this.scale.x;
  50111. y1 = this.vertices[index + 1] * this.scale.y;
  50112. x2 = this.vertices[index + 4] * this.scale.x;
  50113. y2 = this.vertices[index + 3] * this.scale.y;
  50114. width = Phaser.Math.difference(x1, x2);
  50115. height = Phaser.Math.difference(y1, y2);
  50116. x1 += this.world.x;
  50117. y1 += this.world.y;
  50118. rect = new Phaser.Rectangle(x1, y1, width, height);
  50119. segments.push(rect);
  50120. }
  50121. return segments;
  50122. }
  50123. });
  50124. /**
  50125. * @author Richard Davey <rich@photonstorm.com>
  50126. * @copyright 2016 Photon Storm Ltd.
  50127. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  50128. */
  50129. /**
  50130. * A TileSprite is a Sprite that has a repeating texture. The texture can be scrolled and scaled independently of the TileSprite itself.
  50131. * Textures will automatically wrap and are designed so that you can create game backdrops using seamless textures as a source.
  50132. *
  50133. * TileSprites have no input handler or physics bodies by default, both need enabling in the same way as for normal Sprites.
  50134. *
  50135. * You shouldn't ever create a TileSprite any larger than your actual screen size. If you want to create a large repeating background
  50136. * that scrolls across the whole map of your game, then you create a TileSprite that fits the screen size and then use the `tilePosition`
  50137. * property to scroll the texture as the player moves. If you create a TileSprite that is thousands of pixels in size then it will
  50138. * consume huge amounts of memory and cause performance issues. Remember: use `tilePosition` to scroll your texture and `tileScale` to
  50139. * adjust the scale of the texture - don't resize the sprite itself or make it larger than it needs.
  50140. *
  50141. * An important note about texture dimensions:
  50142. *
  50143. * When running under Canvas a TileSprite can use any texture size without issue. When running under WebGL the texture should ideally be
  50144. * a power of two in size (i.e. 4, 8, 16, 32, 64, 128, 256, 512, etc pixels width by height). If the texture isn't a power of two
  50145. * it will be rendered to a blank canvas that is the correct size, which means you may have 'blank' areas appearing to the right and
  50146. * bottom of your frame. To avoid this ensure your textures are perfect powers of two.
  50147. *
  50148. * TileSprites support animations in the same way that Sprites do. You add and play animations using the AnimationManager. However
  50149. * if your game is running under WebGL please note that each frame of the animation must be a power of two in size, or it will receive
  50150. * additional padding to enforce it to be so.
  50151. *
  50152. * @class Phaser.TileSprite
  50153. * @constructor
  50154. * @extends PIXI.Sprite
  50155. * @extends Phaser.Component.Core
  50156. * @extends Phaser.Component.Angle
  50157. * @extends Phaser.Component.Animation
  50158. * @extends Phaser.Component.AutoCull
  50159. * @extends Phaser.Component.Bounds
  50160. * @extends Phaser.Component.BringToTop
  50161. * @extends Phaser.Component.Destroy
  50162. * @extends Phaser.Component.FixedToCamera
  50163. * @extends Phaser.Component.Health
  50164. * @extends Phaser.Component.InCamera
  50165. * @extends Phaser.Component.InputEnabled
  50166. * @extends Phaser.Component.InWorld
  50167. * @extends Phaser.Component.LifeSpan
  50168. * @extends Phaser.Component.LoadTexture
  50169. * @extends Phaser.Component.Overlap
  50170. * @extends Phaser.Component.PhysicsBody
  50171. * @extends Phaser.Component.Reset
  50172. * @extends Phaser.Component.Smoothed
  50173. * @param {Phaser.Game} game - A reference to the currently running game.
  50174. * @param {number} [x=0] - The x coordinate (in world space) to position the TileSprite at.
  50175. * @param {number} [y=0] - The y coordinate (in world space) to position the TileSprite at.
  50176. * @param {number} [width=256] - The width of the TileSprite.
  50177. * @param {number} [height=256] - The height of the TileSprite.
  50178. * @param {string|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the TileSprite during rendering. It can be a string which is a reference to the Phaser Image Cache entry, or an instance of a PIXI.Texture or BitmapData.
  50179. * @param {string|number} frame - If this TileSprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  50180. */
  50181. Phaser.TileSprite = function (game, x, y, width, height, key, frame) {
  50182. x = x || 0;
  50183. y = y || 0;
  50184. width = width || 256;
  50185. height = height || 256;
  50186. key = key || null;
  50187. frame = frame || null;
  50188. PIXI.Sprite.call(this, new PIXI.Texture(Phaser.Cache.DEFAULT.baseTexture), width, height);
  50189. /**
  50190. * @property {number} type - The const type of this object.
  50191. * @readonly
  50192. */
  50193. this.type = Phaser.TILESPRITE;
  50194. /**
  50195. * @property {number} physicsType - The const physics body type of this object.
  50196. * @readonly
  50197. */
  50198. this.physicsType = Phaser.SPRITE;
  50199. /**
  50200. * @property {Phaser.Point} _scroll - Internal cache var.
  50201. * @private
  50202. */
  50203. this._scroll = new Phaser.Point();
  50204. /**
  50205. * @property {Phaser.Point} tileScale - The scale applied to the image being tiled.
  50206. */
  50207. this.tileScale = new Phaser.Point(1, 1);
  50208. /**
  50209. * @property {Phaser.Point} tileScaleOffset - The scale offset applied to the image being tiled.
  50210. */
  50211. this.tileScaleOffset = new Phaser.Point(1, 1);
  50212. /**
  50213. * @property {Phaser.Point} tilePosition - The offset position of the image being tiled.
  50214. */
  50215. this.tilePosition = new Phaser.Point();
  50216. /**
  50217. * If enabled a green rectangle will be drawn behind the generated tiling texture,
  50218. * allowing you to visually debug the texture being used.
  50219. *
  50220. * @property {boolean} textureDebug
  50221. */
  50222. this.textureDebug = false;
  50223. /**
  50224. * The CanvasBuffer object that the tiled texture is drawn to.
  50225. *
  50226. * @property {PIXI.CanvasBuffer} canvasBuffer
  50227. */
  50228. this.canvasBuffer = null;
  50229. /**
  50230. * An internal Texture object that holds the tiling texture that was generated from TilingSprite.texture.
  50231. *
  50232. * @property {PIXI.Texture} tilingTexture
  50233. */
  50234. this.tilingTexture = null;
  50235. /**
  50236. * The Context fill pattern that is used to draw the TilingSprite in Canvas mode only (will be null in WebGL).
  50237. *
  50238. * @property {object} tilePattern
  50239. */
  50240. this.tilePattern = null;
  50241. /**
  50242. * If true the TileSprite will run `generateTexture` on its **next** render pass.
  50243. * This is set by the likes of Phaser.LoadTexture.setFrame.
  50244. *
  50245. * @property {boolean} refreshTexture
  50246. */
  50247. this.refreshTexture = true;
  50248. this.frameWidth = 0;
  50249. this.frameHeight = 0;
  50250. this._width = width;
  50251. this._height = height;
  50252. Phaser.Component.Core.init.call(this, game, x, y, key, frame);
  50253. };
  50254. Phaser.TileSprite.prototype = Object.create(PIXI.Sprite.prototype);
  50255. Phaser.TileSprite.prototype.constructor = Phaser.TileSprite;
  50256. Phaser.Component.Core.install.call(Phaser.TileSprite.prototype, [
  50257. 'Angle',
  50258. 'Animation',
  50259. 'AutoCull',
  50260. 'Bounds',
  50261. 'BringToTop',
  50262. 'Destroy',
  50263. 'FixedToCamera',
  50264. 'Health',
  50265. 'InCamera',
  50266. 'InputEnabled',
  50267. 'InWorld',
  50268. 'LifeSpan',
  50269. 'LoadTexture',
  50270. 'Overlap',
  50271. 'PhysicsBody',
  50272. 'Reset',
  50273. 'Smoothed'
  50274. ]);
  50275. Phaser.TileSprite.prototype.preUpdatePhysics = Phaser.Component.PhysicsBody.preUpdate;
  50276. Phaser.TileSprite.prototype.preUpdateLifeSpan = Phaser.Component.LifeSpan.preUpdate;
  50277. Phaser.TileSprite.prototype.preUpdateInWorld = Phaser.Component.InWorld.preUpdate;
  50278. Phaser.TileSprite.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
  50279. /**
  50280. * Automatically called by World.preUpdate.
  50281. *
  50282. * @method Phaser.TileSprite#preUpdate
  50283. * @memberof Phaser.TileSprite
  50284. * @return {boolean}
  50285. */
  50286. Phaser.TileSprite.prototype.preUpdate = function () {
  50287. if (this._scroll.x !== 0)
  50288. {
  50289. this.tilePosition.x += this._scroll.x * this.game.time.physicsElapsed;
  50290. }
  50291. if (this._scroll.y !== 0)
  50292. {
  50293. this.tilePosition.y += this._scroll.y * this.game.time.physicsElapsed;
  50294. }
  50295. if (!this.preUpdatePhysics() || !this.preUpdateLifeSpan() || !this.preUpdateInWorld())
  50296. {
  50297. return false;
  50298. }
  50299. return this.preUpdateCore();
  50300. };
  50301. /**
  50302. * Sets this TileSprite to automatically scroll in the given direction until stopped via TileSprite.stopScroll().
  50303. * The scroll speed is specified in pixels per second.
  50304. * A negative x value will scroll to the left. A positive x value will scroll to the right.
  50305. * A negative y value will scroll up. A positive y value will scroll down.
  50306. *
  50307. * @method Phaser.TileSprite#autoScroll
  50308. * @memberof Phaser.TileSprite
  50309. * @param {number} x - Horizontal scroll speed in pixels per second.
  50310. * @param {number} y - Vertical scroll speed in pixels per second.
  50311. * @return {Phaser.TileSprite} This instance.
  50312. */
  50313. Phaser.TileSprite.prototype.autoScroll = function (x, y) {
  50314. this._scroll.set(x, y);
  50315. return this;
  50316. };
  50317. /**
  50318. * Stops an automatically scrolling TileSprite.
  50319. *
  50320. * @method Phaser.TileSprite#stopScroll
  50321. * @memberof Phaser.TileSprite
  50322. * @return {Phaser.TileSprite} This instance.
  50323. */
  50324. Phaser.TileSprite.prototype.stopScroll = function () {
  50325. this._scroll.set(0, 0);
  50326. return this;
  50327. };
  50328. /**
  50329. * Destroys the TileSprite. This removes it from its parent group, destroys the event and animation handlers if present
  50330. * and nulls its reference to game, freeing it up for garbage collection.
  50331. *
  50332. * @method Phaser.TileSprite#destroy
  50333. * @memberof Phaser.TileSprite
  50334. * @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
  50335. */
  50336. Phaser.TileSprite.prototype.destroy = function (destroyChildren) {
  50337. Phaser.Component.Destroy.prototype.destroy.call(this, destroyChildren);
  50338. PIXI.Sprite.prototype.destroy.call(this);
  50339. if (this.canvasBuffer)
  50340. {
  50341. this.canvasBuffer.destroy();
  50342. this.canvasBuffer = null;
  50343. }
  50344. this.tileScale = null;
  50345. this.tileScaleOffset = null;
  50346. this.tilePosition = null;
  50347. if (this.tilingTexture)
  50348. {
  50349. this.tilingTexture.destroy(true);
  50350. this.tilingTexture = null;
  50351. }
  50352. };
  50353. /**
  50354. * Resets the TileSprite. This places the TileSprite at the given x/y world coordinates, resets the tilePosition and then
  50355. * sets alive, exists, visible and renderable all to true. Also resets the outOfBounds state.
  50356. * If the TileSprite has a physics body that too is reset.
  50357. *
  50358. * @method Phaser.TileSprite#reset
  50359. * @memberof Phaser.TileSprite
  50360. * @param {number} x - The x coordinate (in world space) to position the Sprite at.
  50361. * @param {number} y - The y coordinate (in world space) to position the Sprite at.
  50362. * @return {Phaser.TileSprite} This instance.
  50363. */
  50364. Phaser.TileSprite.prototype.reset = function (x, y) {
  50365. Phaser.Component.Reset.prototype.reset.call(this, x, y);
  50366. this.tilePosition.x = 0;
  50367. this.tilePosition.y = 0;
  50368. return this;
  50369. };
  50370. /**
  50371. * Changes the texture being rendered by this TileSprite.
  50372. * Causes a texture refresh to take place on the next render.
  50373. *
  50374. * @method Phaser.TileSprite#setTexture
  50375. * @memberof Phaser.TileSprite
  50376. * @param {PIXI.Texture} texture - The texture to apply to this TileSprite.
  50377. * @return {Phaser.TileSprite} This instance.
  50378. */
  50379. Phaser.TileSprite.prototype.setTexture = function (texture) {
  50380. if (this.texture !== texture)
  50381. {
  50382. this.texture = texture;
  50383. this.refreshTexture = true;
  50384. this.cachedTint = 0xFFFFFF;
  50385. }
  50386. return this;
  50387. };
  50388. /**
  50389. * Renders the TileSprite using the WebGL Renderer.
  50390. *
  50391. * @private
  50392. * @method Phaser.TileSprite#_renderWebGL
  50393. * @memberof Phaser.TileSprite
  50394. * @param {object} renderSession
  50395. */
  50396. Phaser.TileSprite.prototype._renderWebGL = function (renderSession) {
  50397. if (!this.visible || !this.renderable || this.alpha === 0)
  50398. {
  50399. return;
  50400. }
  50401. if (this._mask)
  50402. {
  50403. renderSession.spriteBatch.stop();
  50404. renderSession.maskManager.pushMask(this.mask, renderSession);
  50405. renderSession.spriteBatch.start();
  50406. }
  50407. if (this._filters)
  50408. {
  50409. renderSession.spriteBatch.flush();
  50410. renderSession.filterManager.pushFilter(this._filterBlock);
  50411. }
  50412. if (this.refreshTexture)
  50413. {
  50414. this.generateTilingTexture(true, renderSession);
  50415. if (this.tilingTexture)
  50416. {
  50417. if (this.tilingTexture.needsUpdate)
  50418. {
  50419. this.tilingTexture.baseTexture.textureIndex = this.texture.baseTexture.textureIndex;
  50420. renderSession.renderer.updateTexture(this.tilingTexture.baseTexture);
  50421. this.tilingTexture.needsUpdate = false;
  50422. }
  50423. }
  50424. else
  50425. {
  50426. return;
  50427. }
  50428. }
  50429. renderSession.spriteBatch.renderTilingSprite(this);
  50430. for (var i = 0; i < this.children.length; i++)
  50431. {
  50432. this.children[i]._renderWebGL(renderSession);
  50433. }
  50434. var restartBatch = false;
  50435. if (this._filters)
  50436. {
  50437. restartBatch = true;
  50438. renderSession.spriteBatch.stop();
  50439. renderSession.filterManager.popFilter();
  50440. }
  50441. if (this._mask)
  50442. {
  50443. if (!restartBatch)
  50444. {
  50445. renderSession.spriteBatch.stop();
  50446. }
  50447. renderSession.maskManager.popMask(this._mask, renderSession);
  50448. }
  50449. if (restartBatch)
  50450. {
  50451. renderSession.spriteBatch.start();
  50452. }
  50453. };
  50454. /**
  50455. * Renders the TileSprite using the Canvas Renderer.
  50456. *
  50457. * @private
  50458. * @method Phaser.TileSprite#_renderCanvas
  50459. * @memberof Phaser.TileSprite
  50460. * @param {object} renderSession
  50461. */
  50462. Phaser.TileSprite.prototype._renderCanvas = function (renderSession) {
  50463. if (!this.visible || !this.renderable || this.alpha === 0)
  50464. {
  50465. return;
  50466. }
  50467. var context = renderSession.context;
  50468. if (this._mask)
  50469. {
  50470. renderSession.maskManager.pushMask(this._mask, renderSession);
  50471. }
  50472. context.globalAlpha = this.worldAlpha;
  50473. var wt = this.worldTransform;
  50474. var resolution = renderSession.resolution;
  50475. var tx = (wt.tx * resolution) + renderSession.shakeX;
  50476. var ty = (wt.ty * resolution) + renderSession.shakeY;
  50477. context.setTransform(wt.a * resolution, wt.b * resolution, wt.c * resolution, wt.d * resolution, tx, ty);
  50478. if (this.tint !== 0xFFFFFF && (this.texture.requiresReTint || this.cachedTint !== this.tint))
  50479. {
  50480. this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint);
  50481. this.cachedTint = this.tint;
  50482. this.texture.requiresReTint = false;
  50483. this.refreshTexture = true;
  50484. }
  50485. if (this.refreshTexture)
  50486. {
  50487. this.generateTilingTexture(false, renderSession);
  50488. if (this.tilingTexture)
  50489. {
  50490. this.tilePattern = context.createPattern(this.tilingTexture.baseTexture.source, 'repeat');
  50491. }
  50492. else
  50493. {
  50494. return;
  50495. }
  50496. }
  50497. var sessionBlendMode = renderSession.currentBlendMode;
  50498. // Check blend mode
  50499. if (this.blendMode !== renderSession.currentBlendMode)
  50500. {
  50501. renderSession.currentBlendMode = this.blendMode;
  50502. context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
  50503. }
  50504. var tilePosition = this.tilePosition;
  50505. var tileScale = this.tileScale;
  50506. tilePosition.x %= this.tilingTexture.baseTexture.width;
  50507. tilePosition.y %= this.tilingTexture.baseTexture.height;
  50508. // Translate
  50509. context.scale(tileScale.x, tileScale.y);
  50510. context.translate(tilePosition.x + (this.anchor.x * -this._width), tilePosition.y + (this.anchor.y * -this._height));
  50511. context.fillStyle = this.tilePattern;
  50512. tx = -tilePosition.x;
  50513. ty = -tilePosition.y;
  50514. var tw = this._width / tileScale.x;
  50515. var th = this._height / tileScale.y;
  50516. // Allow for pixel rounding
  50517. if (renderSession.roundPixels)
  50518. {
  50519. tx |= 0;
  50520. ty |= 0;
  50521. tw |= 0;
  50522. th |= 0;
  50523. }
  50524. context.fillRect(tx, ty, tw, th);
  50525. // Translate back again
  50526. context.scale(1 / tileScale.x, 1 / tileScale.y);
  50527. context.translate(-tilePosition.x + (this.anchor.x * this._width), -tilePosition.y + (this.anchor.y * this._height));
  50528. if (this._mask)
  50529. {
  50530. renderSession.maskManager.popMask(renderSession);
  50531. }
  50532. for (var i = 0; i < this.children.length; i++)
  50533. {
  50534. this.children[i]._renderCanvas(renderSession);
  50535. }
  50536. // Reset blend mode
  50537. if (sessionBlendMode !== this.blendMode)
  50538. {
  50539. renderSession.currentBlendMode = sessionBlendMode;
  50540. context.globalCompositeOperation = PIXI.blendModesCanvas[sessionBlendMode];
  50541. }
  50542. };
  50543. /**
  50544. * Override the Sprite method.
  50545. *
  50546. * @private
  50547. * @method Phaser.TileSprite#onTextureUpdate
  50548. * @memberof Phaser.TileSprite
  50549. */
  50550. Phaser.TileSprite.prototype.onTextureUpdate = function () {
  50551. // overriding the sprite version of this!
  50552. };
  50553. /**
  50554. * Internal method that generates a new tiling texture.
  50555. *
  50556. * @method Phaser.TileSprite#generateTilingTexture
  50557. * @memberof Phaser.TileSprite
  50558. * @param {boolean} forcePowerOfTwo - Whether we want to force the texture to be a power of two
  50559. */
  50560. Phaser.TileSprite.prototype.generateTilingTexture = function (forcePowerOfTwo) {
  50561. if (!this.texture.baseTexture.hasLoaded)
  50562. {
  50563. return;
  50564. }
  50565. var texture = this.texture;
  50566. var frame = texture.frame;
  50567. var targetWidth = this._frame.sourceSizeW || this._frame.width;
  50568. var targetHeight = this._frame.sourceSizeH || this._frame.height;
  50569. var dx = 0;
  50570. var dy = 0;
  50571. if (this._frame.trimmed)
  50572. {
  50573. dx = this._frame.spriteSourceSizeX;
  50574. dy = this._frame.spriteSourceSizeY;
  50575. }
  50576. if (forcePowerOfTwo)
  50577. {
  50578. targetWidth = Phaser.Math.getNextPowerOfTwo(targetWidth);
  50579. targetHeight = Phaser.Math.getNextPowerOfTwo(targetHeight);
  50580. }
  50581. if (this.canvasBuffer)
  50582. {
  50583. this.canvasBuffer.resize(targetWidth, targetHeight);
  50584. this.tilingTexture.baseTexture.width = targetWidth;
  50585. this.tilingTexture.baseTexture.height = targetHeight;
  50586. this.tilingTexture.needsUpdate = true;
  50587. }
  50588. else
  50589. {
  50590. this.canvasBuffer = new PIXI.CanvasBuffer(targetWidth, targetHeight);
  50591. this.tilingTexture = PIXI.Texture.fromCanvas(this.canvasBuffer.canvas);
  50592. this.tilingTexture.isTiling = true;
  50593. this.tilingTexture.needsUpdate = true;
  50594. }
  50595. if (this.textureDebug)
  50596. {
  50597. this.canvasBuffer.context.strokeStyle = '#00ff00';
  50598. this.canvasBuffer.context.strokeRect(0, 0, targetWidth, targetHeight);
  50599. }
  50600. // If a sprite sheet we need this:
  50601. var w = texture.crop.width;
  50602. var h = texture.crop.height;
  50603. if (w !== targetWidth || h !== targetHeight)
  50604. {
  50605. w = targetWidth;
  50606. h = targetHeight;
  50607. }
  50608. var targetTexture = this.tintedTexture ? this.tintedTexture : texture.baseTexture.source;
  50609. this.canvasBuffer.context.drawImage(
  50610. targetTexture,
  50611. texture.crop.x,
  50612. texture.crop.y,
  50613. texture.crop.width,
  50614. texture.crop.height,
  50615. dx,
  50616. dy,
  50617. w,
  50618. h
  50619. );
  50620. this.tileScaleOffset.x = frame.width / targetWidth;
  50621. this.tileScaleOffset.y = frame.height / targetHeight;
  50622. this.refreshTexture = false;
  50623. this.tilingTexture.baseTexture._powerOf2 = true;
  50624. };
  50625. /**
  50626. * Returns the framing rectangle of the Tile Sprite.
  50627. *
  50628. * @method Phaser.TileSprite#getBounds
  50629. * @memberof Phaser.TileSprite
  50630. * @return {Phaser.Rectangle} The bounds of the Tile Sprite.
  50631. */
  50632. Phaser.TileSprite.prototype.getBounds = function () {
  50633. var width = this._width;
  50634. var height = this._height;
  50635. var w0 = width * (1 - this.anchor.x);
  50636. var w1 = width * -this.anchor.x;
  50637. var h0 = height * (1 - this.anchor.y);
  50638. var h1 = height * -this.anchor.y;
  50639. var worldTransform = this.worldTransform;
  50640. var a = worldTransform.a;
  50641. var b = worldTransform.b;
  50642. var c = worldTransform.c;
  50643. var d = worldTransform.d;
  50644. var tx = worldTransform.tx;
  50645. var ty = worldTransform.ty;
  50646. var x1 = (a * w1) + (c * h1) + tx;
  50647. var y1 = (d * h1) + (b * w1) + ty;
  50648. var x2 = (a * w0) + (c * h1) + tx;
  50649. var y2 = (d * h1) + (b * w0) + ty;
  50650. var x3 = (a * w0) + (c * h0) + tx;
  50651. var y3 = (d * h0) + (b * w0) + ty;
  50652. var x4 = a * w1 + c * h0 + tx;
  50653. var y4 = d * h0 + b * w1 + ty;
  50654. var maxX = -Infinity;
  50655. var maxY = -Infinity;
  50656. var minX = Infinity;
  50657. var minY = Infinity;
  50658. minX = x1 < minX ? x1 : minX;
  50659. minX = x2 < minX ? x2 : minX;
  50660. minX = x3 < minX ? x3 : minX;
  50661. minX = x4 < minX ? x4 : minX;
  50662. minY = y1 < minY ? y1 : minY;
  50663. minY = y2 < minY ? y2 : minY;
  50664. minY = y3 < minY ? y3 : minY;
  50665. minY = y4 < minY ? y4 : minY;
  50666. maxX = x1 > maxX ? x1 : maxX;
  50667. maxX = x2 > maxX ? x2 : maxX;
  50668. maxX = x3 > maxX ? x3 : maxX;
  50669. maxX = x4 > maxX ? x4 : maxX;
  50670. maxY = y1 > maxY ? y1 : maxY;
  50671. maxY = y2 > maxY ? y2 : maxY;
  50672. maxY = y3 > maxY ? y3 : maxY;
  50673. maxY = y4 > maxY ? y4 : maxY;
  50674. // TODO: This is surely always undefined? As it's not set anywhere in the parent objects
  50675. var bounds = this._bounds;
  50676. bounds.x = minX;
  50677. bounds.width = maxX - minX;
  50678. bounds.y = minY;
  50679. bounds.height = maxY - minY;
  50680. // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
  50681. this._currentBounds = bounds;
  50682. return bounds;
  50683. };
  50684. /**
  50685. * The width of the sprite, setting this will actually modify the scale to achieve the value set
  50686. *
  50687. * @property width
  50688. * @type Number
  50689. */
  50690. Object.defineProperty(Phaser.TileSprite.prototype, 'width', {
  50691. get: function () {
  50692. return this._width;
  50693. },
  50694. set: function (value) {
  50695. this._width = value;
  50696. }
  50697. });
  50698. /**
  50699. * The height of the TilingSprite, setting this will actually modify the scale to achieve the value set
  50700. *
  50701. * @property height
  50702. * @type Number
  50703. */
  50704. Object.defineProperty(Phaser.TileSprite.prototype, 'height', {
  50705. get: function () {
  50706. return this._height;
  50707. },
  50708. set: function (value) {
  50709. this._height = value;
  50710. }
  50711. });
  50712. /**
  50713. * @author Richard Davey <rich@photonstorm.com>
  50714. * @copyright 2016 Photon Storm Ltd.
  50715. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  50716. */
  50717. /**
  50718. * The CanvasPool is a global static object, that allows Phaser to recycle and pool Canvas DOM elements.
  50719. *
  50720. * @class Phaser.CanvasPool
  50721. * @static
  50722. */
  50723. Phaser.CanvasPool = {
  50724. /**
  50725. * Creates a new Canvas DOM element, or pulls one from the pool if free.
  50726. *
  50727. * @method Phaser.CanvasPool.create
  50728. * @static
  50729. * @param {any} parent - The parent of the canvas element.
  50730. * @param {number} width - The width of the canvas element.
  50731. * @param {number} height - The height of the canvas element.
  50732. * @return {HTMLCanvasElement} The canvas element.
  50733. */
  50734. create: function (parent, width, height) {
  50735. var idx = Phaser.CanvasPool.getFirst();
  50736. var canvas;
  50737. if (idx === -1)
  50738. {
  50739. var container = {
  50740. parent: parent,
  50741. canvas: document.createElement('canvas')
  50742. };
  50743. Phaser.CanvasPool.pool.push(container);
  50744. canvas = container.canvas;
  50745. }
  50746. else
  50747. {
  50748. Phaser.CanvasPool.pool[idx].parent = parent;
  50749. canvas = Phaser.CanvasPool.pool[idx].canvas;
  50750. }
  50751. if (width !== undefined)
  50752. {
  50753. canvas.width = width;
  50754. canvas.height = height;
  50755. }
  50756. return canvas;
  50757. },
  50758. /**
  50759. * Gets the first free canvas index from the pool.
  50760. *
  50761. * @static
  50762. * @method Phaser.CanvasPool.getFirst
  50763. * @return {number}
  50764. */
  50765. getFirst: function () {
  50766. var pool = Phaser.CanvasPool.pool;
  50767. for (var i = 0; i < pool.length; i++)
  50768. {
  50769. if (!pool[i].parent)
  50770. {
  50771. return i;
  50772. }
  50773. }
  50774. return -1;
  50775. },
  50776. /**
  50777. * Looks up a canvas based on its parent, and if found puts it back in the pool, freeing it up for re-use.
  50778. * The canvas has its width and height set to 1, and its parent attribute nulled.
  50779. *
  50780. * @static
  50781. * @method Phaser.CanvasPool.remove
  50782. * @param {any} parent - The parent of the canvas element.
  50783. */
  50784. remove: function (parent) {
  50785. var pool = Phaser.CanvasPool.pool;
  50786. for (var i = 0; i < pool.length; i++)
  50787. {
  50788. if (pool[i].parent === parent)
  50789. {
  50790. pool[i].parent = null;
  50791. pool[i].canvas.width = 1;
  50792. pool[i].canvas.height = 1;
  50793. }
  50794. }
  50795. },
  50796. /**
  50797. * Looks up a canvas based on its type, and if found puts it back in the pool, freeing it up for re-use.
  50798. * The canvas has its width and height set to 1, and its parent attribute nulled.
  50799. *
  50800. * @static
  50801. * @method Phaser.CanvasPool.removeByCanvas
  50802. * @param {HTMLCanvasElement} canvas - The canvas element to remove.
  50803. */
  50804. removeByCanvas: function (canvas) {
  50805. var pool = Phaser.CanvasPool.pool;
  50806. for (var i = 0; i < pool.length; i++)
  50807. {
  50808. if (pool[i].canvas === canvas)
  50809. {
  50810. pool[i].parent = null;
  50811. pool[i].canvas.width = 1;
  50812. pool[i].canvas.height = 1;
  50813. }
  50814. }
  50815. },
  50816. /**
  50817. * Gets the total number of used canvas elements in the pool.
  50818. *
  50819. * @static
  50820. * @method Phaser.CanvasPool.getTotal
  50821. * @return {number} The number of in-use (parented) canvas elements in the pool.
  50822. */
  50823. getTotal: function () {
  50824. var pool = Phaser.CanvasPool.pool;
  50825. var c = 0;
  50826. for (var i = 0; i < pool.length; i++)
  50827. {
  50828. if (pool[i].parent)
  50829. {
  50830. c++;
  50831. }
  50832. }
  50833. return c;
  50834. },
  50835. /**
  50836. * Gets the total number of free canvas elements in the pool.
  50837. *
  50838. * @static
  50839. * @method Phaser.CanvasPool.getFree
  50840. * @return {number} The number of free (un-parented) canvas elements in the pool.
  50841. */
  50842. getFree: function () {
  50843. var pool = Phaser.CanvasPool.pool;
  50844. var c = 0;
  50845. for (var i = 0; i < pool.length; i++)
  50846. {
  50847. if (!pool[i].parent)
  50848. {
  50849. c++;
  50850. }
  50851. }
  50852. return c;
  50853. },
  50854. /**
  50855. * Prints in-use, free, and total counts to console.log.
  50856. *
  50857. * @static
  50858. * @method Phaser.CanvasPool.log
  50859. */
  50860. log: function () {
  50861. console.log('CanvasPool: %s used, %s free, %s total', this.getTotal(), this.getFree(), this.pool.length);
  50862. }
  50863. };
  50864. /**
  50865. * The pool into which the canvas elements are placed.
  50866. *
  50867. * @property pool
  50868. * @type Array
  50869. * @static
  50870. */
  50871. Phaser.CanvasPool.pool = [];
  50872. /**
  50873. * The total number of canvas elements in the {@link Phaser.CanvasPool.pool pool}.
  50874. *
  50875. * @property length
  50876. * @type number
  50877. * @static
  50878. * @readonly
  50879. */
  50880. Object.defineProperty(Phaser.CanvasPool, 'length', {
  50881. get: function () {
  50882. return this.pool.length;
  50883. }
  50884. });
  50885. /**
  50886. * @author Richard Davey <rich@photonstorm.com>
  50887. * @copyright 2016 Photon Storm Ltd.
  50888. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  50889. */
  50890. /**
  50891. * @classdesc
  50892. * Detects device support capabilities and is responsible for device initialization - see {@link Phaser.Device.whenReady whenReady}.
  50893. *
  50894. * This class represents a singleton object that can be accessed directly as `game.device`
  50895. * (or, as a fallback, `Phaser.Device` when a game instance is not available) without the need to instantiate it.
  50896. *
  50897. * Unless otherwise noted the device capabilities are only guaranteed after initialization. Initialization
  50898. * occurs automatically and is guaranteed complete before {@link Phaser.Game} begins its "boot" phase.
  50899. * Feature detection can be modified in the {@link Phaser.Device.onInitialized onInitialized} signal.
  50900. *
  50901. * When checking features using the exposed properties only the *truth-iness* of the value should be relied upon
  50902. * unless the documentation states otherwise: properties may return `false`, `''`, `null`, or even `undefined`
  50903. * when indicating the lack of a feature.
  50904. *
  50905. * Uses elements from System.js by MrDoob and Modernizr
  50906. *
  50907. * @description
  50908. * It is not possible to instantiate the Device class manually.
  50909. *
  50910. * @class
  50911. * @protected
  50912. */
  50913. Phaser.Device = function () {
  50914. /**
  50915. * The time the device became ready.
  50916. * @property {integer} deviceReadyAt
  50917. * @protected
  50918. */
  50919. this.deviceReadyAt = 0;
  50920. /**
  50921. * The time as which initialization has completed.
  50922. * @property {boolean} initialized
  50923. * @protected
  50924. */
  50925. this.initialized = false;
  50926. // Browser / Host / Operating System
  50927. /**
  50928. * @property {boolean} desktop - Is running on a desktop?
  50929. * @default
  50930. */
  50931. this.desktop = false;
  50932. /**
  50933. * @property {boolean} iOS - Is running on iOS?
  50934. * @default
  50935. */
  50936. this.iOS = false;
  50937. /**
  50938. * @property {number} iOSVersion - If running in iOS this will contain the major version number.
  50939. * @default
  50940. */
  50941. this.iOSVersion = 0;
  50942. /**
  50943. * @property {boolean} cocoonJS - Is the game running under CocoonJS?
  50944. * @default
  50945. */
  50946. this.cocoonJS = false;
  50947. /**
  50948. * @property {boolean} cocoonJSApp - Is this game running with CocoonJS.App?
  50949. * @default
  50950. */
  50951. this.cocoonJSApp = false;
  50952. /**
  50953. * @property {boolean} cordova - Is the game running under Apache Cordova?
  50954. * @default
  50955. */
  50956. this.cordova = false;
  50957. /**
  50958. * @property {boolean} node - Is the game running under Node.js?
  50959. * @default
  50960. */
  50961. this.node = false;
  50962. /**
  50963. * @property {boolean} nodeWebkit - Is the game running under Node-Webkit?
  50964. * @default
  50965. */
  50966. this.nodeWebkit = false;
  50967. /**
  50968. * @property {boolean} electron - Is the game running under GitHub Electron?
  50969. * @default
  50970. */
  50971. this.electron = false;
  50972. /**
  50973. * @property {boolean} ejecta - Is the game running under Ejecta?
  50974. * @default
  50975. */
  50976. this.ejecta = false;
  50977. /**
  50978. * @property {boolean} crosswalk - Is the game running under the Intel Crosswalk XDK?
  50979. * @default
  50980. */
  50981. this.crosswalk = false;
  50982. /**
  50983. * @property {boolean} android - Is running on android?
  50984. * @default
  50985. */
  50986. this.android = false;
  50987. /**
  50988. * @property {boolean} chromeOS - Is running on chromeOS?
  50989. * @default
  50990. */
  50991. this.chromeOS = false;
  50992. /**
  50993. * @property {boolean} linux - Is running on linux?
  50994. * @default
  50995. */
  50996. this.linux = false;
  50997. /**
  50998. * @property {boolean} macOS - Is running on macOS?
  50999. * @default
  51000. */
  51001. this.macOS = false;
  51002. /**
  51003. * @property {boolean} windows - Is running on windows?
  51004. * @default
  51005. */
  51006. this.windows = false;
  51007. /**
  51008. * @property {boolean} windowsPhone - Is running on a Windows Phone?
  51009. * @default
  51010. */
  51011. this.windowsPhone = false;
  51012. // Features
  51013. /**
  51014. * @property {boolean} canvas - Is canvas available?
  51015. * @default
  51016. */
  51017. this.canvas = false;
  51018. /**
  51019. * @property {?boolean} canvasBitBltShift - True if canvas supports a 'copy' bitblt onto itself when the source and destination regions overlap.
  51020. * @default
  51021. */
  51022. this.canvasBitBltShift = null;
  51023. /**
  51024. * If the browser isn't capable of handling tinting with alpha this will be false.
  51025. * @property {boolean} canHandleAlpha
  51026. * @default
  51027. */
  51028. this.canHandleAlpha = false;
  51029. /**
  51030. * Whether or not the {@link http://caniuse.com/#feat=canvas-blending Canvas Blend Modes} are supported, consequently the ability to tint using the multiply method.
  51031. *
  51032. * Expect `false` in Internet Explorer <= 11.
  51033. *
  51034. * @property {boolean} canUseMultiply
  51035. * @default
  51036. */
  51037. this.canUseMultiply = false;
  51038. /**
  51039. * @property {boolean} webGL - Is webGL available?
  51040. * @default
  51041. */
  51042. this.webGL = false;
  51043. /**
  51044. * @property {boolean} file - Is file available?
  51045. * @default
  51046. */
  51047. this.file = false;
  51048. /**
  51049. * @property {boolean} fileSystem - Is fileSystem available?
  51050. * @default
  51051. */
  51052. this.fileSystem = false;
  51053. /**
  51054. * @property {boolean} localStorage - Is localStorage available?
  51055. * @default
  51056. */
  51057. this.localStorage = false;
  51058. /**
  51059. * @property {boolean} worker - Is worker available?
  51060. * @default
  51061. */
  51062. this.worker = false;
  51063. /**
  51064. * @property {boolean} css3D - Is css3D available?
  51065. * @default
  51066. */
  51067. this.css3D = false;
  51068. /**
  51069. * @property {boolean} pointerLock - Is Pointer Lock available?
  51070. * @default
  51071. */
  51072. this.pointerLock = false;
  51073. /**
  51074. * @property {boolean} typedArray - Does the browser support TypedArrays?
  51075. * @default
  51076. */
  51077. this.typedArray = false;
  51078. /**
  51079. * @property {boolean} vibration - Does the device support the Vibration API?
  51080. * @default
  51081. */
  51082. this.vibration = false;
  51083. /**
  51084. * @property {boolean} getUserMedia - Does the device support the getUserMedia API?
  51085. * @default
  51086. */
  51087. this.getUserMedia = true;
  51088. /**
  51089. * @property {boolean} quirksMode - Is the browser running in strict mode (false) or quirks mode? (true)
  51090. * @default
  51091. */
  51092. this.quirksMode = false;
  51093. // Input
  51094. /**
  51095. * @property {boolean} touch - Is touch available?
  51096. * @default
  51097. */
  51098. this.touch = false;
  51099. /**
  51100. * @property {boolean} mspointer - Is mspointer available?
  51101. * @default
  51102. */
  51103. this.mspointer = false;
  51104. /**
  51105. * @property {?string} wheelType - The newest type of Wheel/Scroll event supported: 'wheel', 'mousewheel', 'DOMMouseScroll'
  51106. * @default
  51107. * @protected
  51108. */
  51109. this.wheelEvent = null;
  51110. // Browser
  51111. /**
  51112. * @property {boolean} arora - Set to true if running in Arora.
  51113. * @default
  51114. */
  51115. this.arora = false;
  51116. /**
  51117. * @property {boolean} chrome - Set to true if running in Chrome.
  51118. * @default
  51119. */
  51120. this.chrome = false;
  51121. /**
  51122. * @property {number} chromeVersion - If running in Chrome this will contain the major version number.
  51123. * @default
  51124. */
  51125. this.chromeVersion = 0;
  51126. /**
  51127. * @property {boolean} epiphany - Set to true if running in Epiphany.
  51128. * @default
  51129. */
  51130. this.epiphany = false;
  51131. /**
  51132. * @property {boolean} firefox - Set to true if running in Firefox.
  51133. * @default
  51134. */
  51135. this.firefox = false;
  51136. /**
  51137. * @property {number} firefoxVersion - If running in Firefox this will contain the major version number.
  51138. * @default
  51139. */
  51140. this.firefoxVersion = 0;
  51141. /**
  51142. * @property {boolean} ie - Set to true if running in Internet Explorer.
  51143. * @default
  51144. */
  51145. this.ie = false;
  51146. /**
  51147. * @property {number} ieVersion - If running in Internet Explorer this will contain the major version number. Beyond IE10 you should use Device.trident and Device.tridentVersion.
  51148. * @default
  51149. */
  51150. this.ieVersion = 0;
  51151. /**
  51152. * @property {boolean} trident - Set to true if running a Trident version of Internet Explorer (IE11+)
  51153. * @default
  51154. */
  51155. this.trident = false;
  51156. /**
  51157. * @property {number} tridentVersion - If running in Internet Explorer 11 this will contain the major version number. See {@link http://msdn.microsoft.com/en-us/library/ie/ms537503(v=vs.85).aspx}
  51158. * @default
  51159. */
  51160. this.tridentVersion = 0;
  51161. /**
  51162. * @property {boolean} edge - Set to true if running in Microsoft Edge browser.
  51163. * @default
  51164. */
  51165. this.edge = false;
  51166. /**
  51167. * @property {boolean} mobileSafari - Set to true if running in Mobile Safari.
  51168. * @default
  51169. */
  51170. this.mobileSafari = false;
  51171. /**
  51172. * @property {boolean} midori - Set to true if running in Midori.
  51173. * @default
  51174. */
  51175. this.midori = false;
  51176. /**
  51177. * @property {boolean} opera - Set to true if running in Opera.
  51178. * @default
  51179. */
  51180. this.opera = false;
  51181. /**
  51182. * @property {boolean} safari - Set to true if running in Safari.
  51183. * @default
  51184. */
  51185. this.safari = false;
  51186. /**
  51187. * @property {number} safariVersion - If running in Safari this will contain the major version number.
  51188. * @default
  51189. */
  51190. this.safariVersion = 0;
  51191. /**
  51192. * @property {boolean} webApp - Set to true if running as a WebApp, i.e. within a WebView
  51193. * @default
  51194. */
  51195. this.webApp = false;
  51196. /**
  51197. * @property {boolean} silk - Set to true if running in the Silk browser (as used on the Amazon Kindle)
  51198. * @default
  51199. */
  51200. this.silk = false;
  51201. // Audio
  51202. /**
  51203. * @property {boolean} audioData - Are Audio tags available?
  51204. * @default
  51205. */
  51206. this.audioData = false;
  51207. /**
  51208. * @property {boolean} webAudio - Is the WebAudio API available?
  51209. * @default
  51210. */
  51211. this.webAudio = false;
  51212. /**
  51213. * @property {boolean} ogg - Can this device play ogg files?
  51214. * @default
  51215. */
  51216. this.ogg = false;
  51217. /**
  51218. * @property {boolean} opus - Can this device play opus files?
  51219. * @default
  51220. */
  51221. this.opus = false;
  51222. /**
  51223. * @property {boolean} mp3 - Can this device play mp3 files?
  51224. * @default
  51225. */
  51226. this.mp3 = false;
  51227. /**
  51228. * @property {boolean} wav - Can this device play wav files?
  51229. * @default
  51230. */
  51231. this.wav = false;
  51232. /**
  51233. * Can this device play m4a files?
  51234. * @property {boolean} m4a - True if this device can play m4a files.
  51235. * @default
  51236. */
  51237. this.m4a = false;
  51238. /**
  51239. * @property {boolean} webm - Can this device play webm files?
  51240. * @default
  51241. */
  51242. this.webm = false;
  51243. /**
  51244. * @property {boolean} dolby - Can this device play EC-3 Dolby Digital Plus files?
  51245. * @default
  51246. */
  51247. this.dolby = false;
  51248. // Video
  51249. /**
  51250. * @property {boolean} oggVideo - Can this device play ogg video files?
  51251. * @default
  51252. */
  51253. this.oggVideo = false;
  51254. /**
  51255. * @property {boolean} h264Video - Can this device play h264 mp4 video files?
  51256. * @default
  51257. */
  51258. this.h264Video = false;
  51259. /**
  51260. * @property {boolean} mp4Video - Can this device play h264 mp4 video files?
  51261. * @default
  51262. */
  51263. this.mp4Video = false;
  51264. /**
  51265. * @property {boolean} webmVideo - Can this device play webm video files?
  51266. * @default
  51267. */
  51268. this.webmVideo = false;
  51269. /**
  51270. * @property {boolean} vp9Video - Can this device play vp9 video files?
  51271. * @default
  51272. */
  51273. this.vp9Video = false;
  51274. /**
  51275. * @property {boolean} hlsVideo - Can this device play hls video files?
  51276. * @default
  51277. */
  51278. this.hlsVideo = false;
  51279. // Device
  51280. /**
  51281. * @property {boolean} iPhone - Is running on iPhone?
  51282. * @default
  51283. */
  51284. this.iPhone = false;
  51285. /**
  51286. * @property {boolean} iPhone4 - Is running on iPhone4?
  51287. * @default
  51288. */
  51289. this.iPhone4 = false;
  51290. /**
  51291. * @property {boolean} iPad - Is running on iPad?
  51292. * @default
  51293. */
  51294. this.iPad = false;
  51295. // Device features
  51296. /**
  51297. * @property {number} pixelRatio - PixelRatio of the host device?
  51298. * @default
  51299. */
  51300. this.pixelRatio = 0;
  51301. /**
  51302. * @property {boolean} littleEndian - Is the device big or little endian? (only detected if the browser supports TypedArrays)
  51303. * @default
  51304. */
  51305. this.littleEndian = false;
  51306. /**
  51307. * @property {boolean} LITTLE_ENDIAN - Same value as `littleEndian`.
  51308. * @default
  51309. */
  51310. this.LITTLE_ENDIAN = false;
  51311. /**
  51312. * @property {boolean} support32bit - Does the device context support 32bit pixel manipulation using array buffer views?
  51313. * @default
  51314. */
  51315. this.support32bit = false;
  51316. /**
  51317. * @property {boolean} fullscreen - Does the browser support the Full Screen API?
  51318. * @default
  51319. */
  51320. this.fullscreen = false;
  51321. /**
  51322. * @property {string} requestFullscreen - If the browser supports the Full Screen API this holds the call you need to use to activate it.
  51323. * @default
  51324. */
  51325. this.requestFullscreen = '';
  51326. /**
  51327. * @property {string} cancelFullscreen - If the browser supports the Full Screen API this holds the call you need to use to cancel it.
  51328. * @default
  51329. */
  51330. this.cancelFullscreen = '';
  51331. /**
  51332. * @property {boolean} fullscreenKeyboard - Does the browser support access to the Keyboard during Full Screen mode?
  51333. * @default
  51334. */
  51335. this.fullscreenKeyboard = false;
  51336. };
  51337. // Device is really a singleton/static entity; instantiate it
  51338. // and add new methods directly sans-prototype.
  51339. Phaser.Device = new Phaser.Device();
  51340. /**
  51341. * This signal is dispatched after device initialization occurs but before any of the ready
  51342. * callbacks (see {@link Phaser.Device.whenReady whenReady}) have been invoked.
  51343. *
  51344. * Local "patching" for a particular device can/should be done in this event.
  51345. *
  51346. * _Note_: This signal is removed after the device has been readied; if a handler has not been
  51347. * added _before_ `new Phaser.Game(..)` it is probably too late.
  51348. *
  51349. * @type {?Phaser.Signal}
  51350. * @static
  51351. */
  51352. Phaser.Device.onInitialized = new Phaser.Signal();
  51353. /**
  51354. * Add a device-ready handler and ensure the device ready sequence is started.
  51355. *
  51356. * Phaser.Device will _not_ activate or initialize until at least one `whenReady` handler is added,
  51357. * which is normally done automatically be calling `new Phaser.Game(..)`.
  51358. *
  51359. * The handler is invoked when the device is considered "ready", which may be immediately
  51360. * if the device is already "ready". See {@link Phaser.Device#deviceReadyAt deviceReadyAt}.
  51361. *
  51362. * @method
  51363. * @param {function} handler - Callback to invoke when the device is ready. It is invoked with the given context the Phaser.Device object is supplied as the first argument.
  51364. * @param {object} [context] - Context in which to invoke the handler
  51365. * @param {boolean} [nonPrimer=false] - If true the device ready check will not be started.
  51366. */
  51367. Phaser.Device.whenReady = function (callback, context, nonPrimer) {
  51368. var readyCheck = this._readyCheck;
  51369. if (this.deviceReadyAt || !readyCheck)
  51370. {
  51371. callback.call(context, this);
  51372. }
  51373. else if (readyCheck._monitor || nonPrimer)
  51374. {
  51375. readyCheck._queue = readyCheck._queue || [];
  51376. readyCheck._queue.push([callback, context]);
  51377. }
  51378. else
  51379. {
  51380. readyCheck._monitor = readyCheck.bind(this);
  51381. readyCheck._queue = readyCheck._queue || [];
  51382. readyCheck._queue.push([callback, context]);
  51383. var cordova = typeof window.cordova !== 'undefined';
  51384. var cocoonJS = navigator['isCocoonJS'];
  51385. if (document.readyState === 'complete' || document.readyState === 'interactive')
  51386. {
  51387. // Why is there an additional timeout here?
  51388. window.setTimeout(readyCheck._monitor, 0);
  51389. }
  51390. else if (cordova && !cocoonJS)
  51391. {
  51392. // Ref. http://docs.phonegap.com/en/3.5.0/cordova_events_events.md.html#deviceready
  51393. // Cordova, but NOT Cocoon?
  51394. document.addEventListener('deviceready', readyCheck._monitor, false);
  51395. }
  51396. else
  51397. {
  51398. document.addEventListener('DOMContentLoaded', readyCheck._monitor, false);
  51399. window.addEventListener('load', readyCheck._monitor, false);
  51400. }
  51401. }
  51402. };
  51403. /**
  51404. * Internal method used for checking when the device is ready.
  51405. * This function is removed from Phaser.Device when the device becomes ready.
  51406. *
  51407. * @method
  51408. * @private
  51409. */
  51410. Phaser.Device._readyCheck = function () {
  51411. var readyCheck = this._readyCheck;
  51412. if (!document.body)
  51413. {
  51414. window.setTimeout(readyCheck._monitor, 20);
  51415. }
  51416. else if (!this.deviceReadyAt)
  51417. {
  51418. this.deviceReadyAt = Date.now();
  51419. document.removeEventListener('deviceready', readyCheck._monitor);
  51420. document.removeEventListener('DOMContentLoaded', readyCheck._monitor);
  51421. window.removeEventListener('load', readyCheck._monitor);
  51422. this._initialize();
  51423. this.initialized = true;
  51424. this.onInitialized.dispatch(this);
  51425. var item;
  51426. while ((item = readyCheck._queue.shift()))
  51427. {
  51428. var callback = item[0];
  51429. var context = item[1];
  51430. callback.call(context, this);
  51431. }
  51432. // Remove no longer useful methods and properties.
  51433. this._readyCheck = null;
  51434. this._initialize = null;
  51435. this.onInitialized = null;
  51436. }
  51437. };
  51438. /**
  51439. * Internal method to initialize the capability checks.
  51440. * This function is removed from Phaser.Device once the device is initialized.
  51441. *
  51442. * @method
  51443. * @private
  51444. */
  51445. Phaser.Device._initialize = function () {
  51446. var device = this;
  51447. /**
  51448. * Check which OS is game running on.
  51449. */
  51450. function _checkOS () {
  51451. var ua = navigator.userAgent;
  51452. if (/Playstation Vita/.test(ua))
  51453. {
  51454. device.vita = true;
  51455. }
  51456. else if (/Kindle/.test(ua) || /\bKF[A-Z][A-Z]+/.test(ua) || /Silk.*Mobile Safari/.test(ua))
  51457. {
  51458. device.kindle = true;
  51459. // This will NOT detect early generations of Kindle Fire, I think there is no reliable way...
  51460. // E.g. "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-80) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true"
  51461. }
  51462. else if (/Android/.test(ua))
  51463. {
  51464. device.android = true;
  51465. }
  51466. else if (/CrOS/.test(ua))
  51467. {
  51468. device.chromeOS = true;
  51469. }
  51470. else if (/iP[ao]d|iPhone/i.test(ua))
  51471. {
  51472. device.iOS = true;
  51473. (navigator.appVersion).match(/OS (\d+)/);
  51474. device.iOSVersion = parseInt(RegExp.$1, 10);
  51475. }
  51476. else if (/Linux/.test(ua))
  51477. {
  51478. device.linux = true;
  51479. }
  51480. else if (/Mac OS/.test(ua))
  51481. {
  51482. device.macOS = true;
  51483. }
  51484. else if (/Windows/.test(ua))
  51485. {
  51486. device.windows = true;
  51487. }
  51488. if (/Windows Phone/i.test(ua) || /IEMobile/i.test(ua))
  51489. {
  51490. device.android = false;
  51491. device.iOS = false;
  51492. device.macOS = false;
  51493. device.windows = true;
  51494. device.windowsPhone = true;
  51495. }
  51496. var silk = /Silk/.test(ua); // detected in browsers
  51497. if (device.windows || device.macOS || (device.linux && !silk) || device.chromeOS)
  51498. {
  51499. device.desktop = true;
  51500. }
  51501. // Windows Phone / Table reset
  51502. if (device.windowsPhone || ((/Windows NT/i.test(ua)) && (/Touch/i.test(ua))))
  51503. {
  51504. device.desktop = false;
  51505. }
  51506. }
  51507. /**
  51508. * Checks if the browser correctly supports putImageData alpha channels.
  51509. * If the browser isn't capable of handling tinting with alpha, `Device.canHandleAlpha` will be false.
  51510. * Also checks whether the Canvas BlendModes are supported by the current browser for drawImage.
  51511. */
  51512. function _checkCanvasFeatures () {
  51513. var canvas = Phaser.CanvasPool.create(this, 6, 1);
  51514. var context = canvas.getContext('2d');
  51515. context.fillStyle = 'rgba(10, 20, 30, 0.5)';
  51516. // Draw a single pixel
  51517. context.fillRect(0, 0, 1, 1);
  51518. // Get the color values
  51519. var s1 = context.getImageData(0, 0, 1, 1);
  51520. if (s1)
  51521. {
  51522. // Plot them to x2
  51523. context.putImageData(s1, 1, 0);
  51524. // Get those values
  51525. var s2 = context.getImageData(1, 0, 1, 1);
  51526. // Compare and set
  51527. device.canHandleAlpha = (
  51528. s2.data[0] === s1.data[0] &&
  51529. s2.data[1] === s1.data[1] &&
  51530. s2.data[2] === s1.data[2] &&
  51531. s2.data[3] === s1.data[3]
  51532. );
  51533. }
  51534. // Checks whether the Canvas BlendModes are supported by the current browser for drawImage.
  51535. context.globalCompositeOperation = 'multiply';
  51536. device.canUseMultiply = (context.globalCompositeOperation === 'multiply');
  51537. Phaser.CanvasPool.removeByCanvas(canvas);
  51538. PIXI.CanvasTinter.tintMethod = (device.canUseMultiply) ? PIXI.CanvasTinter.tintWithMultiply : PIXI.CanvasTinter.tintWithPerPixel;
  51539. }
  51540. /**
  51541. * Check HTML5 features of the host environment.
  51542. */
  51543. function _checkFeatures () {
  51544. device.canvas = !!window['CanvasRenderingContext2D'] || device.cocoonJS;
  51545. try {
  51546. device.localStorage = !!localStorage.getItem;
  51547. } catch (error) {
  51548. device.localStorage = false;
  51549. }
  51550. device.file = !!window['File'] && !!window['FileReader'] && !!window['FileList'] && !!window['Blob'];
  51551. device.fileSystem = !!window['requestFileSystem'];
  51552. device.webGL = ( function () { try { var canvas = document.createElement( 'canvas' ); /*Force screencanvas to false*/ canvas.screencanvas = false; return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )();
  51553. device.webGL = !!device.webGL;
  51554. device.worker = !!window['Worker'];
  51555. device.pointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
  51556. device.quirksMode = (document.compatMode === 'CSS1Compat') ? false : true;
  51557. navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
  51558. window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
  51559. device.getUserMedia = device.getUserMedia && !!navigator.getUserMedia && !!window.URL;
  51560. // Older versions of firefox (< 21) apparently claim support but user media does not actually work
  51561. if (device.firefox && device.firefoxVersion < 21)
  51562. {
  51563. device.getUserMedia = false;
  51564. }
  51565. // TODO: replace canvasBitBltShift detection with actual feature check
  51566. // Excludes iOS versions as they generally wrap UIWebView (eg. Safari WebKit) and it
  51567. // is safer to not try and use the fast copy-over method.
  51568. if (!device.iOS && (device.ie || device.firefox || device.chrome))
  51569. {
  51570. device.canvasBitBltShift = true;
  51571. }
  51572. // Known not to work
  51573. if (device.safari || device.mobileSafari)
  51574. {
  51575. device.canvasBitBltShift = false;
  51576. }
  51577. }
  51578. /**
  51579. * Checks/configures various input.
  51580. */
  51581. function _checkInput () {
  51582. if ('ontouchstart' in document.documentElement || (window.navigator.maxTouchPoints && window.navigator.maxTouchPoints >= 1))
  51583. {
  51584. device.touch = true;
  51585. }
  51586. if (window.PointerEvent || window.MSPointerEvent || window.navigator.msPointerEnabled || window.navigator.pointerEnabled)
  51587. {
  51588. device.mspointer = true;
  51589. }
  51590. if (!device.cocoonJS)
  51591. {
  51592. // See https://developer.mozilla.org/en-US/docs/Web/Events/wheel
  51593. if ('onwheel' in window || (device.ie && 'WheelEvent' in window))
  51594. {
  51595. // DOM3 Wheel Event: FF 17+, IE 9+, Chrome 31+, Safari 7+
  51596. device.wheelEvent = 'wheel';
  51597. }
  51598. else if ('onmousewheel' in window)
  51599. {
  51600. // Non-FF legacy: IE 6-9, Chrome 1-31, Safari 5-7.
  51601. device.wheelEvent = 'mousewheel';
  51602. }
  51603. else if (device.firefox && 'MouseScrollEvent' in window)
  51604. {
  51605. // FF prior to 17. This should probably be scrubbed.
  51606. device.wheelEvent = 'DOMMouseScroll';
  51607. }
  51608. }
  51609. }
  51610. /**
  51611. * Checks for support of the Full Screen API.
  51612. */
  51613. function _checkFullScreenSupport () {
  51614. var fs = [
  51615. 'requestFullscreen',
  51616. 'requestFullScreen',
  51617. 'webkitRequestFullscreen',
  51618. 'webkitRequestFullScreen',
  51619. 'msRequestFullscreen',
  51620. 'msRequestFullScreen',
  51621. 'mozRequestFullScreen',
  51622. 'mozRequestFullscreen'
  51623. ];
  51624. var element = document.createElement('div');
  51625. for (var i = 0; i < fs.length; i++)
  51626. {
  51627. if (element[fs[i]])
  51628. {
  51629. device.fullscreen = true;
  51630. device.requestFullscreen = fs[i];
  51631. break;
  51632. }
  51633. }
  51634. var cfs = [
  51635. 'cancelFullScreen',
  51636. 'exitFullscreen',
  51637. 'webkitCancelFullScreen',
  51638. 'webkitExitFullscreen',
  51639. 'msCancelFullScreen',
  51640. 'msExitFullscreen',
  51641. 'mozCancelFullScreen',
  51642. 'mozExitFullscreen'
  51643. ];
  51644. if (device.fullscreen)
  51645. {
  51646. for (var i = 0; i < cfs.length; i++)
  51647. {
  51648. if (document[cfs[i]])
  51649. {
  51650. device.cancelFullscreen = cfs[i];
  51651. break;
  51652. }
  51653. }
  51654. }
  51655. // Keyboard Input?
  51656. if (window['Element'] && Element['ALLOW_KEYBOARD_INPUT'])
  51657. {
  51658. device.fullscreenKeyboard = true;
  51659. }
  51660. }
  51661. /**
  51662. * Check what browser is game running in.
  51663. */
  51664. function _checkBrowser () {
  51665. var ua = navigator.userAgent;
  51666. if (/Arora/.test(ua))
  51667. {
  51668. device.arora = true;
  51669. }
  51670. else if (/Edge\/\d+/.test(ua))
  51671. {
  51672. device.edge = true;
  51673. }
  51674. else if (/Chrome\/(\d+)/.test(ua) && !device.windowsPhone)
  51675. {
  51676. device.chrome = true;
  51677. device.chromeVersion = parseInt(RegExp.$1, 10);
  51678. }
  51679. else if (/Epiphany/.test(ua))
  51680. {
  51681. device.epiphany = true;
  51682. }
  51683. else if (/Firefox\D+(\d+)/.test(ua))
  51684. {
  51685. device.firefox = true;
  51686. device.firefoxVersion = parseInt(RegExp.$1, 10);
  51687. }
  51688. else if (/AppleWebKit/.test(ua) && device.iOS)
  51689. {
  51690. device.mobileSafari = true;
  51691. }
  51692. else if (/MSIE (\d+\.\d+);/.test(ua))
  51693. {
  51694. device.ie = true;
  51695. device.ieVersion = parseInt(RegExp.$1, 10);
  51696. }
  51697. else if (/Midori/.test(ua))
  51698. {
  51699. device.midori = true;
  51700. }
  51701. else if (/Opera/.test(ua))
  51702. {
  51703. device.opera = true;
  51704. }
  51705. else if (/Safari\/(\d+)/.test(ua) && !device.windowsPhone)
  51706. {
  51707. device.safari = true;
  51708. if (/Version\/(\d+)\./.test(ua))
  51709. {
  51710. device.safariVersion = parseInt(RegExp.$1, 10);
  51711. }
  51712. }
  51713. else if (/Trident\/(\d+\.\d+)(.*)rv:(\d+\.\d+)/.test(ua))
  51714. {
  51715. device.ie = true;
  51716. device.trident = true;
  51717. device.tridentVersion = parseInt(RegExp.$1, 10);
  51718. device.ieVersion = parseInt(RegExp.$3, 10);
  51719. }
  51720. // Silk gets its own if clause because its ua also contains 'Safari'
  51721. if (/Silk/.test(ua))
  51722. {
  51723. device.silk = true;
  51724. }
  51725. // WebApp mode in iOS
  51726. if (navigator['standalone'])
  51727. {
  51728. device.webApp = true;
  51729. }
  51730. if (typeof window.cordova !== 'undefined')
  51731. {
  51732. device.cordova = true;
  51733. }
  51734. if (typeof process !== 'undefined' && typeof require !== 'undefined')
  51735. {
  51736. device.node = true;
  51737. }
  51738. if (device.node && typeof process.versions === 'object')
  51739. {
  51740. device.nodeWebkit = !!process.versions['node-webkit'];
  51741. device.electron = !!process.versions.electron;
  51742. }
  51743. if (navigator['isCocoonJS'])
  51744. {
  51745. device.cocoonJS = true;
  51746. }
  51747. if (device.cocoonJS)
  51748. {
  51749. try {
  51750. device.cocoonJSApp = (typeof CocoonJS !== 'undefined');
  51751. }
  51752. catch(error)
  51753. {
  51754. device.cocoonJSApp = false;
  51755. }
  51756. }
  51757. if (typeof window.ejecta !== 'undefined')
  51758. {
  51759. device.ejecta = true;
  51760. }
  51761. if (/Crosswalk/.test(ua))
  51762. {
  51763. device.crosswalk = true;
  51764. }
  51765. }
  51766. /**
  51767. * Check video support.
  51768. */
  51769. function _checkVideo () {
  51770. var videoElement = document.createElement("video");
  51771. var result = false;
  51772. try {
  51773. if (result = !!videoElement.canPlayType)
  51774. {
  51775. if (videoElement.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, ''))
  51776. {
  51777. device.oggVideo = true;
  51778. }
  51779. if (videoElement.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, ''))
  51780. {
  51781. // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
  51782. device.h264Video = true;
  51783. device.mp4Video = true;
  51784. }
  51785. if (videoElement.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, ''))
  51786. {
  51787. device.webmVideo = true;
  51788. }
  51789. if (videoElement.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, ''))
  51790. {
  51791. device.vp9Video = true;
  51792. }
  51793. if (videoElement.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, ''))
  51794. {
  51795. device.hlsVideo = true;
  51796. }
  51797. }
  51798. } catch (e) {}
  51799. }
  51800. /**
  51801. * Check audio support.
  51802. */
  51803. function _checkAudio () {
  51804. device.audioData = !!(window['Audio']);
  51805. device.webAudio = !!(window['AudioContext'] || window['webkitAudioContext']);
  51806. var audioElement = document.createElement('audio');
  51807. var result = false;
  51808. try {
  51809. if (result = !!audioElement.canPlayType)
  51810. {
  51811. if (audioElement.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''))
  51812. {
  51813. device.ogg = true;
  51814. }
  51815. if (audioElement.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, '') || audioElement.canPlayType('audio/opus;').replace(/^no$/, ''))
  51816. {
  51817. device.opus = true;
  51818. }
  51819. if (audioElement.canPlayType('audio/mpeg;').replace(/^no$/, ''))
  51820. {
  51821. device.mp3 = true;
  51822. }
  51823. // Mimetypes accepted:
  51824. // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
  51825. // bit.ly/iphoneoscodecs
  51826. if (audioElement.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''))
  51827. {
  51828. device.wav = true;
  51829. }
  51830. if (audioElement.canPlayType('audio/x-m4a;') || audioElement.canPlayType('audio/aac;').replace(/^no$/, ''))
  51831. {
  51832. device.m4a = true;
  51833. }
  51834. if (audioElement.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''))
  51835. {
  51836. device.webm = true;
  51837. }
  51838. if (audioElement.canPlayType('audio/mp4;codecs="ec-3"') !== '')
  51839. {
  51840. if (device.edge)
  51841. {
  51842. device.dolby = true;
  51843. }
  51844. else if (device.safari && device.safariVersion >= 9)
  51845. {
  51846. if (/Mac OS X (\d+)_(\d+)/.test(navigator.userAgent))
  51847. {
  51848. var major = parseInt(RegExp.$1, 10);
  51849. var minor = parseInt(RegExp.$2, 10);
  51850. if ((major === 10 && minor >= 11) || major > 10)
  51851. {
  51852. device.dolby = true;
  51853. }
  51854. }
  51855. }
  51856. }
  51857. }
  51858. } catch (e) {
  51859. }
  51860. }
  51861. /**
  51862. * Check Little or Big Endian system.
  51863. *
  51864. * @author Matt DesLauriers (@mattdesl)
  51865. */
  51866. function _checkIsLittleEndian () {
  51867. var a = new ArrayBuffer(4);
  51868. var b = new Uint8Array(a);
  51869. var c = new Uint32Array(a);
  51870. b[0] = 0xa1;
  51871. b[1] = 0xb2;
  51872. b[2] = 0xc3;
  51873. b[3] = 0xd4;
  51874. if (c[0] === 0xd4c3b2a1)
  51875. {
  51876. return true;
  51877. }
  51878. if (c[0] === 0xa1b2c3d4)
  51879. {
  51880. return false;
  51881. }
  51882. else
  51883. {
  51884. // Could not determine endianness
  51885. return null;
  51886. }
  51887. }
  51888. /**
  51889. * Test to see if ImageData uses CanvasPixelArray or Uint8ClampedArray.
  51890. *
  51891. * @author Matt DesLauriers (@mattdesl)
  51892. */
  51893. function _checkIsUint8ClampedImageData () {
  51894. if (Uint8ClampedArray === undefined)
  51895. {
  51896. return false;
  51897. }
  51898. var elem = Phaser.CanvasPool.create(this, 1, 1);
  51899. var ctx = elem.getContext('2d');
  51900. if (!ctx)
  51901. {
  51902. return false;
  51903. }
  51904. var image = ctx.createImageData(1, 1);
  51905. Phaser.CanvasPool.remove(this);
  51906. return image.data instanceof Uint8ClampedArray;
  51907. }
  51908. /**
  51909. * Check PixelRatio, iOS device, Vibration API, ArrayBuffers and endianess.
  51910. */
  51911. function _checkDevice () {
  51912. device.pixelRatio = window['devicePixelRatio'] || 1;
  51913. device.iPhone = navigator.userAgent.toLowerCase().indexOf('iphone') !== -1;
  51914. device.iPhone4 = (device.pixelRatio === 2 && device.iPhone);
  51915. device.iPad = navigator.userAgent.toLowerCase().indexOf('ipad') !== -1;
  51916. if (typeof Int8Array !== 'undefined')
  51917. {
  51918. device.typedArray = true;
  51919. }
  51920. else
  51921. {
  51922. device.typedArray = false;
  51923. }
  51924. if (typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined' && typeof Uint32Array !== 'undefined')
  51925. {
  51926. device.littleEndian = _checkIsLittleEndian();
  51927. device.LITTLE_ENDIAN = device.littleEndian;
  51928. }
  51929. device.support32bit = (typeof ArrayBuffer !== 'undefined' && typeof Uint8ClampedArray !== 'undefined' && typeof Int32Array !== 'undefined' && device.littleEndian !== null && _checkIsUint8ClampedImageData());
  51930. navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate;
  51931. if (navigator.vibrate)
  51932. {
  51933. device.vibration = true;
  51934. }
  51935. }
  51936. /**
  51937. * Check whether the host environment support 3D CSS.
  51938. */
  51939. function _checkCSS3D () {
  51940. var el = document.createElement('p');
  51941. var has3d;
  51942. var transforms = {
  51943. 'webkitTransform': '-webkit-transform',
  51944. 'OTransform': '-o-transform',
  51945. 'msTransform': '-ms-transform',
  51946. 'MozTransform': '-moz-transform',
  51947. 'transform': 'transform'
  51948. };
  51949. // Add it to the body to get the computed style.
  51950. document.body.insertBefore(el, null);
  51951. for (var t in transforms)
  51952. {
  51953. if (el.style[t] !== undefined)
  51954. {
  51955. el.style[t] = "translate3d(1px,1px,1px)";
  51956. has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
  51957. }
  51958. }
  51959. document.body.removeChild(el);
  51960. device.css3D = (has3d !== undefined && has3d.length > 0 && has3d !== "none");
  51961. }
  51962. // Run the checks
  51963. _checkOS();
  51964. _checkBrowser();
  51965. _checkAudio();
  51966. _checkVideo();
  51967. _checkCSS3D();
  51968. _checkDevice();
  51969. _checkFeatures();
  51970. _checkCanvasFeatures();
  51971. _checkFullScreenSupport();
  51972. _checkInput();
  51973. };
  51974. /**
  51975. * Check whether the host environment can play audio.
  51976. *
  51977. * @method canPlayAudio
  51978. * @memberof Phaser.Device.prototype
  51979. * @param {string} type - One of 'mp3, 'ogg', 'm4a', 'wav', 'webm' or 'opus'.
  51980. * @return {boolean} True if the given file type is supported by the browser, otherwise false.
  51981. */
  51982. Phaser.Device.canPlayAudio = function (type) {
  51983. if (type === 'mp3' && this.mp3)
  51984. {
  51985. return true;
  51986. }
  51987. else if (type === 'ogg' && (this.ogg || this.opus))
  51988. {
  51989. return true;
  51990. }
  51991. else if (type === 'm4a' && this.m4a)
  51992. {
  51993. return true;
  51994. }
  51995. else if (type === 'opus' && this.opus)
  51996. {
  51997. return true;
  51998. }
  51999. else if (type === 'wav' && this.wav)
  52000. {
  52001. return true;
  52002. }
  52003. else if (type === 'webm' && this.webm)
  52004. {
  52005. return true;
  52006. }
  52007. else if (type === 'mp4' && this.dolby)
  52008. {
  52009. return true;
  52010. }
  52011. return false;
  52012. };
  52013. /**
  52014. * Check whether the host environment can play video files.
  52015. *
  52016. * @method canPlayVideo
  52017. * @memberof Phaser.Device.prototype
  52018. * @param {string} type - One of 'mp4, 'ogg', 'webm' or 'mpeg'.
  52019. * @return {boolean} True if the given file type is supported by the browser, otherwise false.
  52020. */
  52021. Phaser.Device.canPlayVideo = function (type) {
  52022. if (type === 'webm' && (this.webmVideo || this.vp9Video))
  52023. {
  52024. return true;
  52025. }
  52026. else if (type === 'mp4' && (this.mp4Video || this.h264Video))
  52027. {
  52028. return true;
  52029. }
  52030. else if ((type === 'ogg' || type === 'ogv') && this.oggVideo)
  52031. {
  52032. return true;
  52033. }
  52034. else if (type === 'mpeg' && this.hlsVideo)
  52035. {
  52036. return true;
  52037. }
  52038. return false;
  52039. };
  52040. /**
  52041. * Whether the device plays audio/video only in response to a user touch event.
  52042. *
  52043. * @method needsTouchUnlock
  52044. * @memberof Phaser.Device.prototype
  52045. * @return {boolean}
  52046. */
  52047. Phaser.Device.needsTouchUnlock = function () {
  52048. return !!(!this.cocoonJS && (this.iOS || this.android) || (window.PhaserGlobal && window.PhaserGlobal.fakeiOSTouchLock));
  52049. };
  52050. /**
  52051. * Returns false.
  52052. *
  52053. * @deprecated
  52054. * @method isConsoleOpen
  52055. * @memberof Phaser.Device.prototype
  52056. * @return false
  52057. */
  52058. Phaser.Device.isConsoleOpen = function () {
  52059. console.warn('Phaser.Device.isConsoleOpen is deprecated and will be removed.');
  52060. return false;
  52061. };
  52062. /**
  52063. * Detect if the host is a an Android Stock browser.
  52064. * This is available before the device "ready" event.
  52065. *
  52066. * Authors might want to scale down on effects and switch to the CANVAS rendering method on those devices.
  52067. *
  52068. * @example
  52069. * var defaultRenderingMode = Phaser.Device.isAndroidStockBrowser() ? Phaser.CANVAS : Phaser.AUTO;
  52070. *
  52071. * @method isAndroidStockBrowser
  52072. * @memberof Phaser.Device.prototype
  52073. */
  52074. Phaser.Device.isAndroidStockBrowser = function () {
  52075. var matches = window.navigator.userAgent.match(/Android.*AppleWebKit\/([\d.]+)/);
  52076. return matches && matches[1] < 537;
  52077. };
  52078. /**
  52079. * @author Richard Davey <rich@photonstorm.com>
  52080. * @copyright 2016 Photon Storm Ltd.
  52081. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  52082. */
  52083. /**
  52084. * The Canvas class handles everything related to creating the `canvas` DOM tag that Phaser will use,
  52085. * including styles, offset and aspect ratio.
  52086. *
  52087. * @class Phaser.Canvas
  52088. * @static
  52089. */
  52090. Phaser.Canvas = {
  52091. /**
  52092. * Creates a `canvas` DOM element. The element is not automatically added to the document.
  52093. *
  52094. * @method Phaser.Canvas.create
  52095. * @param {object} parent - The object that will own the canvas that is created.
  52096. * @param {number} [width=256] - The width of the canvas element.
  52097. * @param {number} [height=256] - The height of the canvas element..
  52098. * @param {string} [id=(none)] - If specified, and not the empty string, this will be set as the ID of the canvas element. Otherwise no ID will be set.
  52099. * @param {boolean} [skipPool=false] - If `true` the canvas will not be placed in the CanvasPool global.
  52100. * @return {HTMLCanvasElement} The newly created canvas element.
  52101. */
  52102. create: function (parent, width, height, id, skipPool) {
  52103. width = width || 256;
  52104. height = height || 256;
  52105. var canvas = (skipPool) ? document.createElement('canvas') : Phaser.CanvasPool.create(parent, width, height);
  52106. if (typeof id === 'string' && id !== '')
  52107. {
  52108. canvas.id = id;
  52109. }
  52110. canvas.width = width;
  52111. canvas.height = height;
  52112. canvas.style.display = 'block';
  52113. return canvas;
  52114. },
  52115. /**
  52116. * Sets the background color behind the canvas. This changes the canvas style property.
  52117. *
  52118. * @method Phaser.Canvas.setBackgroundColor
  52119. * @param {HTMLCanvasElement} canvas - The canvas to set the background color on.
  52120. * @param {string} [color='rgb(0,0,0)'] - The color to set. Can be in the format 'rgb(r,g,b)', or '#RRGGBB' or any valid CSS color.
  52121. * @return {HTMLCanvasElement} Returns the source canvas.
  52122. */
  52123. setBackgroundColor: function (canvas, color) {
  52124. color = color || 'rgb(0,0,0)';
  52125. canvas.style.backgroundColor = color;
  52126. return canvas;
  52127. },
  52128. /**
  52129. * Sets the touch-action property on the canvas style. Can be used to disable default browser touch actions.
  52130. *
  52131. * @method Phaser.Canvas.setTouchAction
  52132. * @param {HTMLCanvasElement} canvas - The canvas to set the touch action on.
  52133. * @param {string} [value] - The touch action to set. Defaults to 'none'.
  52134. * @return {HTMLCanvasElement} The source canvas.
  52135. */
  52136. setTouchAction: function (canvas, value) {
  52137. value = value || 'none';
  52138. canvas.style.msTouchAction = value;
  52139. canvas.style['ms-touch-action'] = value;
  52140. canvas.style['touch-action'] = value;
  52141. return canvas;
  52142. },
  52143. /**
  52144. * Sets the user-select property on the canvas style. Can be used to disable default browser selection actions.
  52145. *
  52146. * @method Phaser.Canvas.setUserSelect
  52147. * @param {HTMLCanvasElement} canvas - The canvas to set the touch action on.
  52148. * @param {string} [value] - The touch action to set. Defaults to 'none'.
  52149. * @return {HTMLCanvasElement} The source canvas.
  52150. */
  52151. setUserSelect: function (canvas, value) {
  52152. value = value || 'none';
  52153. canvas.style['-webkit-touch-callout'] = value;
  52154. canvas.style['-webkit-user-select'] = value;
  52155. canvas.style['-khtml-user-select'] = value;
  52156. canvas.style['-moz-user-select'] = value;
  52157. canvas.style['-ms-user-select'] = value;
  52158. canvas.style['user-select'] = value;
  52159. canvas.style['-webkit-tap-highlight-color'] = 'rgba(0, 0, 0, 0)';
  52160. return canvas;
  52161. },
  52162. /**
  52163. * Adds the given canvas element to the DOM. The canvas will be added as a child of the given parent.
  52164. * If no parent is given it will be added as a child of the document.body.
  52165. *
  52166. * @method Phaser.Canvas.addToDOM
  52167. * @param {HTMLCanvasElement} canvas - The canvas to be added to the DOM.
  52168. * @param {string|HTMLElement} parent - The DOM element to add the canvas to.
  52169. * @param {boolean} [overflowHidden=true] - If set to true it will add the overflow='hidden' style to the parent DOM element.
  52170. * @return {HTMLCanvasElement} Returns the source canvas.
  52171. */
  52172. addToDOM: function (canvas, parent, overflowHidden) {
  52173. var target;
  52174. if (overflowHidden === undefined) { overflowHidden = true; }
  52175. if (parent)
  52176. {
  52177. if (typeof parent === 'string')
  52178. {
  52179. // hopefully an element ID
  52180. target = document.getElementById(parent);
  52181. }
  52182. else if (typeof parent === 'object' && parent.nodeType === 1)
  52183. {
  52184. // quick test for a HTMLelement
  52185. target = parent;
  52186. }
  52187. }
  52188. // Fallback, covers an invalid ID and a non HTMLelement object
  52189. if (!target)
  52190. {
  52191. target = document.body;
  52192. }
  52193. if (overflowHidden && target.style)
  52194. {
  52195. target.style.overflow = 'hidden';
  52196. }
  52197. target.appendChild(canvas);
  52198. return canvas;
  52199. },
  52200. /**
  52201. * Removes the given canvas element from the DOM.
  52202. *
  52203. * @method Phaser.Canvas.removeFromDOM
  52204. * @param {HTMLCanvasElement} canvas - The canvas to be removed from the DOM.
  52205. */
  52206. removeFromDOM: function (canvas) {
  52207. if (canvas.parentNode)
  52208. {
  52209. canvas.parentNode.removeChild(canvas);
  52210. }
  52211. },
  52212. /**
  52213. * Sets the transform of the given canvas to the matrix values provided.
  52214. *
  52215. * @method Phaser.Canvas.setTransform
  52216. * @param {CanvasRenderingContext2D} context - The context to set the transform on.
  52217. * @param {number} translateX - The value to translate horizontally by.
  52218. * @param {number} translateY - The value to translate vertically by.
  52219. * @param {number} scaleX - The value to scale horizontally by.
  52220. * @param {number} scaleY - The value to scale vertically by.
  52221. * @param {number} skewX - The value to skew horizontaly by.
  52222. * @param {number} skewY - The value to skew vertically by.
  52223. * @return {CanvasRenderingContext2D} Returns the source context.
  52224. */
  52225. setTransform: function (context, translateX, translateY, scaleX, scaleY, skewX, skewY) {
  52226. context.setTransform(scaleX, skewX, skewY, scaleY, translateX, translateY);
  52227. return context;
  52228. },
  52229. /**
  52230. * Sets the Image Smoothing property on the given context. Set to false to disable image smoothing.
  52231. * By default browsers have image smoothing enabled, which isn't always what you visually want, especially
  52232. * when using pixel art in a game. Note that this sets the property on the context itself, so that any image
  52233. * drawn to the context will be affected. This sets the property across all current browsers but support is
  52234. * patchy on earlier browsers, especially on mobile.
  52235. *
  52236. * @method Phaser.Canvas.setSmoothingEnabled
  52237. * @param {CanvasRenderingContext2D} context - The context to enable or disable the image smoothing on.
  52238. * @param {boolean} value - If set to true it will enable image smoothing, false will disable it.
  52239. * @return {CanvasRenderingContext2D} Returns the source context.
  52240. */
  52241. setSmoothingEnabled: function (context, value) {
  52242. var s = Phaser.Canvas.getSmoothingPrefix(context);
  52243. if (s)
  52244. {
  52245. context[s] = value;
  52246. }
  52247. return context;
  52248. },
  52249. /**
  52250. * Gets the Smoothing Enabled vendor prefix being used on the given context, or null if not set.
  52251. *
  52252. * @method Phaser.Canvas.getSmoothingPrefix
  52253. * @param {CanvasRenderingContext2D} context - The context to enable or disable the image smoothing on.
  52254. * @return {string|null} Returns the smoothingEnabled vendor prefix, or null if not set on the context.
  52255. */
  52256. getSmoothingPrefix: function (context) {
  52257. var vendor = [ 'i', 'webkitI', 'msI', 'mozI', 'oI' ];
  52258. for (var prefix in vendor)
  52259. {
  52260. var s = vendor[prefix] + 'mageSmoothingEnabled';
  52261. if (s in context)
  52262. {
  52263. return s;
  52264. }
  52265. }
  52266. return null;
  52267. },
  52268. /**
  52269. * Returns `true` if the given context has image smoothing enabled, otherwise returns `false`.
  52270. *
  52271. * @method Phaser.Canvas.getSmoothingEnabled
  52272. * @param {CanvasRenderingContext2D} context - The context to check for smoothing on.
  52273. * @return {boolean} True if the given context has image smoothing enabled, otherwise false.
  52274. */
  52275. getSmoothingEnabled: function (context) {
  52276. var s = Phaser.Canvas.getSmoothingPrefix(context);
  52277. if (s)
  52278. {
  52279. return context[s];
  52280. }
  52281. },
  52282. /**
  52283. * Sets the CSS image-rendering property on the given canvas to be 'crisp' (aka 'optimize contrast' on webkit).
  52284. * Note that if this doesn't given the desired result then see the setSmoothingEnabled.
  52285. *
  52286. * @method Phaser.Canvas.setImageRenderingCrisp
  52287. * @param {HTMLCanvasElement} canvas - The canvas to set image-rendering crisp on.
  52288. * @return {HTMLCanvasElement} Returns the source canvas.
  52289. */
  52290. setImageRenderingCrisp: function (canvas) {
  52291. var types = [ 'optimizeSpeed', 'crisp-edges', '-moz-crisp-edges', '-webkit-optimize-contrast', 'optimize-contrast', 'pixelated' ];
  52292. for (var i = 0; i < types.length; i++)
  52293. {
  52294. canvas.style['image-rendering'] = types[i];
  52295. }
  52296. canvas.style.msInterpolationMode = 'nearest-neighbor';
  52297. return canvas;
  52298. },
  52299. /**
  52300. * Sets the CSS image-rendering property on the given canvas to be 'bicubic' (aka 'auto').
  52301. * Note that if this doesn't given the desired result then see the CanvasUtils.setSmoothingEnabled method.
  52302. *
  52303. * @method Phaser.Canvas.setImageRenderingBicubic
  52304. * @param {HTMLCanvasElement} canvas The canvas to set image-rendering bicubic on.
  52305. * @return {HTMLCanvasElement} Returns the source canvas.
  52306. */
  52307. setImageRenderingBicubic: function (canvas) {
  52308. canvas.style['image-rendering'] = 'auto';
  52309. canvas.style.msInterpolationMode = 'bicubic';
  52310. return canvas;
  52311. }
  52312. };
  52313. /**
  52314. * @author Richard Davey <rich@photonstorm.com>
  52315. * @copyright 2016 Photon Storm Ltd.
  52316. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  52317. */
  52318. /**
  52319. * Abstracts away the use of RAF or setTimeOut for the core game update loop.
  52320. *
  52321. * @class Phaser.RequestAnimationFrame
  52322. * @constructor
  52323. * @param {Phaser.Game} game - A reference to the currently running game.
  52324. * @param {boolean} [forceSetTimeOut=false] - Tell Phaser to use setTimeOut even if raf is available.
  52325. */
  52326. Phaser.RequestAnimationFrame = function(game, forceSetTimeOut) {
  52327. if (forceSetTimeOut === undefined) { forceSetTimeOut = false; }
  52328. /**
  52329. * @property {Phaser.Game} game - The currently running game.
  52330. */
  52331. this.game = game;
  52332. /**
  52333. * @property {boolean} isRunning - true if RequestAnimationFrame is running, otherwise false.
  52334. * @default
  52335. */
  52336. this.isRunning = false;
  52337. /**
  52338. * @property {boolean} forceSetTimeOut - Tell Phaser to use setTimeOut even if raf is available.
  52339. */
  52340. this.forceSetTimeOut = forceSetTimeOut;
  52341. var vendors = [
  52342. 'ms',
  52343. 'moz',
  52344. 'webkit',
  52345. 'o'
  52346. ];
  52347. for (var x = 0; x < vendors.length && !window.requestAnimationFrame; x++)
  52348. {
  52349. window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
  52350. window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
  52351. }
  52352. /**
  52353. * @property {boolean} _isSetTimeOut - true if the browser is using setTimeout instead of raf.
  52354. * @private
  52355. */
  52356. this._isSetTimeOut = false;
  52357. /**
  52358. * @property {function} _onLoop - The function called by the update.
  52359. * @private
  52360. */
  52361. this._onLoop = null;
  52362. /**
  52363. * @property {number} _timeOutID - The callback ID used when calling cancel.
  52364. * @private
  52365. */
  52366. this._timeOutID = null;
  52367. };
  52368. Phaser.RequestAnimationFrame.prototype = {
  52369. /**
  52370. * Starts the requestAnimationFrame running or setTimeout if unavailable in browser
  52371. * @method Phaser.RequestAnimationFrame#start
  52372. */
  52373. start: function () {
  52374. this.isRunning = true;
  52375. var _this = this;
  52376. if (!window.requestAnimationFrame || this.forceSetTimeOut)
  52377. {
  52378. this._isSetTimeOut = true;
  52379. this._onLoop = function () {
  52380. return _this.updateSetTimeout();
  52381. };
  52382. this._timeOutID = window.setTimeout(this._onLoop, 0);
  52383. }
  52384. else
  52385. {
  52386. this._isSetTimeOut = false;
  52387. this._onLoop = function (time) {
  52388. return _this.updateRAF(time);
  52389. };
  52390. this._timeOutID = window.requestAnimationFrame(this._onLoop);
  52391. }
  52392. },
  52393. /**
  52394. * The update method for the requestAnimationFrame
  52395. * @method Phaser.RequestAnimationFrame#updateRAF
  52396. */
  52397. updateRAF: function (rafTime) {
  52398. if (this.isRunning)
  52399. {
  52400. // floor the rafTime to make it equivalent to the Date.now() provided by updateSetTimeout (just below)
  52401. this.game.update(Math.floor(rafTime));
  52402. this._timeOutID = window.requestAnimationFrame(this._onLoop);
  52403. }
  52404. },
  52405. /**
  52406. * The update method for the setTimeout.
  52407. * @method Phaser.RequestAnimationFrame#updateSetTimeout
  52408. */
  52409. updateSetTimeout: function () {
  52410. if (this.isRunning)
  52411. {
  52412. this.game.update(Date.now());
  52413. this._timeOutID = window.setTimeout(this._onLoop, this.game.time.timeToCall);
  52414. }
  52415. },
  52416. /**
  52417. * Stops the requestAnimationFrame from running.
  52418. * @method Phaser.RequestAnimationFrame#stop
  52419. */
  52420. stop: function () {
  52421. if (this._isSetTimeOut)
  52422. {
  52423. clearTimeout(this._timeOutID);
  52424. }
  52425. else
  52426. {
  52427. window.cancelAnimationFrame(this._timeOutID);
  52428. }
  52429. this.isRunning = false;
  52430. },
  52431. /**
  52432. * Is the browser using setTimeout?
  52433. * @method Phaser.RequestAnimationFrame#isSetTimeOut
  52434. * @return {boolean}
  52435. */
  52436. isSetTimeOut: function () {
  52437. return this._isSetTimeOut;
  52438. },
  52439. /**
  52440. * Is the browser using requestAnimationFrame?
  52441. * @method Phaser.RequestAnimationFrame#isRAF
  52442. * @return {boolean}
  52443. */
  52444. isRAF: function () {
  52445. return (this._isSetTimeOut === false);
  52446. }
  52447. };
  52448. Phaser.RequestAnimationFrame.prototype.constructor = Phaser.RequestAnimationFrame;
  52449. /**
  52450. * @author Richard Davey <rich@photonstorm.com>
  52451. * @copyright 2016 Photon Storm Ltd.
  52452. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  52453. */
  52454. /**
  52455. * A collection of useful mathematical functions.
  52456. *
  52457. * These are normally accessed through `game.math`.
  52458. *
  52459. * @class Phaser.Math
  52460. * @static
  52461. * @see {@link Phaser.Utils}
  52462. * @see {@link Phaser.ArrayUtils}
  52463. */
  52464. Phaser.Math = {
  52465. /**
  52466. * Twice PI.
  52467. * @property {number} Phaser.Math#PI2
  52468. * @default ~6.283
  52469. */
  52470. PI2: Math.PI * 2,
  52471. /**
  52472. * Half PI.
  52473. * @property {number} Phaser.Math#HALF_PI
  52474. * @default ~1.570
  52475. */
  52476. HALF_PI: Math.PI * 0.5,
  52477. /**
  52478. * Degrees to Radians factor.
  52479. * @property {number} Phaser.Math#DEG_TO_RAD
  52480. */
  52481. DEG_TO_RAD: Math.PI / 180,
  52482. /**
  52483. * Degrees to Radians factor.
  52484. * @property {number} Phaser.Math#RAD_TO_DEG
  52485. */
  52486. RAD_TO_DEG: 180 / Math.PI,
  52487. /**
  52488. * Convert degrees to radians.
  52489. *
  52490. * @method Phaser.Math#degToRad
  52491. * @param {number} degrees - Angle in degrees.
  52492. * @return {number} Angle in radians.
  52493. */
  52494. degToRad: function (degrees) {
  52495. return degrees * Phaser.Math.DEG_TO_RAD;
  52496. },
  52497. /**
  52498. * Convert radians to degrees.
  52499. *
  52500. * @method Phaser.Math#radToDeg
  52501. * @param {number} radians - Angle in radians.
  52502. * @return {number} Angle in degrees
  52503. */
  52504. radToDeg: function (radians) {
  52505. return radians * Phaser.Math.RAD_TO_DEG;
  52506. },
  52507. /**
  52508. * Given a number, this function returns the closest number that is a power of two.
  52509. * This function is from the Starling Framework.
  52510. *
  52511. * @method Phaser.Math#getNextPowerOfTwo
  52512. * @param {number} value - The value to get the closest power of two from.
  52513. * @return {number} The closest number that is a power of two.
  52514. */
  52515. getNextPowerOfTwo: function (value) {
  52516. if (value > 0 && (value & (value - 1)) === 0)
  52517. {
  52518. // http://goo.gl/D9kPj
  52519. return value;
  52520. }
  52521. else
  52522. {
  52523. var result = 1;
  52524. while (result < value)
  52525. {
  52526. result <<= 1;
  52527. }
  52528. return result;
  52529. }
  52530. },
  52531. /**
  52532. * Checks if the given dimensions make a power of two texture.
  52533. *
  52534. * @method Phaser.Math#isPowerOfTwo
  52535. * @param {number} width - The width to check.
  52536. * @param {number} height - The height to check.
  52537. * @return {boolean} True if the width and height are a power of two.
  52538. */
  52539. isPowerOfTwo: function (width, height) {
  52540. return (width > 0 && (width & (width - 1)) === 0 && height > 0 && (height & (height - 1)) === 0);
  52541. },
  52542. /**
  52543. * Returns a random float in the range `[min, max)`. If these parameters are not in order than they will be put in order.
  52544. * Default is 0 for `min` and 1 for `max`.
  52545. *
  52546. * @method Phaser.Math#random
  52547. * @param {number} min - The minimum value. Must be a Number.
  52548. * @param {number} max - The maximum value. Must be a Number.
  52549. * @return {number} A floating point number between min (inclusive) and max (exclusive).
  52550. */
  52551. random: function (min, max) {
  52552. if (min === undefined) { min = 0; }
  52553. if (max === undefined) { max = 1; }
  52554. if (min === max)
  52555. {
  52556. return min;
  52557. }
  52558. if (min > max)
  52559. {
  52560. var temp = min;
  52561. min = max;
  52562. max = temp;
  52563. }
  52564. return (Math.random() * (max - min) + min);
  52565. },
  52566. /**
  52567. * Returns a random integer in the range `[min, max]`. If these parameters are not in order than they will be put in order.
  52568. * Default is 0 for `min` and 1 for `max`.
  52569. *
  52570. * @method Phaser.Math#between
  52571. * @param {number} min - The minimum value. Must be a Number.
  52572. * @param {number} max - The maximum value. Must be a Number.
  52573. * @return {number} An integer between min (inclusive) and max (inclusive).
  52574. */
  52575. between: function (min, max) {
  52576. if (min === undefined) { min = 0; }
  52577. if (max === undefined) { max = 1; }
  52578. if (min === max)
  52579. {
  52580. return min;
  52581. }
  52582. if (min > max)
  52583. {
  52584. var temp = min;
  52585. min = max;
  52586. max = temp;
  52587. }
  52588. min = Math.ceil(min);
  52589. max = Math.floor(max);
  52590. return Math.floor(Math.random() * (max - min + 1)) + min;
  52591. },
  52592. /**
  52593. * Two number are fuzzyEqual if their difference is less than epsilon.
  52594. *
  52595. * @method Phaser.Math#fuzzyEqual
  52596. * @param {number} a - The first number to compare.
  52597. * @param {number} b - The second number to compare.
  52598. * @param {number} [epsilon=0.0001] - The epsilon (a small value used in the calculation)
  52599. * @return {boolean} True if |a-b|<epsilon
  52600. */
  52601. fuzzyEqual: function (a, b, epsilon) {
  52602. if (epsilon === undefined) { epsilon = 0.0001; }
  52603. return Math.abs(a - b) < epsilon;
  52604. },
  52605. /**
  52606. * `a` is fuzzyLessThan `b` if it is less than b + epsilon.
  52607. *
  52608. * @method Phaser.Math#fuzzyLessThan
  52609. * @param {number} a - The first number to compare.
  52610. * @param {number} b - The second number to compare.
  52611. * @param {number} [epsilon=0.0001] - The epsilon (a small value used in the calculation)
  52612. * @return {boolean} True if a<b+epsilon
  52613. */
  52614. fuzzyLessThan: function (a, b, epsilon) {
  52615. if (epsilon === undefined) { epsilon = 0.0001; }
  52616. return a < b + epsilon;
  52617. },
  52618. /**
  52619. * `a` is fuzzyGreaterThan `b` if it is more than b - epsilon.
  52620. *
  52621. * @method Phaser.Math#fuzzyGreaterThan
  52622. * @param {number} a - The first number to compare.
  52623. * @param {number} b - The second number to compare.
  52624. * @param {number} [epsilon=0.0001] - The epsilon (a small value used in the calculation)
  52625. * @return {boolean} True if a>b+epsilon
  52626. */
  52627. fuzzyGreaterThan: function (a, b, epsilon) {
  52628. if (epsilon === undefined) { epsilon = 0.0001; }
  52629. return a > b - epsilon;
  52630. },
  52631. /**
  52632. * Applies a fuzzy ceil to the given value.
  52633. *
  52634. * @method Phaser.Math#fuzzyCeil
  52635. * @param {number} val - The value to ceil.
  52636. * @param {number} [epsilon=0.0001] - The epsilon (a small value used in the calculation)
  52637. * @return {number} ceiling(val-epsilon)
  52638. */
  52639. fuzzyCeil: function (val, epsilon) {
  52640. if (epsilon === undefined) { epsilon = 0.0001; }
  52641. return Math.ceil(val - epsilon);
  52642. },
  52643. /**
  52644. * Applies a fuzzy floor to the given value.
  52645. *
  52646. * @method Phaser.Math#fuzzyFloor
  52647. * @param {number} val - The value to floor.
  52648. * @param {number} [epsilon=0.0001] - The epsilon (a small value used in the calculation)
  52649. * @return {number} floor(val+epsilon)
  52650. */
  52651. fuzzyFloor: function (val, epsilon) {
  52652. if (epsilon === undefined) { epsilon = 0.0001; }
  52653. return Math.floor(val + epsilon);
  52654. },
  52655. /**
  52656. * Averages all values passed to the function and returns the result.
  52657. *
  52658. * @method Phaser.Math#average
  52659. * @params {...number} The numbers to average
  52660. * @return {number} The average of all given values.
  52661. */
  52662. average: function () {
  52663. var sum = 0;
  52664. var len = arguments.length;
  52665. for (var i = 0; i < len; i++)
  52666. {
  52667. sum += (+arguments[i]);
  52668. }
  52669. return sum / len;
  52670. },
  52671. /**
  52672. * @method Phaser.Math#shear
  52673. * @param {number} n
  52674. * @return {number} n mod 1
  52675. */
  52676. shear: function (n) {
  52677. return n % 1;
  52678. },
  52679. /**
  52680. * Snap a value to nearest grid slice, using rounding.
  52681. *
  52682. * Example: if you have an interval gap of 5 and a position of 12... you will snap to 10 whereas 14 will snap to 15.
  52683. *
  52684. * @method Phaser.Math#snapTo
  52685. * @param {number} input - The value to snap.
  52686. * @param {number} gap - The interval gap of the grid.
  52687. * @param {number} [start=0] - Optional starting offset for gap.
  52688. * @return {number} The snapped value.
  52689. */
  52690. snapTo: function (input, gap, start) {
  52691. if (start === undefined) { start = 0; }
  52692. if (gap === 0) {
  52693. return input;
  52694. }
  52695. input -= start;
  52696. input = gap * Math.round(input / gap);
  52697. return start + input;
  52698. },
  52699. /**
  52700. * Snap a value to nearest grid slice, using floor.
  52701. *
  52702. * Example: if you have an interval gap of 5 and a position of 12... you will snap to 10.
  52703. * As will 14 snap to 10... but 16 will snap to 15.
  52704. *
  52705. * @method Phaser.Math#snapToFloor
  52706. * @param {number} input - The value to snap.
  52707. * @param {number} gap - The interval gap of the grid.
  52708. * @param {number} [start=0] - Optional starting offset for gap.
  52709. * @return {number} The snapped value.
  52710. */
  52711. snapToFloor: function (input, gap, start) {
  52712. if (start === undefined) { start = 0; }
  52713. if (gap === 0) {
  52714. return input;
  52715. }
  52716. input -= start;
  52717. input = gap * Math.floor(input / gap);
  52718. return start + input;
  52719. },
  52720. /**
  52721. * Snap a value to nearest grid slice, using ceil.
  52722. *
  52723. * Example: if you have an interval gap of 5 and a position of 12... you will snap to 15.
  52724. * As will 14 will snap to 15... but 16 will snap to 20.
  52725. *
  52726. * @method Phaser.Math#snapToCeil
  52727. * @param {number} input - The value to snap.
  52728. * @param {number} gap - The interval gap of the grid.
  52729. * @param {number} [start=0] - Optional starting offset for gap.
  52730. * @return {number} The snapped value.
  52731. */
  52732. snapToCeil: function (input, gap, start) {
  52733. if (start === undefined) { start = 0; }
  52734. if (gap === 0) {
  52735. return input;
  52736. }
  52737. input -= start;
  52738. input = gap * Math.ceil(input / gap);
  52739. return start + input;
  52740. },
  52741. /**
  52742. * Round to some place comparative to a `base`, default is 10 for decimal place.
  52743. * The `place` is represented by the power applied to `base` to get that place.
  52744. *
  52745. * e.g. 2000/7 ~= 285.714285714285714285714 ~= (bin)100011101.1011011011011011
  52746. *
  52747. * roundTo(2000/7,3) === 0
  52748. * roundTo(2000/7,2) == 300
  52749. * roundTo(2000/7,1) == 290
  52750. * roundTo(2000/7,0) == 286
  52751. * roundTo(2000/7,-1) == 285.7
  52752. * roundTo(2000/7,-2) == 285.71
  52753. * roundTo(2000/7,-3) == 285.714
  52754. * roundTo(2000/7,-4) == 285.7143
  52755. * roundTo(2000/7,-5) == 285.71429
  52756. *
  52757. * roundTo(2000/7,3,2) == 288 -- 100100000
  52758. * roundTo(2000/7,2,2) == 284 -- 100011100
  52759. * roundTo(2000/7,1,2) == 286 -- 100011110
  52760. * roundTo(2000/7,0,2) == 286 -- 100011110
  52761. * roundTo(2000/7,-1,2) == 285.5 -- 100011101.1
  52762. * roundTo(2000/7,-2,2) == 285.75 -- 100011101.11
  52763. * roundTo(2000/7,-3,2) == 285.75 -- 100011101.11
  52764. * roundTo(2000/7,-4,2) == 285.6875 -- 100011101.1011
  52765. * roundTo(2000/7,-5,2) == 285.71875 -- 100011101.10111
  52766. *
  52767. * Note what occurs when we round to the 3rd space (8ths place), 100100000, this is to be assumed
  52768. * because we are rounding 100011.1011011011011011 which rounds up.
  52769. *
  52770. * @method Phaser.Math#roundTo
  52771. * @param {number} value - The value to round.
  52772. * @param {number} [place=0] - The place to round to.
  52773. * @param {number} [base=10] - The base to round in. Default is 10 for decimal.
  52774. * @return {number} The rounded value.
  52775. */
  52776. roundTo: function (value, place, base) {
  52777. if (place === undefined) { place = 0; }
  52778. if (base === undefined) { base = 10; }
  52779. var p = Math.pow(base, -place);
  52780. return Math.round(value * p) / p;
  52781. },
  52782. /**
  52783. * Floors to some place comparative to a `base`, default is 10 for decimal place.
  52784. * The `place` is represented by the power applied to `base` to get that place.
  52785. *
  52786. * @method Phaser.Math#floorTo
  52787. * @param {number} value - The value to round.
  52788. * @param {number} [place=0] - The place to round to.
  52789. * @param {number} [base=10] - The base to round in. Default is 10 for decimal.
  52790. * @return {number} The rounded value.
  52791. */
  52792. floorTo: function (value, place, base) {
  52793. if (place === undefined) { place = 0; }
  52794. if (base === undefined) { base = 10; }
  52795. var p = Math.pow(base, -place);
  52796. return Math.floor(value * p) / p;
  52797. },
  52798. /**
  52799. * Ceils to some place comparative to a `base`, default is 10 for decimal place.
  52800. * The `place` is represented by the power applied to `base` to get that place.
  52801. *
  52802. * @method Phaser.Math#ceilTo
  52803. * @param {number} value - The value to round.
  52804. * @param {number} [place=0] - The place to round to.
  52805. * @param {number} [base=10] - The base to round in. Default is 10 for decimal.
  52806. * @return {number} The rounded value.
  52807. */
  52808. ceilTo: function (value, place, base) {
  52809. if (place === undefined) { place = 0; }
  52810. if (base === undefined) { base = 10; }
  52811. var p = Math.pow(base, -place);
  52812. return Math.ceil(value * p) / p;
  52813. },
  52814. /**
  52815. * Rotates currentAngle towards targetAngle, taking the shortest rotation distance.
  52816. * The lerp argument is the amount to rotate by in this call.
  52817. *
  52818. * @method Phaser.Math#rotateToAngle
  52819. * @param {number} currentAngle - The current angle, in radians.
  52820. * @param {number} targetAngle - The target angle to rotate to, in radians.
  52821. * @param {number} [lerp=0.05] - The lerp value to add to the current angle.
  52822. * @return {number} The adjusted angle.
  52823. */
  52824. rotateToAngle: function (currentAngle, targetAngle, lerp) {
  52825. if (lerp === undefined) { lerp = 0.05; }
  52826. if (currentAngle === targetAngle)
  52827. {
  52828. return currentAngle;
  52829. }
  52830. if (Math.abs(targetAngle - currentAngle) <= lerp || Math.abs(targetAngle - currentAngle) >= (Phaser.Math.PI2 - lerp))
  52831. {
  52832. currentAngle = targetAngle;
  52833. }
  52834. else
  52835. {
  52836. if (Math.abs(targetAngle - currentAngle) > Math.PI)
  52837. {
  52838. if (targetAngle < currentAngle)
  52839. {
  52840. targetAngle += Phaser.Math.PI2;
  52841. }
  52842. else
  52843. {
  52844. targetAngle -= Phaser.Math.PI2;
  52845. }
  52846. }
  52847. if (targetAngle > currentAngle)
  52848. {
  52849. currentAngle += lerp;
  52850. }
  52851. else if (targetAngle < currentAngle)
  52852. {
  52853. currentAngle -= lerp;
  52854. }
  52855. }
  52856. return currentAngle;
  52857. },
  52858. /**
  52859. * Gets the shortest angle between `angle1` and `angle2`.
  52860. * Both angles must be in the range -180 to 180, which is the same clamped
  52861. * range that `sprite.angle` uses, so you can pass in two sprite angles to
  52862. * this method, and get the shortest angle back between the two of them.
  52863. *
  52864. * The angle returned will be in the same range. If the returned angle is
  52865. * greater than 0 then it's a counter-clockwise rotation, if < 0 then it's
  52866. * a clockwise rotation.
  52867. *
  52868. * @method Phaser.Math#getShortestAngle
  52869. * @param {number} angle1 - The first angle. In the range -180 to 180.
  52870. * @param {number} angle2 - The second angle. In the range -180 to 180.
  52871. * @return {number} The shortest angle, in degrees. If greater than zero it's a counter-clockwise rotation.
  52872. */
  52873. getShortestAngle: function (angle1, angle2) {
  52874. var difference = angle2 - angle1;
  52875. if (difference === 0)
  52876. {
  52877. return 0;
  52878. }
  52879. var times = Math.floor((difference - (-180)) / 360);
  52880. return difference - (times * 360);
  52881. },
  52882. /**
  52883. * Find the angle of a segment from (x1, y1) -> (x2, y2).
  52884. *
  52885. * @method Phaser.Math#angleBetween
  52886. * @param {number} x1 - The x coordinate of the first value.
  52887. * @param {number} y1 - The y coordinate of the first value.
  52888. * @param {number} x2 - The x coordinate of the second value.
  52889. * @param {number} y2 - The y coordinate of the second value.
  52890. * @return {number} The angle, in radians.
  52891. */
  52892. angleBetween: function (x1, y1, x2, y2) {
  52893. return Math.atan2(y2 - y1, x2 - x1);
  52894. },
  52895. /**
  52896. * Find the angle of a segment from (x1, y1) -> (x2, y2).
  52897. *
  52898. * The difference between this method and Math.angleBetween is that this assumes the y coordinate travels
  52899. * down the screen.
  52900. *
  52901. * @method Phaser.Math#angleBetweenY
  52902. * @param {number} x1 - The x coordinate of the first value.
  52903. * @param {number} y1 - The y coordinate of the first value.
  52904. * @param {number} x2 - The x coordinate of the second value.
  52905. * @param {number} y2 - The y coordinate of the second value.
  52906. * @return {number} The angle, in radians.
  52907. */
  52908. angleBetweenY: function (x1, y1, x2, y2) {
  52909. return Math.atan2(x2 - x1, y2 - y1);
  52910. },
  52911. /**
  52912. * Find the angle of a segment from (point1.x, point1.y) -> (point2.x, point2.y).
  52913. *
  52914. * @method Phaser.Math#angleBetweenPoints
  52915. * @param {Phaser.Point} point1 - The first point.
  52916. * @param {Phaser.Point} point2 - The second point.
  52917. * @return {number} The angle between the two points, in radians.
  52918. */
  52919. angleBetweenPoints: function (point1, point2) {
  52920. return Math.atan2(point2.y - point1.y, point2.x - point1.x);
  52921. },
  52922. /**
  52923. * Find the angle of a segment from (point1.x, point1.y) -> (point2.x, point2.y).
  52924. * @method Phaser.Math#angleBetweenPointsY
  52925. * @param {Phaser.Point} point1
  52926. * @param {Phaser.Point} point2
  52927. * @return {number} The angle, in radians.
  52928. */
  52929. angleBetweenPointsY: function (point1, point2) {
  52930. return Math.atan2(point2.x - point1.x, point2.y - point1.y);
  52931. },
  52932. /**
  52933. * Reverses an angle.
  52934. * @method Phaser.Math#reverseAngle
  52935. * @param {number} angleRad - The angle to reverse, in radians.
  52936. * @return {number} The reverse angle, in radians.
  52937. */
  52938. reverseAngle: function (angleRad) {
  52939. return this.normalizeAngle(angleRad + Math.PI, true);
  52940. },
  52941. /**
  52942. * Normalizes an angle to the [0,2pi) range.
  52943. * @method Phaser.Math#normalizeAngle
  52944. * @param {number} angleRad - The angle to normalize, in radians.
  52945. * @return {number} The angle, fit within the [0,2pi] range, in radians.
  52946. */
  52947. normalizeAngle: function (angleRad) {
  52948. angleRad = angleRad % (2 * Math.PI);
  52949. return angleRad >= 0 ? angleRad : angleRad + 2 * Math.PI;
  52950. },
  52951. /**
  52952. * Adds the given amount to the value, but never lets the value go over the specified maximum.
  52953. *
  52954. * @method Phaser.Math#maxAdd
  52955. * @param {number} value - The value to add the amount to.
  52956. * @param {number} amount - The amount to add to the value.
  52957. * @param {number} max - The maximum the value is allowed to be.
  52958. * @return {number} The new value.
  52959. */
  52960. maxAdd: function (value, amount, max) {
  52961. return Math.min(value + amount, max);
  52962. },
  52963. /**
  52964. * Subtracts the given amount from the value, but never lets the value go below the specified minimum.
  52965. *
  52966. * @method Phaser.Math#minSub
  52967. * @param {number} value - The base value.
  52968. * @param {number} amount - The amount to subtract from the base value.
  52969. * @param {number} min - The minimum the value is allowed to be.
  52970. * @return {number} The new value.
  52971. */
  52972. minSub: function (value, amount, min) {
  52973. return Math.max(value - amount, min);
  52974. },
  52975. /**
  52976. * Ensures that the value always stays between min and max, by wrapping the value around.
  52977. *
  52978. * If `max` is not larger than `min` the result is 0.
  52979. *
  52980. * @method Phaser.Math#wrap
  52981. * @param {number} value - The value to wrap.
  52982. * @param {number} min - The minimum the value is allowed to be.
  52983. * @param {number} max - The maximum the value is allowed to be, should be larger than `min`.
  52984. * @return {number} The wrapped value.
  52985. */
  52986. wrap: function (value, min, max) {
  52987. var range = max - min;
  52988. if (range <= 0)
  52989. {
  52990. return 0;
  52991. }
  52992. var result = (value - min) % range;
  52993. if (result < 0)
  52994. {
  52995. result += range;
  52996. }
  52997. return result + min;
  52998. },
  52999. /**
  53000. * Adds value to amount and ensures that the result always stays between 0 and max, by wrapping the value around.
  53001. *
  53002. * Values _must_ be positive integers, and are passed through Math.abs. See {@link Phaser.Math#wrap} for an alternative.
  53003. *
  53004. * @method Phaser.Math#wrapValue
  53005. * @param {number} value - The value to add the amount to.
  53006. * @param {number} amount - The amount to add to the value.
  53007. * @param {number} max - The maximum the value is allowed to be.
  53008. * @return {number} The wrapped value.
  53009. */
  53010. wrapValue: function (value, amount, max) {
  53011. var diff;
  53012. value = Math.abs(value);
  53013. amount = Math.abs(amount);
  53014. max = Math.abs(max);
  53015. diff = (value + amount) % max;
  53016. return diff;
  53017. },
  53018. /**
  53019. * Returns true if the number given is odd.
  53020. *
  53021. * @method Phaser.Math#isOdd
  53022. * @param {integer} n - The number to check.
  53023. * @return {boolean} True if the given number is odd. False if the given number is even.
  53024. */
  53025. isOdd: function (n) {
  53026. // Does not work with extremely large values
  53027. return !!(n & 1);
  53028. },
  53029. /**
  53030. * Returns true if the number given is even.
  53031. *
  53032. * @method Phaser.Math#isEven
  53033. * @param {integer} n - The number to check.
  53034. * @return {boolean} True if the given number is even. False if the given number is odd.
  53035. */
  53036. isEven: function (n) {
  53037. // Does not work with extremely large values
  53038. return !(n & 1);
  53039. },
  53040. /**
  53041. * Variation of Math.min that can be passed either an array of numbers or the numbers as parameters.
  53042. *
  53043. * Prefer the standard `Math.min` function when appropriate.
  53044. *
  53045. * @method Phaser.Math#min
  53046. * @return {number} The lowest value from those given.
  53047. * @see {@link http://jsperf.com/math-s-min-max-vs-homemade}
  53048. */
  53049. min: function () {
  53050. if (arguments.length === 1 && typeof arguments[0] === 'object')
  53051. {
  53052. var data = arguments[0];
  53053. }
  53054. else
  53055. {
  53056. var data = arguments;
  53057. }
  53058. for (var i = 1, min = 0, len = data.length; i < len; i++)
  53059. {
  53060. if (data[i] < data[min])
  53061. {
  53062. min = i;
  53063. }
  53064. }
  53065. return data[min];
  53066. },
  53067. /**
  53068. * Variation of Math.max that can be passed either an array of numbers or the numbers as parameters.
  53069. *
  53070. * Prefer the standard `Math.max` function when appropriate.
  53071. *
  53072. * @method Phaser.Math#max
  53073. * @return {number} The largest value from those given.
  53074. * @see {@link http://jsperf.com/math-s-min-max-vs-homemade}
  53075. */
  53076. max: function () {
  53077. if (arguments.length === 1 && typeof arguments[0] === 'object')
  53078. {
  53079. var data = arguments[0];
  53080. }
  53081. else
  53082. {
  53083. var data = arguments;
  53084. }
  53085. for (var i = 1, max = 0, len = data.length; i < len; i++)
  53086. {
  53087. if (data[i] > data[max])
  53088. {
  53089. max = i;
  53090. }
  53091. }
  53092. return data[max];
  53093. },
  53094. /**
  53095. * Variation of Math.min that can be passed a property and either an array of objects or the objects as parameters.
  53096. * It will find the lowest matching property value from the given objects.
  53097. *
  53098. * @method Phaser.Math#minProperty
  53099. * @return {number} The lowest value from those given.
  53100. */
  53101. minProperty: function (property) {
  53102. if (arguments.length === 2 && typeof arguments[1] === 'object')
  53103. {
  53104. var data = arguments[1];
  53105. }
  53106. else
  53107. {
  53108. var data = arguments.slice(1);
  53109. }
  53110. for (var i = 1, min = 0, len = data.length; i < len; i++)
  53111. {
  53112. if (data[i][property] < data[min][property])
  53113. {
  53114. min = i;
  53115. }
  53116. }
  53117. return data[min][property];
  53118. },
  53119. /**
  53120. * Variation of Math.max that can be passed a property and either an array of objects or the objects as parameters.
  53121. * It will find the largest matching property value from the given objects.
  53122. *
  53123. * @method Phaser.Math#maxProperty
  53124. * @return {number} The largest value from those given.
  53125. */
  53126. maxProperty: function (property) {
  53127. if (arguments.length === 2 && typeof arguments[1] === 'object')
  53128. {
  53129. var data = arguments[1];
  53130. }
  53131. else
  53132. {
  53133. var data = arguments.slice(1);
  53134. }
  53135. for (var i = 1, max = 0, len = data.length; i < len; i++)
  53136. {
  53137. if (data[i][property] > data[max][property])
  53138. {
  53139. max = i;
  53140. }
  53141. }
  53142. return data[max][property];
  53143. },
  53144. /**
  53145. * Keeps an angle value between -180 and +180; or -PI and PI if radians.
  53146. *
  53147. * @method Phaser.Math#wrapAngle
  53148. * @param {number} angle - The angle value to wrap
  53149. * @param {boolean} [radians=false] - Set to `true` if the angle is given in radians, otherwise degrees is expected.
  53150. * @return {number} The new angle value; will be the same as the input angle if it was within bounds.
  53151. */
  53152. wrapAngle: function (angle, radians) {
  53153. return radians ? this.wrap(angle, -Math.PI, Math.PI) : this.wrap(angle, -180, 180);
  53154. },
  53155. /**
  53156. * A Linear Interpolation Method, mostly used by Phaser.Tween.
  53157. *
  53158. * @method Phaser.Math#linearInterpolation
  53159. * @param {Array} v - The input array of values to interpolate between.
  53160. * @param {number} k - The percentage of interpolation, between 0 and 1.
  53161. * @return {number} The interpolated value
  53162. */
  53163. linearInterpolation: function (v, k) {
  53164. var m = v.length - 1;
  53165. var f = m * k;
  53166. var i = Math.floor(f);
  53167. if (k < 0)
  53168. {
  53169. return this.linear(v[0], v[1], f);
  53170. }
  53171. if (k > 1)
  53172. {
  53173. return this.linear(v[m], v[m - 1], m - f);
  53174. }
  53175. return this.linear(v[i], v[i + 1 > m ? m : i + 1], f - i);
  53176. },
  53177. /**
  53178. * A Bezier Interpolation Method, mostly used by Phaser.Tween.
  53179. *
  53180. * @method Phaser.Math#bezierInterpolation
  53181. * @param {Array} v - The input array of values to interpolate between.
  53182. * @param {number} k - The percentage of interpolation, between 0 and 1.
  53183. * @return {number} The interpolated value
  53184. */
  53185. bezierInterpolation: function (v, k) {
  53186. var b = 0;
  53187. var n = v.length - 1;
  53188. for (var i = 0; i <= n; i++)
  53189. {
  53190. b += Math.pow(1 - k, n - i) * Math.pow(k, i) * v[i] * this.bernstein(n, i);
  53191. }
  53192. return b;
  53193. },
  53194. /**
  53195. * A Catmull Rom Interpolation Method, mostly used by Phaser.Tween.
  53196. *
  53197. * @method Phaser.Math#catmullRomInterpolation
  53198. * @param {Array} v - The input array of values to interpolate between.
  53199. * @param {number} k - The percentage of interpolation, between 0 and 1.
  53200. * @return {number} The interpolated value
  53201. */
  53202. catmullRomInterpolation: function (v, k) {
  53203. var m = v.length - 1;
  53204. var f = m * k;
  53205. var i = Math.floor(f);
  53206. if (v[0] === v[m])
  53207. {
  53208. if (k < 0)
  53209. {
  53210. i = Math.floor(f = m * (1 + k));
  53211. }
  53212. return this.catmullRom(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i);
  53213. }
  53214. else
  53215. {
  53216. if (k < 0)
  53217. {
  53218. return v[0] - (this.catmullRom(v[0], v[0], v[1], v[1], -f) - v[0]);
  53219. }
  53220. if (k > 1)
  53221. {
  53222. return v[m] - (this.catmullRom(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]);
  53223. }
  53224. return this.catmullRom(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i);
  53225. }
  53226. },
  53227. /**
  53228. * Calculates a linear (interpolation) value over t.
  53229. *
  53230. * @method Phaser.Math#linear
  53231. * @param {number} p0
  53232. * @param {number} p1
  53233. * @param {number} t - A value between 0 and 1.
  53234. * @return {number}
  53235. */
  53236. linear: function (p0, p1, t) {
  53237. return (p1 - p0) * t + p0;
  53238. },
  53239. /**
  53240. * @method Phaser.Math#bernstein
  53241. * @protected
  53242. * @param {number} n
  53243. * @param {number} i
  53244. * @return {number}
  53245. */
  53246. bernstein: function (n, i) {
  53247. return this.factorial(n) / this.factorial(i) / this.factorial(n - i);
  53248. },
  53249. /**
  53250. * @method Phaser.Math#factorial
  53251. * @param {number} value - the number you want to evaluate
  53252. * @return {number}
  53253. */
  53254. factorial: function (value) {
  53255. if (value === 0)
  53256. {
  53257. return 1;
  53258. }
  53259. var res = value;
  53260. while(--value)
  53261. {
  53262. res *= value;
  53263. }
  53264. return res;
  53265. },
  53266. /**
  53267. * Calculates a catmum rom value.
  53268. *
  53269. * @method Phaser.Math#catmullRom
  53270. * @protected
  53271. * @param {number} p0
  53272. * @param {number} p1
  53273. * @param {number} p2
  53274. * @param {number} p3
  53275. * @param {number} t
  53276. * @return {number}
  53277. */
  53278. catmullRom: function (p0, p1, p2, p3, t) {
  53279. var v0 = (p2 - p0) * 0.5, v1 = (p3 - p1) * 0.5, t2 = t * t, t3 = t * t2;
  53280. return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
  53281. },
  53282. /**
  53283. * The absolute difference between two values.
  53284. *
  53285. * @method Phaser.Math#difference
  53286. * @param {number} a - The first value to check.
  53287. * @param {number} b - The second value to check.
  53288. * @return {number} The absolute difference between the two values.
  53289. */
  53290. difference: function (a, b) {
  53291. return Math.abs(a - b);
  53292. },
  53293. /**
  53294. * Round to the next whole number _away_ from zero.
  53295. *
  53296. * @method Phaser.Math#roundAwayFromZero
  53297. * @param {number} value - Any number.
  53298. * @return {integer} The rounded value of that number.
  53299. */
  53300. roundAwayFromZero: function (value) {
  53301. // "Opposite" of truncate.
  53302. return (value > 0) ? Math.ceil(value) : Math.floor(value);
  53303. },
  53304. /**
  53305. * Generate a sine and cosine table simultaneously and extremely quickly.
  53306. * The parameters allow you to specify the length, amplitude and frequency of the wave.
  53307. * This generator is fast enough to be used in real-time.
  53308. * Code based on research by Franky of scene.at
  53309. *
  53310. * @method Phaser.Math#sinCosGenerator
  53311. * @param {number} length - The length of the wave
  53312. * @param {number} sinAmplitude - The amplitude to apply to the sine table (default 1.0) if you need values between say -+ 125 then give 125 as the value
  53313. * @param {number} cosAmplitude - The amplitude to apply to the cosine table (default 1.0) if you need values between say -+ 125 then give 125 as the value
  53314. * @param {number} frequency - The frequency of the sine and cosine table data
  53315. * @return {{sin:number[], cos:number[]}} Returns the table data.
  53316. */
  53317. sinCosGenerator: function (length, sinAmplitude, cosAmplitude, frequency) {
  53318. if (sinAmplitude === undefined) { sinAmplitude = 1.0; }
  53319. if (cosAmplitude === undefined) { cosAmplitude = 1.0; }
  53320. if (frequency === undefined) { frequency = 1.0; }
  53321. var sin = sinAmplitude;
  53322. var cos = cosAmplitude;
  53323. var frq = frequency * Math.PI / length;
  53324. var cosTable = [];
  53325. var sinTable = [];
  53326. for (var c = 0; c < length; c++) {
  53327. cos -= sin * frq;
  53328. sin += cos * frq;
  53329. cosTable[c] = cos;
  53330. sinTable[c] = sin;
  53331. }
  53332. return { sin: sinTable, cos: cosTable, length: length };
  53333. },
  53334. /**
  53335. * Returns the length of the hypotenuse connecting two segments of given lengths.
  53336. *
  53337. * @method Phaser.Math#hypot
  53338. * @param {number} a
  53339. * @param {number} b
  53340. * @return {number} The length of the hypotenuse connecting the given lengths.
  53341. */
  53342. hypot: function (a, b) {
  53343. return Math.sqrt(a * a + b * b);
  53344. },
  53345. /**
  53346. * Returns the euclidian distance between the two given set of coordinates.
  53347. *
  53348. * @method Phaser.Math#distance
  53349. * @param {number} x1
  53350. * @param {number} y1
  53351. * @param {number} x2
  53352. * @param {number} y2
  53353. * @return {number} The distance between the two sets of coordinates.
  53354. */
  53355. distance: function (x1, y1, x2, y2) {
  53356. var dx = x1 - x2;
  53357. var dy = y1 - y2;
  53358. return Math.sqrt(dx * dx + dy * dy);
  53359. },
  53360. /**
  53361. * Returns the euclidean distance squared between the two given set of
  53362. * coordinates (cuts out a square root operation before returning).
  53363. *
  53364. * @method Phaser.Math#distanceSq
  53365. * @param {number} x1
  53366. * @param {number} y1
  53367. * @param {number} x2
  53368. * @param {number} y2
  53369. * @return {number} The distance squared between the two sets of coordinates.
  53370. */
  53371. distanceSq: function (x1, y1, x2, y2) {
  53372. var dx = x1 - x2;
  53373. var dy = y1 - y2;
  53374. return dx * dx + dy * dy;
  53375. },
  53376. /**
  53377. * Returns the distance between the two given set of coordinates at the power given.
  53378. *
  53379. * @method Phaser.Math#distancePow
  53380. * @param {number} x1
  53381. * @param {number} y1
  53382. * @param {number} x2
  53383. * @param {number} y2
  53384. * @param {number} [pow=2]
  53385. * @return {number} The distance between the two sets of coordinates.
  53386. */
  53387. distancePow: function (x1, y1, x2, y2, pow) {
  53388. if (pow === undefined) { pow = 2; }
  53389. return Math.sqrt(Math.pow(x2 - x1, pow) + Math.pow(y2 - y1, pow));
  53390. },
  53391. /**
  53392. * Force a value within the boundaries by clamping it to the range `min`, `max`.
  53393. *
  53394. * @method Phaser.Math#clamp
  53395. * @param {float} v - The value to be clamped.
  53396. * @param {float} min - The minimum bounds.
  53397. * @param {float} max - The maximum bounds.
  53398. * @return {number} The clamped value.
  53399. */
  53400. clamp: function (v, min, max) {
  53401. if (v < min)
  53402. {
  53403. return min;
  53404. }
  53405. else if (max < v)
  53406. {
  53407. return max;
  53408. }
  53409. else
  53410. {
  53411. return v;
  53412. }
  53413. },
  53414. /**
  53415. * Clamp `x` to the range `[a, Infinity)`.
  53416. * Roughly the same as `Math.max(x, a)`, except for NaN handling.
  53417. *
  53418. * @method Phaser.Math#clampBottom
  53419. * @param {number} x
  53420. * @param {number} a
  53421. * @return {number}
  53422. */
  53423. clampBottom: function (x, a) {
  53424. return x < a ? a : x;
  53425. },
  53426. /**
  53427. * Checks if two values are within the given tolerance of each other.
  53428. *
  53429. * @method Phaser.Math#within
  53430. * @param {number} a - The first number to check
  53431. * @param {number} b - The second number to check
  53432. * @param {number} tolerance - The tolerance. Anything equal to or less than this is considered within the range.
  53433. * @return {boolean} True if a is <= tolerance of b.
  53434. * @see {@link Phaser.Math.fuzzyEqual}
  53435. */
  53436. within: function (a, b, tolerance) {
  53437. return (Math.abs(a - b) <= tolerance);
  53438. },
  53439. /**
  53440. * Linear mapping from range <a1, a2> to range <b1, b2>
  53441. *
  53442. * @method Phaser.Math#mapLinear
  53443. * @param {number} x - The value to map
  53444. * @param {number} a1 - First endpoint of the range <a1, a2>
  53445. * @param {number} a2 - Final endpoint of the range <a1, a2>
  53446. * @param {number} b1 - First endpoint of the range <b1, b2>
  53447. * @param {number} b2 - Final endpoint of the range <b1, b2>
  53448. * @return {number}
  53449. */
  53450. mapLinear: function (x, a1, a2, b1, b2) {
  53451. return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
  53452. },
  53453. /**
  53454. * Smoothstep function as detailed at http://en.wikipedia.org/wiki/Smoothstep
  53455. *
  53456. * @method Phaser.Math#smoothstep
  53457. * @param {float} x - The input value.
  53458. * @param {float} min - The left edge. Should be smaller than the right edge.
  53459. * @param {float} max - The right edge.
  53460. * @return {float} A value between 0 and 1.
  53461. */
  53462. smoothstep: function (x, min, max) {
  53463. // Scale, bias and saturate x to 0..1 range
  53464. x = Math.max(0, Math.min(1, (x - min) / (max - min)));
  53465. // Evaluate polynomial
  53466. return x * x * (3 - 2 * x);
  53467. },
  53468. /**
  53469. * Smootherstep function as detailed at http://en.wikipedia.org/wiki/Smoothstep
  53470. *
  53471. * @method Phaser.Math#smootherstep
  53472. * @param {float} x - The input value.
  53473. * @param {float} min - The left edge. Should be smaller than the right edge.
  53474. * @param {float} max - The right edge.
  53475. * @return {float} A value between 0 and 1.
  53476. */
  53477. smootherstep: function (x, min, max) {
  53478. x = Math.max(0, Math.min(1, (x - min) / (max - min)));
  53479. return x * x * x * (x * (x * 6 - 15) + 10);
  53480. },
  53481. /**
  53482. * A value representing the sign of the value: -1 for negative, +1 for positive, 0 if value is 0.
  53483. *
  53484. * This works differently from `Math.sign` for values of NaN and -0, etc.
  53485. *
  53486. * @method Phaser.Math#sign
  53487. * @param {number} x
  53488. * @return {integer} An integer in {-1, 0, 1}
  53489. */
  53490. sign: function (x) {
  53491. return ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 );
  53492. },
  53493. /**
  53494. * Work out what percentage value `a` is of value `b` using the given base.
  53495. *
  53496. * @method Phaser.Math#percent
  53497. * @param {number} a - The value to work out the percentage for.
  53498. * @param {number} b - The value you wish to get the percentage of.
  53499. * @param {number} [base=0] - The base value.
  53500. * @return {number} The percentage a is of b, between 0 and 1.
  53501. */
  53502. percent: function (a, b, base) {
  53503. if (base === undefined) { base = 0; }
  53504. if (a > b || base > b)
  53505. {
  53506. return 1;
  53507. }
  53508. else if (a < base || base > a)
  53509. {
  53510. return 0;
  53511. }
  53512. else
  53513. {
  53514. return (a - base) / b;
  53515. }
  53516. }
  53517. };
  53518. /* jshint noempty: false */
  53519. /**
  53520. * @author Richard Davey <rich@photonstorm.com>
  53521. * @copyright 2016 Photon Storm Ltd.
  53522. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  53523. */
  53524. /**
  53525. * An extremely useful repeatable random data generator.
  53526. *
  53527. * Based on Nonsense by Josh Faul https://github.com/jocafa/Nonsense.
  53528. *
  53529. * The random number genererator is based on the Alea PRNG, but is modified.
  53530. * - https://github.com/coverslide/node-alea
  53531. * - https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
  53532. * - http://baagoe.org/en/wiki/Better_random_numbers_for_javascript (original, perm. 404)
  53533. *
  53534. * @class Phaser.RandomDataGenerator
  53535. * @constructor
  53536. * @param {any[]|string} [seeds] - An array of values to use as the seed, or a generator state (from {#state}).
  53537. */
  53538. Phaser.RandomDataGenerator = function (seeds) {
  53539. if (seeds === undefined) { seeds = []; }
  53540. /**
  53541. * @property {number} c - Internal var.
  53542. * @private
  53543. */
  53544. this.c = 1;
  53545. /**
  53546. * @property {number} s0 - Internal var.
  53547. * @private
  53548. */
  53549. this.s0 = 0;
  53550. /**
  53551. * @property {number} s1 - Internal var.
  53552. * @private
  53553. */
  53554. this.s1 = 0;
  53555. /**
  53556. * @property {number} s2 - Internal var.
  53557. * @private
  53558. */
  53559. this.s2 = 0;
  53560. if (typeof seeds === 'string')
  53561. {
  53562. this.state(seeds);
  53563. }
  53564. else
  53565. {
  53566. this.sow(seeds);
  53567. }
  53568. };
  53569. Phaser.RandomDataGenerator.prototype = {
  53570. /**
  53571. * Private random helper.
  53572. *
  53573. * @method Phaser.RandomDataGenerator#rnd
  53574. * @private
  53575. * @return {number}
  53576. */
  53577. rnd: function () {
  53578. var t = 2091639 * this.s0 + this.c * 2.3283064365386963e-10; // 2^-32
  53579. this.c = t | 0;
  53580. this.s0 = this.s1;
  53581. this.s1 = this.s2;
  53582. this.s2 = t - this.c;
  53583. return this.s2;
  53584. },
  53585. /**
  53586. * Reset the seed of the random data generator.
  53587. *
  53588. * _Note_: the seed array is only processed up to the first `undefined` (or `null`) value, should such be present.
  53589. *
  53590. * @method Phaser.RandomDataGenerator#sow
  53591. * @param {any[]} seeds - The array of seeds: the `toString()` of each value is used.
  53592. */
  53593. sow: function (seeds) {
  53594. // Always reset to default seed
  53595. this.s0 = this.hash(' ');
  53596. this.s1 = this.hash(this.s0);
  53597. this.s2 = this.hash(this.s1);
  53598. this.c = 1;
  53599. if (!seeds)
  53600. {
  53601. return;
  53602. }
  53603. // Apply any seeds
  53604. for (var i = 0; i < seeds.length && (seeds[i] != null); i++)
  53605. {
  53606. var seed = seeds[i];
  53607. this.s0 -= this.hash(seed);
  53608. this.s0 += ~~(this.s0 < 0);
  53609. this.s1 -= this.hash(seed);
  53610. this.s1 += ~~(this.s1 < 0);
  53611. this.s2 -= this.hash(seed);
  53612. this.s2 += ~~(this.s2 < 0);
  53613. }
  53614. },
  53615. /**
  53616. * Internal method that creates a seed hash.
  53617. *
  53618. * @method Phaser.RandomDataGenerator#hash
  53619. * @private
  53620. * @param {any} data
  53621. * @return {number} hashed value.
  53622. */
  53623. hash: function (data) {
  53624. var h, i, n;
  53625. n = 0xefc8249d;
  53626. data = data.toString();
  53627. for (i = 0; i < data.length; i++) {
  53628. n += data.charCodeAt(i);
  53629. h = 0.02519603282416938 * n;
  53630. n = h >>> 0;
  53631. h -= n;
  53632. h *= n;
  53633. n = h >>> 0;
  53634. h -= n;
  53635. n += h * 0x100000000;// 2^32
  53636. }
  53637. return (n >>> 0) * 2.3283064365386963e-10;// 2^-32
  53638. },
  53639. /**
  53640. * Returns a random integer between 0 and 2^32.
  53641. *
  53642. * @method Phaser.RandomDataGenerator#integer
  53643. * @return {number} A random integer between 0 and 2^32.
  53644. */
  53645. integer: function() {
  53646. return this.rnd.apply(this) * 0x100000000;// 2^32
  53647. },
  53648. /**
  53649. * Returns a random real number between 0 and 1.
  53650. *
  53651. * @method Phaser.RandomDataGenerator#frac
  53652. * @return {number} A random real number between 0 and 1.
  53653. */
  53654. frac: function() {
  53655. return this.rnd.apply(this) + (this.rnd.apply(this) * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
  53656. },
  53657. /**
  53658. * Returns a random real number between 0 and 2^32.
  53659. *
  53660. * @method Phaser.RandomDataGenerator#real
  53661. * @return {number} A random real number between 0 and 2^32.
  53662. */
  53663. real: function() {
  53664. return this.integer() + this.frac();
  53665. },
  53666. /**
  53667. * Returns a random integer between and including min and max.
  53668. *
  53669. * @method Phaser.RandomDataGenerator#integerInRange
  53670. * @param {number} min - The minimum value in the range.
  53671. * @param {number} max - The maximum value in the range.
  53672. * @return {number} A random number between min and max.
  53673. */
  53674. integerInRange: function (min, max) {
  53675. return Math.floor(this.realInRange(0, max - min + 1) + min);
  53676. },
  53677. /**
  53678. * Returns a random integer between and including min and max.
  53679. * This method is an alias for RandomDataGenerator.integerInRange.
  53680. *
  53681. * @method Phaser.RandomDataGenerator#between
  53682. * @param {number} min - The minimum value in the range.
  53683. * @param {number} max - The maximum value in the range.
  53684. * @return {number} A random number between min and max.
  53685. */
  53686. between: function (min, max) {
  53687. return this.integerInRange(min, max);
  53688. },
  53689. /**
  53690. * Returns a random real number between min and max.
  53691. *
  53692. * @method Phaser.RandomDataGenerator#realInRange
  53693. * @param {number} min - The minimum value in the range.
  53694. * @param {number} max - The maximum value in the range.
  53695. * @return {number} A random number between min and max.
  53696. */
  53697. realInRange: function (min, max) {
  53698. return this.frac() * (max - min) + min;
  53699. },
  53700. /**
  53701. * Returns a random real number between -1 and 1.
  53702. *
  53703. * @method Phaser.RandomDataGenerator#normal
  53704. * @return {number} A random real number between -1 and 1.
  53705. */
  53706. normal: function () {
  53707. return 1 - 2 * this.frac();
  53708. },
  53709. /**
  53710. * Returns a valid RFC4122 version4 ID hex string from https://gist.github.com/1308368
  53711. *
  53712. * @method Phaser.RandomDataGenerator#uuid
  53713. * @return {string} A valid RFC4122 version4 ID hex string
  53714. */
  53715. uuid: function () {
  53716. var a = '';
  53717. var b = '';
  53718. for (b = a = ''; a++ < 36; b +=~a % 5 | a * 3&4 ? (a^15 ? 8^this.frac() * (a^20 ? 16 : 4) : 4).toString(16) : '-')
  53719. {
  53720. }
  53721. return b;
  53722. },
  53723. /**
  53724. * Returns a random member of `array`.
  53725. *
  53726. * @method Phaser.RandomDataGenerator#pick
  53727. * @param {Array} ary - An Array to pick a random member of.
  53728. * @return {any} A random member of the array.
  53729. */
  53730. pick: function (ary) {
  53731. return ary[this.integerInRange(0, ary.length - 1)];
  53732. },
  53733. /**
  53734. * Returns a sign to be used with multiplication operator.
  53735. *
  53736. * @method Phaser.RandomDataGenerator#sign
  53737. * @return {number} -1 or +1.
  53738. */
  53739. sign: function () {
  53740. return this.pick([-1, 1]);
  53741. },
  53742. /**
  53743. * Returns a random member of `array`, favoring the earlier entries.
  53744. *
  53745. * @method Phaser.RandomDataGenerator#weightedPick
  53746. * @param {Array} ary - An Array to pick a random member of.
  53747. * @return {any} A random member of the array.
  53748. */
  53749. weightedPick: function (ary) {
  53750. return ary[~~(Math.pow(this.frac(), 2) * (ary.length - 1) + 0.5)];
  53751. },
  53752. /**
  53753. * Returns a random timestamp between min and max, or between the beginning of 2000 and the end of 2020 if min and max aren't specified.
  53754. *
  53755. * @method Phaser.RandomDataGenerator#timestamp
  53756. * @param {number} min - The minimum value in the range.
  53757. * @param {number} max - The maximum value in the range.
  53758. * @return {number} A random timestamp between min and max.
  53759. */
  53760. timestamp: function (min, max) {
  53761. return this.realInRange(min || 946684800000, max || 1577862000000);
  53762. },
  53763. /**
  53764. * Returns a random angle between -180 and 180.
  53765. *
  53766. * @method Phaser.RandomDataGenerator#angle
  53767. * @return {number} A random number between -180 and 180.
  53768. */
  53769. angle: function() {
  53770. return this.integerInRange(-180, 180);
  53771. },
  53772. /**
  53773. * Gets or Sets the state of the generator. This allows you to retain the values
  53774. * that the generator is using between games, i.e. in a game save file.
  53775. *
  53776. * To seed this generator with a previously saved state you can pass it as the
  53777. * `seed` value in your game config, or call this method directly after Phaser has booted.
  53778. *
  53779. * Call this method with no parameters to return the current state.
  53780. *
  53781. * If providing a state it should match the same format that this method
  53782. * returns, which is a string with a header `!rnd` followed by the `c`,
  53783. * `s0`, `s1` and `s2` values respectively, each comma-delimited.
  53784. *
  53785. * @method Phaser.RandomDataGenerator#state
  53786. * @param {string} [state] - Generator state to be set.
  53787. * @return {string} The current state of the generator.
  53788. */
  53789. state: function (state) {
  53790. if (typeof state === 'string' && state.match(/^!rnd/))
  53791. {
  53792. state = state.split(',');
  53793. this.c = parseFloat(state[1]);
  53794. this.s0 = parseFloat(state[2]);
  53795. this.s1 = parseFloat(state[3]);
  53796. this.s2 = parseFloat(state[4]);
  53797. }
  53798. return ['!rnd', this.c, this.s0, this.s1, this.s2].join(',');
  53799. }
  53800. };
  53801. Phaser.RandomDataGenerator.prototype.constructor = Phaser.RandomDataGenerator;
  53802. /**
  53803. * @author Timo Hausmann
  53804. * @author Richard Davey <rich@photonstorm.com>
  53805. * @copyright 2016 Photon Storm Ltd.
  53806. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  53807. */
  53808. /**
  53809. * A QuadTree implementation. The original code was a conversion of the Java code posted to GameDevTuts.
  53810. * However I've tweaked it massively to add node indexing, removed lots of temp. var creation and significantly increased performance as a result.
  53811. * Original version at https://github.com/timohausmann/quadtree-js/
  53812. *
  53813. * @class Phaser.QuadTree
  53814. * @constructor
  53815. * @param {number} x - The top left coordinate of the quadtree.
  53816. * @param {number} y - The top left coordinate of the quadtree.
  53817. * @param {number} width - The width of the quadtree in pixels.
  53818. * @param {number} height - The height of the quadtree in pixels.
  53819. * @param {number} [maxObjects=10] - The maximum number of objects per node.
  53820. * @param {number} [maxLevels=4] - The maximum number of levels to iterate to.
  53821. * @param {number} [level=0] - Which level is this?
  53822. */
  53823. Phaser.QuadTree = function(x, y, width, height, maxObjects, maxLevels, level) {
  53824. /**
  53825. * @property {number} maxObjects - The maximum number of objects per node.
  53826. * @default
  53827. */
  53828. this.maxObjects = 10;
  53829. /**
  53830. * @property {number} maxLevels - The maximum number of levels to break down to.
  53831. * @default
  53832. */
  53833. this.maxLevels = 4;
  53834. /**
  53835. * @property {number} level - The current level.
  53836. */
  53837. this.level = 0;
  53838. /**
  53839. * @property {object} bounds - Object that contains the quadtree bounds.
  53840. */
  53841. this.bounds = {};
  53842. /**
  53843. * @property {array} objects - Array of quadtree children.
  53844. */
  53845. this.objects = [];
  53846. /**
  53847. * @property {array} nodes - Array of associated child nodes.
  53848. */
  53849. this.nodes = [];
  53850. /**
  53851. * @property {array} _empty - Internal empty array.
  53852. * @private
  53853. */
  53854. this._empty = [];
  53855. this.reset(x, y, width, height, maxObjects, maxLevels, level);
  53856. };
  53857. Phaser.QuadTree.prototype = {
  53858. /**
  53859. * Resets the QuadTree.
  53860. *
  53861. * @method Phaser.QuadTree#reset
  53862. * @param {number} x - The top left coordinate of the quadtree.
  53863. * @param {number} y - The top left coordinate of the quadtree.
  53864. * @param {number} width - The width of the quadtree in pixels.
  53865. * @param {number} height - The height of the quadtree in pixels.
  53866. * @param {number} [maxObjects=10] - The maximum number of objects per node.
  53867. * @param {number} [maxLevels=4] - The maximum number of levels to iterate to.
  53868. * @param {number} [level=0] - Which level is this?
  53869. */
  53870. reset: function (x, y, width, height, maxObjects, maxLevels, level) {
  53871. this.maxObjects = maxObjects || 10;
  53872. this.maxLevels = maxLevels || 4;
  53873. this.level = level || 0;
  53874. this.bounds = {
  53875. x: Math.round(x),
  53876. y: Math.round(y),
  53877. width: width,
  53878. height: height,
  53879. subWidth: Math.floor(width / 2),
  53880. subHeight: Math.floor(height / 2),
  53881. right: Math.round(x) + Math.floor(width / 2),
  53882. bottom: Math.round(y) + Math.floor(height / 2)
  53883. };
  53884. this.objects.length = 0;
  53885. this.nodes.length = 0;
  53886. },
  53887. /**
  53888. * Populates this quadtree with the children of the given Group. In order to be added the child must exist and have a body property.
  53889. *
  53890. * @method Phaser.QuadTree#populate
  53891. * @param {Phaser.Group} group - The Group to add to the quadtree.
  53892. */
  53893. populate: function (group) {
  53894. group.forEach(this.populateHandler, this, true);
  53895. },
  53896. /**
  53897. * Handler for the populate method.
  53898. *
  53899. * @method Phaser.QuadTree#populateHandler
  53900. * @param {Phaser.Sprite|object} sprite - The Sprite to check.
  53901. */
  53902. populateHandler: function (sprite) {
  53903. if (sprite.body && sprite.exists)
  53904. {
  53905. this.insert(sprite.body);
  53906. }
  53907. },
  53908. /**
  53909. * Split the node into 4 subnodes
  53910. *
  53911. * @method Phaser.QuadTree#split
  53912. */
  53913. split: function () {
  53914. // top right node
  53915. this.nodes[0] = new Phaser.QuadTree(this.bounds.right, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, (this.level + 1));
  53916. // top left node
  53917. this.nodes[1] = new Phaser.QuadTree(this.bounds.x, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, (this.level + 1));
  53918. // bottom left node
  53919. this.nodes[2] = new Phaser.QuadTree(this.bounds.x, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, (this.level + 1));
  53920. // bottom right node
  53921. this.nodes[3] = new Phaser.QuadTree(this.bounds.right, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, (this.level + 1));
  53922. },
  53923. /**
  53924. * Insert the object into the node. If the node exceeds the capacity, it will split and add all objects to their corresponding subnodes.
  53925. *
  53926. * @method Phaser.QuadTree#insert
  53927. * @param {Phaser.Physics.Arcade.Body|object} body - The Body object to insert into the quadtree. Can be any object so long as it exposes x, y, right and bottom properties.
  53928. */
  53929. insert: function (body) {
  53930. var i = 0;
  53931. var index;
  53932. // if we have subnodes ...
  53933. if (this.nodes[0] != null)
  53934. {
  53935. index = this.getIndex(body);
  53936. if (index !== -1)
  53937. {
  53938. this.nodes[index].insert(body);
  53939. return;
  53940. }
  53941. }
  53942. this.objects.push(body);
  53943. if (this.objects.length > this.maxObjects && this.level < this.maxLevels)
  53944. {
  53945. // Split if we don't already have subnodes
  53946. if (this.nodes[0] == null)
  53947. {
  53948. this.split();
  53949. }
  53950. // Add objects to subnodes
  53951. while (i < this.objects.length)
  53952. {
  53953. index = this.getIndex(this.objects[i]);
  53954. if (index !== -1)
  53955. {
  53956. // this is expensive - see what we can do about it
  53957. this.nodes[index].insert(this.objects.splice(i, 1)[0]);
  53958. }
  53959. else
  53960. {
  53961. i++;
  53962. }
  53963. }
  53964. }
  53965. },
  53966. /**
  53967. * Determine which node the object belongs to.
  53968. *
  53969. * @method Phaser.QuadTree#getIndex
  53970. * @param {Phaser.Rectangle|object} rect - The bounds in which to check.
  53971. * @return {number} index - Index of the subnode (0-3), or -1 if rect cannot completely fit within a subnode and is part of the parent node.
  53972. */
  53973. getIndex: function (rect) {
  53974. // default is that rect doesn't fit, i.e. it straddles the internal quadrants
  53975. var index = -1;
  53976. if (rect.x < this.bounds.right && rect.right < this.bounds.right)
  53977. {
  53978. if (rect.y < this.bounds.bottom && rect.bottom < this.bounds.bottom)
  53979. {
  53980. // rect fits within the top-left quadrant of this quadtree
  53981. index = 1;
  53982. }
  53983. else if (rect.y > this.bounds.bottom)
  53984. {
  53985. // rect fits within the bottom-left quadrant of this quadtree
  53986. index = 2;
  53987. }
  53988. }
  53989. else if (rect.x > this.bounds.right)
  53990. {
  53991. // rect can completely fit within the right quadrants
  53992. if (rect.y < this.bounds.bottom && rect.bottom < this.bounds.bottom)
  53993. {
  53994. // rect fits within the top-right quadrant of this quadtree
  53995. index = 0;
  53996. }
  53997. else if (rect.y > this.bounds.bottom)
  53998. {
  53999. // rect fits within the bottom-right quadrant of this quadtree
  54000. index = 3;
  54001. }
  54002. }
  54003. return index;
  54004. },
  54005. /**
  54006. * Return all objects that could collide with the given Sprite or Rectangle.
  54007. *
  54008. * @method Phaser.QuadTree#retrieve
  54009. * @param {Phaser.Sprite|Phaser.Rectangle} source - The source object to check the QuadTree against. Either a Sprite or Rectangle.
  54010. * @return {array} - Array with all detected objects.
  54011. */
  54012. retrieve: function (source) {
  54013. if (source instanceof Phaser.Rectangle)
  54014. {
  54015. var returnObjects = this.objects;
  54016. var index = this.getIndex(source);
  54017. }
  54018. else
  54019. {
  54020. if (!source.body)
  54021. {
  54022. return this._empty;
  54023. }
  54024. var returnObjects = this.objects;
  54025. var index = this.getIndex(source.body);
  54026. }
  54027. if (this.nodes[0])
  54028. {
  54029. // If rect fits into a subnode ..
  54030. if (index !== -1)
  54031. {
  54032. returnObjects = returnObjects.concat(this.nodes[index].retrieve(source));
  54033. }
  54034. else
  54035. {
  54036. // If rect does not fit into a subnode, check it against all subnodes (unrolled for speed)
  54037. returnObjects = returnObjects.concat(this.nodes[0].retrieve(source));
  54038. returnObjects = returnObjects.concat(this.nodes[1].retrieve(source));
  54039. returnObjects = returnObjects.concat(this.nodes[2].retrieve(source));
  54040. returnObjects = returnObjects.concat(this.nodes[3].retrieve(source));
  54041. }
  54042. }
  54043. return returnObjects;
  54044. },
  54045. /**
  54046. * Clear the quadtree.
  54047. * @method Phaser.QuadTree#clear
  54048. */
  54049. clear: function () {
  54050. this.objects.length = 0;
  54051. var i = this.nodes.length;
  54052. while (i--)
  54053. {
  54054. this.nodes[i].clear();
  54055. this.nodes.splice(i, 1);
  54056. }
  54057. this.nodes.length = 0;
  54058. }
  54059. };
  54060. Phaser.QuadTree.prototype.constructor = Phaser.QuadTree;
  54061. /**
  54062. * Javascript QuadTree
  54063. * @version 1.0
  54064. *
  54065. * @version 1.3, March 11th 2014
  54066. * @author Richard Davey
  54067. * The original code was a conversion of the Java code posted to GameDevTuts. However I've tweaked
  54068. * it massively to add node indexing, removed lots of temp. var creation and significantly
  54069. * increased performance as a result.
  54070. *
  54071. * Original version at https://github.com/timohausmann/quadtree-js/
  54072. */
  54073. /**
  54074. * @copyright © 2012 Timo Hausmann
  54075. *
  54076. * Permission is hereby granted, free of charge, to any person obtaining
  54077. * a copy of this software and associated documentation files (the
  54078. * "Software"), to deal in the Software without restriction, including
  54079. * without limitation the rights to use, copy, modify, merge, publish,
  54080. * distribute, sublicense, and/or sell copies of the Software, and to
  54081. * permit persons to whom the Software is furnished to do so, subject to
  54082. * the following conditions:
  54083. *
  54084. * The above copyright notice and this permission notice shall be
  54085. * included in all copies or substantial portions of the Software.
  54086. *
  54087. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  54088. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  54089. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  54090. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  54091. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  54092. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  54093. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  54094. */
  54095. /**
  54096. * @author Richard Davey <rich@photonstorm.com>
  54097. * @copyright 2016 Photon Storm Ltd.
  54098. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  54099. */
  54100. /**
  54101. * Phaser.Net handles browser URL related tasks such as checking host names, domain names and query string manipulation.
  54102. *
  54103. * @class Phaser.Net
  54104. * @constructor
  54105. * @param {Phaser.Game} game - A reference to the currently running game.
  54106. */
  54107. Phaser.Net = function (game) {
  54108. this.game = game;
  54109. };
  54110. Phaser.Net.prototype = {
  54111. /**
  54112. * Returns the hostname given by the browser.
  54113. *
  54114. * @method Phaser.Net#getHostName
  54115. * @return {string}
  54116. */
  54117. getHostName: function () {
  54118. if (window.location && window.location.hostname) {
  54119. return window.location.hostname;
  54120. }
  54121. return null;
  54122. },
  54123. /**
  54124. * Compares the given domain name against the hostname of the browser containing the game.
  54125. * If the domain name is found it returns true.
  54126. * You can specify a part of a domain, for example 'google' would match 'google.com', 'google.co.uk', etc.
  54127. * Do not include 'http://' at the start.
  54128. *
  54129. * @method Phaser.Net#checkDomainName
  54130. * @param {string} domain
  54131. * @return {boolean} true if the given domain fragment can be found in the window.location.hostname
  54132. */
  54133. checkDomainName: function (domain) {
  54134. return window.location.hostname.indexOf(domain) !== -1;
  54135. },
  54136. /**
  54137. * Updates a value on the Query String and returns it in full.
  54138. * If the value doesn't already exist it is set.
  54139. * If the value exists it is replaced with the new value given. If you don't provide a new value it is removed from the query string.
  54140. * Optionally you can redirect to the new url, or just return it as a string.
  54141. *
  54142. * @method Phaser.Net#updateQueryString
  54143. * @param {string} key - The querystring key to update.
  54144. * @param {string} value - The new value to be set. If it already exists it will be replaced.
  54145. * @param {boolean} redirect - If true the browser will issue a redirect to the url with the new querystring.
  54146. * @param {string} url - The URL to modify. If none is given it uses window.location.href.
  54147. * @return {string} If redirect is false then the modified url and query string is returned.
  54148. */
  54149. updateQueryString: function (key, value, redirect, url) {
  54150. if (redirect === undefined) { redirect = false; }
  54151. if (url === undefined || url === '') { url = window.location.href; }
  54152. var output = '';
  54153. var re = new RegExp("([?|&])" + key + "=.*?(&|#|$)(.*)", "gi");
  54154. if (re.test(url))
  54155. {
  54156. if (typeof value !== 'undefined' && value !== null)
  54157. {
  54158. output = url.replace(re, '$1' + key + "=" + value + '$2$3');
  54159. }
  54160. else
  54161. {
  54162. output = url.replace(re, '$1$3').replace(/(&|\?)$/, '');
  54163. }
  54164. }
  54165. else
  54166. {
  54167. if (typeof value !== 'undefined' && value !== null)
  54168. {
  54169. var separator = url.indexOf('?') !== -1 ? '&' : '?';
  54170. var hash = url.split('#');
  54171. url = hash[0] + separator + key + '=' + value;
  54172. if (hash[1]) {
  54173. url += '#' + hash[1];
  54174. }
  54175. output = url;
  54176. }
  54177. else
  54178. {
  54179. output = url;
  54180. }
  54181. }
  54182. if (redirect)
  54183. {
  54184. window.location.href = output;
  54185. }
  54186. else
  54187. {
  54188. return output;
  54189. }
  54190. },
  54191. /**
  54192. * Returns the Query String as an object.
  54193. * If you specify a parameter it will return just the value of that parameter, should it exist.
  54194. *
  54195. * @method Phaser.Net#getQueryString
  54196. * @param {string} [parameter=''] - If specified this will return just the value for that key.
  54197. * @return {string|object} An object containing the key value pairs found in the query string or just the value if a parameter was given.
  54198. */
  54199. getQueryString: function (parameter) {
  54200. if (parameter === undefined) { parameter = ''; }
  54201. var output = {};
  54202. var keyValues = location.search.substring(1).split('&');
  54203. for (var i in keyValues)
  54204. {
  54205. var key = keyValues[i].split('=');
  54206. if (key.length > 1)
  54207. {
  54208. if (parameter && parameter === this.decodeURI(key[0]))
  54209. {
  54210. return this.decodeURI(key[1]);
  54211. }
  54212. else
  54213. {
  54214. output[this.decodeURI(key[0])] = this.decodeURI(key[1]);
  54215. }
  54216. }
  54217. }
  54218. return output;
  54219. },
  54220. /**
  54221. * Takes a Uniform Resource Identifier (URI) component (previously created by encodeURIComponent or by a similar routine) and
  54222. * decodes it, replacing \ with spaces in the return. Used internally by the Net classes.
  54223. *
  54224. * @method Phaser.Net#decodeURI
  54225. * @param {string} value - The URI component to be decoded.
  54226. * @return {string} The decoded value.
  54227. */
  54228. decodeURI: function (value) {
  54229. return decodeURIComponent(value.replace(/\+/g, " "));
  54230. }
  54231. };
  54232. Phaser.Net.prototype.constructor = Phaser.Net;
  54233. /**
  54234. * @author Richard Davey <rich@photonstorm.com>
  54235. * @copyright 2016 Photon Storm Ltd.
  54236. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  54237. */
  54238. /**
  54239. * Phaser.Game has a single instance of the TweenManager through which all Tween objects are created and updated.
  54240. * Tweens are hooked into the game clock and pause system, adjusting based on the game state.
  54241. *
  54242. * TweenManager is based heavily on tween.js by http://soledadpenades.com.
  54243. * The difference being that tweens belong to a games instance of TweenManager, rather than to a global TWEEN object.
  54244. * It also has callbacks swapped for Signals and a few issues patched with regard to properties and completion errors.
  54245. * Please see https://github.com/sole/tween.js for a full list of contributors.
  54246. *
  54247. * @class Phaser.TweenManager
  54248. * @constructor
  54249. * @param {Phaser.Game} game - A reference to the currently running game.
  54250. */
  54251. Phaser.TweenManager = function (game) {
  54252. /**
  54253. * @property {Phaser.Game} game - Local reference to game.
  54254. */
  54255. this.game = game;
  54256. /**
  54257. * Are all newly created Tweens frame or time based? A frame based tween will use the physics elapsed timer when updating. This means
  54258. * it will retain the same consistent frame rate, regardless of the speed of the device. The duration value given should
  54259. * be given in frames.
  54260. *
  54261. * If the Tween uses a time based update (which is the default) then the duration is given in milliseconds.
  54262. * In this situation a 2000ms tween will last exactly 2 seconds, regardless of the device and how many visual updates the tween
  54263. * has actually been through. For very short tweens you may wish to experiment with a frame based update instead.
  54264. * @property {boolean} frameBased
  54265. * @default
  54266. */
  54267. this.frameBased = false;
  54268. /**
  54269. * @property {array<Phaser.Tween>} _tweens - All of the currently running tweens.
  54270. * @private
  54271. */
  54272. this._tweens = [];
  54273. /**
  54274. * @property {array<Phaser.Tween>} _add - All of the tweens queued to be added in the next update.
  54275. * @private
  54276. */
  54277. this._add = [];
  54278. this.easeMap = {
  54279. "Power0": Phaser.Easing.Power0,
  54280. "Power1": Phaser.Easing.Power1,
  54281. "Power2": Phaser.Easing.Power2,
  54282. "Power3": Phaser.Easing.Power3,
  54283. "Power4": Phaser.Easing.Power4,
  54284. "Linear": Phaser.Easing.Linear.None,
  54285. "Quad": Phaser.Easing.Quadratic.Out,
  54286. "Cubic": Phaser.Easing.Cubic.Out,
  54287. "Quart": Phaser.Easing.Quartic.Out,
  54288. "Quint": Phaser.Easing.Quintic.Out,
  54289. "Sine": Phaser.Easing.Sinusoidal.Out,
  54290. "Expo": Phaser.Easing.Exponential.Out,
  54291. "Circ": Phaser.Easing.Circular.Out,
  54292. "Elastic": Phaser.Easing.Elastic.Out,
  54293. "Back": Phaser.Easing.Back.Out,
  54294. "Bounce": Phaser.Easing.Bounce.Out,
  54295. "Quad.easeIn": Phaser.Easing.Quadratic.In,
  54296. "Cubic.easeIn": Phaser.Easing.Cubic.In,
  54297. "Quart.easeIn": Phaser.Easing.Quartic.In,
  54298. "Quint.easeIn": Phaser.Easing.Quintic.In,
  54299. "Sine.easeIn": Phaser.Easing.Sinusoidal.In,
  54300. "Expo.easeIn": Phaser.Easing.Exponential.In,
  54301. "Circ.easeIn": Phaser.Easing.Circular.In,
  54302. "Elastic.easeIn": Phaser.Easing.Elastic.In,
  54303. "Back.easeIn": Phaser.Easing.Back.In,
  54304. "Bounce.easeIn": Phaser.Easing.Bounce.In,
  54305. "Quad.easeOut": Phaser.Easing.Quadratic.Out,
  54306. "Cubic.easeOut": Phaser.Easing.Cubic.Out,
  54307. "Quart.easeOut": Phaser.Easing.Quartic.Out,
  54308. "Quint.easeOut": Phaser.Easing.Quintic.Out,
  54309. "Sine.easeOut": Phaser.Easing.Sinusoidal.Out,
  54310. "Expo.easeOut": Phaser.Easing.Exponential.Out,
  54311. "Circ.easeOut": Phaser.Easing.Circular.Out,
  54312. "Elastic.easeOut": Phaser.Easing.Elastic.Out,
  54313. "Back.easeOut": Phaser.Easing.Back.Out,
  54314. "Bounce.easeOut": Phaser.Easing.Bounce.Out,
  54315. "Quad.easeInOut": Phaser.Easing.Quadratic.InOut,
  54316. "Cubic.easeInOut": Phaser.Easing.Cubic.InOut,
  54317. "Quart.easeInOut": Phaser.Easing.Quartic.InOut,
  54318. "Quint.easeInOut": Phaser.Easing.Quintic.InOut,
  54319. "Sine.easeInOut": Phaser.Easing.Sinusoidal.InOut,
  54320. "Expo.easeInOut": Phaser.Easing.Exponential.InOut,
  54321. "Circ.easeInOut": Phaser.Easing.Circular.InOut,
  54322. "Elastic.easeInOut": Phaser.Easing.Elastic.InOut,
  54323. "Back.easeInOut": Phaser.Easing.Back.InOut,
  54324. "Bounce.easeInOut": Phaser.Easing.Bounce.InOut
  54325. };
  54326. this.game.onPause.add(this._pauseAll, this);
  54327. this.game.onResume.add(this._resumeAll, this);
  54328. };
  54329. Phaser.TweenManager.prototype = {
  54330. /**
  54331. * Get all the tween objects in an array.
  54332. * @method Phaser.TweenManager#getAll
  54333. * @returns {Phaser.Tween[]} Array with all tween objects.
  54334. */
  54335. getAll: function () {
  54336. return this._tweens;
  54337. },
  54338. /**
  54339. * Remove all tweens running and in the queue. Doesn't call any of the tween onComplete events.
  54340. * @method Phaser.TweenManager#removeAll
  54341. */
  54342. removeAll: function () {
  54343. for (var i = 0; i < this._tweens.length; i++)
  54344. {
  54345. this._tweens[i].pendingDelete = true;
  54346. }
  54347. this._add = [];
  54348. },
  54349. /**
  54350. * Remove all tweens from a specific object, array of objects or Group.
  54351. *
  54352. * @method Phaser.TweenManager#removeFrom
  54353. * @param {object|object[]|Phaser.Group} obj - The object you want to remove the tweens from.
  54354. * @param {boolean} [children=true] - If passing a group, setting this to true will remove the tweens from all of its children instead of the group itself.
  54355. */
  54356. removeFrom: function (obj, children) {
  54357. if (children === undefined) { children = true; }
  54358. var i;
  54359. var len;
  54360. if (Array.isArray(obj))
  54361. {
  54362. for (i = 0, len = obj.length; i < len; i++)
  54363. {
  54364. this.removeFrom(obj[i]);
  54365. }
  54366. }
  54367. else if (obj.type === Phaser.GROUP && children)
  54368. {
  54369. for (var i = 0, len = obj.children.length; i < len; i++)
  54370. {
  54371. this.removeFrom(obj.children[i]);
  54372. }
  54373. }
  54374. else
  54375. {
  54376. for (i = 0, len = this._tweens.length; i < len; i++)
  54377. {
  54378. if (obj === this._tweens[i].target)
  54379. {
  54380. this.remove(this._tweens[i]);
  54381. }
  54382. }
  54383. for (i = 0, len = this._add.length; i < len; i++)
  54384. {
  54385. if (obj === this._add[i].target)
  54386. {
  54387. this.remove(this._add[i]);
  54388. }
  54389. }
  54390. }
  54391. },
  54392. /**
  54393. * Add a new tween into the TweenManager.
  54394. *
  54395. * @method Phaser.TweenManager#add
  54396. * @param {Phaser.Tween} tween - The tween object you want to add.
  54397. * @returns {Phaser.Tween} The tween object you added to the manager.
  54398. */
  54399. add: function (tween) {
  54400. tween._manager = this;
  54401. this._add.push(tween);
  54402. },
  54403. /**
  54404. * Create a tween object for a specific object. The object can be any JavaScript object or Phaser object such as Sprite.
  54405. *
  54406. * @method Phaser.TweenManager#create
  54407. * @param {object} object - Object the tween will be run on.
  54408. * @returns {Phaser.Tween} The newly created tween object.
  54409. */
  54410. create: function (object) {
  54411. return new Phaser.Tween(object, this.game, this);
  54412. },
  54413. /**
  54414. * Remove a tween from this manager.
  54415. *
  54416. * @method Phaser.TweenManager#remove
  54417. * @param {Phaser.Tween} tween - The tween object you want to remove.
  54418. */
  54419. remove: function (tween) {
  54420. var i = this._tweens.indexOf(tween);
  54421. if (i !== -1)
  54422. {
  54423. this._tweens[i].pendingDelete = true;
  54424. }
  54425. else
  54426. {
  54427. i = this._add.indexOf(tween);
  54428. if (i !== -1)
  54429. {
  54430. this._add[i].pendingDelete = true;
  54431. }
  54432. }
  54433. },
  54434. /**
  54435. * Update all the tween objects you added to this manager.
  54436. *
  54437. * @method Phaser.TweenManager#update
  54438. * @returns {boolean} Return false if there's no tween to update, otherwise return true.
  54439. */
  54440. update: function () {
  54441. var addTweens = this._add.length;
  54442. var numTweens = this._tweens.length;
  54443. if (numTweens === 0 && addTweens === 0)
  54444. {
  54445. return false;
  54446. }
  54447. var i = 0;
  54448. while (i < numTweens)
  54449. {
  54450. if (this._tweens[i].update(this.game.time.time))
  54451. {
  54452. i++;
  54453. }
  54454. else
  54455. {
  54456. this._tweens.splice(i, 1);
  54457. numTweens--;
  54458. }
  54459. }
  54460. // If there are any new tweens to be added, do so now - otherwise they can be spliced out of the array before ever running
  54461. if (addTweens > 0)
  54462. {
  54463. this._tweens = this._tweens.concat(this._add);
  54464. this._add.length = 0;
  54465. }
  54466. return true;
  54467. },
  54468. /**
  54469. * Checks to see if a particular Sprite is currently being tweened.
  54470. *
  54471. * @method Phaser.TweenManager#isTweening
  54472. * @param {object} object - The object to check for tweens against.
  54473. * @returns {boolean} Returns true if the object is currently being tweened, false if not.
  54474. */
  54475. isTweening: function(object) {
  54476. return this._tweens.some(function(tween) {
  54477. return tween.target === object;
  54478. });
  54479. },
  54480. /**
  54481. * Private. Called by game focus loss. Pauses all currently running tweens.
  54482. *
  54483. * @method Phaser.TweenManager#_pauseAll
  54484. * @private
  54485. */
  54486. _pauseAll: function () {
  54487. for (var i = this._tweens.length - 1; i >= 0; i--)
  54488. {
  54489. this._tweens[i]._pause();
  54490. }
  54491. },
  54492. /**
  54493. * Private. Called by game focus loss. Resumes all currently paused tweens.
  54494. *
  54495. * @method Phaser.TweenManager#_resumeAll
  54496. * @private
  54497. */
  54498. _resumeAll: function () {
  54499. for (var i = this._tweens.length - 1; i >= 0; i--)
  54500. {
  54501. this._tweens[i]._resume();
  54502. }
  54503. },
  54504. /**
  54505. * Pauses all currently running tweens.
  54506. *
  54507. * @method Phaser.TweenManager#pauseAll
  54508. */
  54509. pauseAll: function () {
  54510. for (var i = this._tweens.length - 1; i >= 0; i--)
  54511. {
  54512. this._tweens[i].pause();
  54513. }
  54514. },
  54515. /**
  54516. * Resumes all currently paused tweens.
  54517. *
  54518. * @method Phaser.TweenManager#resumeAll
  54519. */
  54520. resumeAll: function () {
  54521. for (var i = this._tweens.length - 1; i >= 0; i--)
  54522. {
  54523. this._tweens[i].resume(true);
  54524. }
  54525. }
  54526. };
  54527. Phaser.TweenManager.prototype.constructor = Phaser.TweenManager;
  54528. /**
  54529. * @author Richard Davey <rich@photonstorm.com>
  54530. * @copyright 2016 Photon Storm Ltd.
  54531. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  54532. */
  54533. /**
  54534. * A Tween allows you to alter one or more properties of a target object over a defined period of time.
  54535. * This can be used for things such as alpha fading Sprites, scaling them or motion.
  54536. * Use `Tween.to` or `Tween.from` to set-up the tween values. You can create multiple tweens on the same object
  54537. * by calling Tween.to multiple times on the same Tween. Additional tweens specified in this way become "child" tweens and
  54538. * are played through in sequence. You can use Tween.timeScale and Tween.reverse to control the playback of this Tween and all of its children.
  54539. *
  54540. * @class Phaser.Tween
  54541. * @constructor
  54542. * @param {object} target - The target object, such as a Phaser.Sprite or Phaser.Sprite.scale.
  54543. * @param {Phaser.Game} game - Current game instance.
  54544. * @param {Phaser.TweenManager} manager - The TweenManager responsible for looking after this Tween.
  54545. */
  54546. Phaser.Tween = function (target, game, manager) {
  54547. /**
  54548. * @property {Phaser.Game} game - A reference to the currently running Game.
  54549. */
  54550. this.game = game;
  54551. /**
  54552. * @property {object} target - The target object, such as a Phaser.Sprite or property like Phaser.Sprite.scale.
  54553. */
  54554. this.target = target;
  54555. /**
  54556. * @property {Phaser.TweenManager} manager - Reference to the TweenManager responsible for updating this Tween.
  54557. */
  54558. this.manager = manager;
  54559. /**
  54560. * @property {Array} timeline - An Array of TweenData objects that comprise the different parts of this Tween.
  54561. */
  54562. this.timeline = [];
  54563. /**
  54564. * If set to `true` the current tween will play in reverse.
  54565. * If the tween hasn't yet started this has no effect.
  54566. * If there are child tweens then all child tweens will play in reverse from the current point.
  54567. * @property {boolean} reverse
  54568. * @default
  54569. */
  54570. this.reverse = false;
  54571. /**
  54572. * The speed at which the tweens will run. A value of 1 means it will match the game frame rate. 0.5 will run at half the frame rate. 2 at double the frame rate, etc.
  54573. * If a tweens duration is 1 second but timeScale is 0.5 then it will take 2 seconds to complete.
  54574. *
  54575. * @property {number} timeScale
  54576. * @default
  54577. */
  54578. this.timeScale = 1;
  54579. /**
  54580. * @property {number} repeatCounter - If the Tween and any child tweens are set to repeat this contains the current repeat count.
  54581. */
  54582. this.repeatCounter = 0;
  54583. /**
  54584. * @property {boolean} pendingDelete - True if this Tween is ready to be deleted by the TweenManager.
  54585. * @default
  54586. * @readonly
  54587. */
  54588. this.pendingDelete = false;
  54589. /**
  54590. * The onStart event is fired when the Tween begins. If there is a delay before the tween starts then onStart fires after the delay is finished.
  54591. * It will be sent 2 parameters: the target object and this tween.
  54592. * @property {Phaser.Signal} onStart
  54593. */
  54594. this.onStart = new Phaser.Signal();
  54595. /**
  54596. * The onLoop event is fired if the Tween, or any child tweens loop.
  54597. * It will be sent 2 parameters: the target object and this tween.
  54598. *
  54599. * @property {Phaser.Signal} onLoop
  54600. */
  54601. this.onLoop = new Phaser.Signal();
  54602. /**
  54603. * The onRepeat event is fired if the Tween and all of its children repeats. If this tween has no children this will never be fired.
  54604. * It will be sent 2 parameters: the target object and this tween.
  54605. * @property {Phaser.Signal} onRepeat
  54606. */
  54607. this.onRepeat = new Phaser.Signal();
  54608. /**
  54609. * The onChildComplete event is fired when the Tween or any of its children completes.
  54610. * Fires every time a child completes unless a child is set to repeat forever.
  54611. * It will be sent 2 parameters: the target object and this tween.
  54612. * @property {Phaser.Signal} onChildComplete
  54613. */
  54614. this.onChildComplete = new Phaser.Signal();
  54615. /**
  54616. * The onComplete event is fired when the Tween and all of its children completes. Does not fire if the Tween is set to loop or repeatAll(-1).
  54617. * It will be sent 2 parameters: the target object and this tween.
  54618. * @property {Phaser.Signal} onComplete
  54619. */
  54620. this.onComplete = new Phaser.Signal();
  54621. /**
  54622. * @property {boolean} isRunning - If the tween is running this is set to true, otherwise false. Tweens that are in a delayed state or waiting to start are considered as being running.
  54623. * @default
  54624. */
  54625. this.isRunning = false;
  54626. /**
  54627. * @property {number} current - The current Tween child being run.
  54628. * @default
  54629. * @readonly
  54630. */
  54631. this.current = 0;
  54632. /**
  54633. * @property {object} properties - Target property cache used when building the child data values.
  54634. */
  54635. this.properties = {};
  54636. /**
  54637. * @property {Phaser.Tween} chainedTween - If this Tween is chained to another this holds a reference to it.
  54638. */
  54639. this.chainedTween = null;
  54640. /**
  54641. * @property {boolean} isPaused - Is this Tween paused or not?
  54642. * @default
  54643. */
  54644. this.isPaused = false;
  54645. /**
  54646. * Is this Tween frame or time based? A frame based tween will use the physics elapsed timer when updating. This means
  54647. * it will retain the same consistent frame rate, regardless of the speed of the device. The duration value given should
  54648. * be given in frames.
  54649. *
  54650. * If the Tween uses a time based update (which is the default) then the duration is given in milliseconds.
  54651. * In this situation a 2000ms tween will last exactly 2 seconds, regardless of the device and how many visual updates the tween
  54652. * has actually been through. For very short tweens you may wish to experiment with a frame based update instead.
  54653. *
  54654. * The default value is whatever you've set in TweenManager.frameBased.
  54655. *
  54656. * @property {boolean} frameBased
  54657. * @default
  54658. */
  54659. this.frameBased = manager.frameBased;
  54660. /**
  54661. * @property {function} _onUpdateCallback - An onUpdate callback.
  54662. * @private
  54663. * @default null
  54664. */
  54665. this._onUpdateCallback = null;
  54666. /**
  54667. * @property {object} _onUpdateCallbackContext - The context in which to call the onUpdate callback.
  54668. * @private
  54669. * @default null
  54670. */
  54671. this._onUpdateCallbackContext = null;
  54672. /**
  54673. * @property {number} _pausedTime - Private pause timer.
  54674. * @private
  54675. * @default
  54676. */
  54677. this._pausedTime = 0;
  54678. /**
  54679. * @property {boolean} _codePaused - Was the Tween paused by code or by Game focus loss?
  54680. * @private
  54681. */
  54682. this._codePaused = false;
  54683. /**
  54684. * @property {boolean} _hasStarted - Internal var to track if the Tween has started yet or not.
  54685. * @private
  54686. */
  54687. this._hasStarted = false;
  54688. };
  54689. /**
  54690. * A helper for tweening {@link Phaser.Color.createColor color objects}.
  54691. *
  54692. * It can be passed to {@link #onUpdateCallback}.
  54693. *
  54694. * ```javascript
  54695. * var color = Phaser.Color.createColor(255, 0, 0); // red
  54696. *
  54697. * var tween = game.add.tween(color).to({
  54698. * r: 0, g: 0, b: 255 // blue
  54699. * });
  54700. *
  54701. * tween.onUpdateCallback(Phaser.Tween.updateColor);
  54702. *
  54703. * tween.start();
  54704. * ```
  54705. *
  54706. * @method Phaser.Tween.updateColor
  54707. * @static
  54708. * @param {Phaser.Tween} tween - A Tween with a {@link #target} that is a {@link Phaser.Color.createColor color object}.
  54709. */
  54710. Phaser.Tween.updateColor = function (tween) {
  54711. Phaser.Color.updateColor(tween.target);
  54712. };
  54713. Phaser.Tween.prototype = {
  54714. /**
  54715. * Sets this tween to be a `to` tween on the properties given. A `to` tween starts at the current value and tweens to the destination value given.
  54716. * For example a Sprite with an `x` coordinate of 100 could be tweened to `x` 200 by giving a properties object of `{ x: 200 }`.
  54717. * The ease function allows you define the rate of change. You can pass either a function such as Phaser.Easing.Circular.Out or a string such as "Circ".
  54718. * ".easeIn", ".easeOut" and "easeInOut" variants are all supported for all ease types.
  54719. *
  54720. * @method Phaser.Tween#to
  54721. * @param {object} properties - An object containing the properties you want to tween, such as `Sprite.x` or `Sound.volume`. Given as a JavaScript object.
  54722. * @param {number} [duration=1000] - Duration of this tween in ms. Or if `Tween.frameBased` is true this represents the number of frames that should elapse.
  54723. * @param {function|string} [ease=null] - Easing function. If not set it will default to Phaser.Easing.Default, which is Phaser.Easing.Linear.None by default but can be over-ridden.
  54724. * @param {boolean} [autoStart=false] - Set to `true` to allow this tween to start automatically. Otherwise call Tween.start().
  54725. * @param {number} [delay=0] - Delay before this tween will start in milliseconds. Defaults to 0, no delay.
  54726. * @param {number} [repeat=0] - Should the tween automatically restart once complete? If you want it to run forever set as -1. This only effects this individual tween, not any chained tweens.
  54727. * @param {boolean} [yoyo=false] - A tween that yoyos will reverse itself and play backwards automatically. A yoyo'd tween doesn't fire the Tween.onComplete event, so listen for Tween.onLoop instead.
  54728. * @return {Phaser.Tween} This Tween object.
  54729. */
  54730. to: function (properties, duration, ease, autoStart, delay, repeat, yoyo) {
  54731. if (duration === undefined || duration <= 0) { duration = 1000; }
  54732. if (ease === undefined || ease === null) { ease = Phaser.Easing.Default; }
  54733. if (autoStart === undefined) { autoStart = false; }
  54734. if (delay === undefined) { delay = 0; }
  54735. if (repeat === undefined) { repeat = 0; }
  54736. if (yoyo === undefined) { yoyo = false; }
  54737. if (typeof ease === 'string' && this.manager.easeMap[ease])
  54738. {
  54739. ease = this.manager.easeMap[ease];
  54740. }
  54741. if (this.isRunning)
  54742. {
  54743. console.warn('Phaser.Tween.to cannot be called after Tween.start');
  54744. return this;
  54745. }
  54746. this.timeline.push(new Phaser.TweenData(this).to(properties, duration, ease, delay, repeat, yoyo));
  54747. if (autoStart)
  54748. {
  54749. this.start();
  54750. }
  54751. return this;
  54752. },
  54753. /**
  54754. * Sets this tween to be a `from` tween on the properties given. A `from` tween sets the target to the destination value and tweens to its current value.
  54755. * For example a Sprite with an `x` coordinate of 100 tweened from `x` 500 would be set to `x` 500 and then tweened to `x` 100 by giving a properties object of `{ x: 500 }`.
  54756. * The ease function allows you define the rate of change. You can pass either a function such as Phaser.Easing.Circular.Out or a string such as "Circ".
  54757. * ".easeIn", ".easeOut" and "easeInOut" variants are all supported for all ease types.
  54758. *
  54759. * @method Phaser.Tween#from
  54760. * @param {object} properties - An object containing the properties you want to tween., such as `Sprite.x` or `Sound.volume`. Given as a JavaScript object.
  54761. * @param {number} [duration=1000] - Duration of this tween in ms. Or if `Tween.frameBased` is true this represents the number of frames that should elapse.
  54762. * @param {function|string} [ease=null] - Easing function. If not set it will default to Phaser.Easing.Default, which is Phaser.Easing.Linear.None by default but can be over-ridden.
  54763. * @param {boolean} [autoStart=false] - Set to `true` to allow this tween to start automatically. Otherwise call Tween.start().
  54764. * @param {number} [delay=0] - Delay before this tween will start in milliseconds. Defaults to 0, no delay.
  54765. * @param {number} [repeat=0] - Should the tween automatically restart once complete? If you want it to run forever set as -1. This only effects this individual tween, not any chained tweens.
  54766. * @param {boolean} [yoyo=false] - A tween that yoyos will reverse itself and play backwards automatically. A yoyo'd tween doesn't fire the Tween.onComplete event, so listen for Tween.onLoop instead.
  54767. * @return {Phaser.Tween} This Tween object.
  54768. */
  54769. from: function (properties, duration, ease, autoStart, delay, repeat, yoyo) {
  54770. if (duration === undefined) { duration = 1000; }
  54771. if (ease === undefined || ease === null) { ease = Phaser.Easing.Default; }
  54772. if (autoStart === undefined) { autoStart = false; }
  54773. if (delay === undefined) { delay = 0; }
  54774. if (repeat === undefined) { repeat = 0; }
  54775. if (yoyo === undefined) { yoyo = false; }
  54776. if (typeof ease === 'string' && this.manager.easeMap[ease])
  54777. {
  54778. ease = this.manager.easeMap[ease];
  54779. }
  54780. if (this.isRunning)
  54781. {
  54782. console.warn('Phaser.Tween.from cannot be called after Tween.start');
  54783. return this;
  54784. }
  54785. this.timeline.push(new Phaser.TweenData(this).from(properties, duration, ease, delay, repeat, yoyo));
  54786. if (autoStart)
  54787. {
  54788. this.start();
  54789. }
  54790. return this;
  54791. },
  54792. /**
  54793. * Starts the tween running. Can also be called by the autoStart parameter of `Tween.to` or `Tween.from`.
  54794. * This sets the `Tween.isRunning` property to `true` and dispatches a `Tween.onStart` signal.
  54795. * If the Tween has a delay set then nothing will start tweening until the delay has expired.
  54796. *
  54797. * @method Phaser.Tween#start
  54798. * @param {number} [index=0] - If this Tween contains child tweens you can specify which one to start from. The default is zero, i.e. the first tween created.
  54799. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54800. */
  54801. start: function (index) {
  54802. if (index === undefined) { index = 0; }
  54803. if (this.game === null || this.target === null || this.timeline.length === 0 || this.isRunning)
  54804. {
  54805. return this;
  54806. }
  54807. // Populate the tween data
  54808. for (var i = 0; i < this.timeline.length; i++)
  54809. {
  54810. // Build our master property list with the starting values
  54811. for (var property in this.timeline[i].vEnd)
  54812. {
  54813. this.properties[property] = this.target[property] || 0;
  54814. if (!Array.isArray(this.properties[property]))
  54815. {
  54816. // Ensures we're using numbers, not strings
  54817. this.properties[property] *= 1.0;
  54818. }
  54819. }
  54820. }
  54821. for (var i = 0; i < this.timeline.length; i++)
  54822. {
  54823. this.timeline[i].loadValues();
  54824. }
  54825. this.manager.add(this);
  54826. this.isRunning = true;
  54827. if (index < 0 || index > this.timeline.length - 1)
  54828. {
  54829. index = 0;
  54830. }
  54831. this.current = index;
  54832. this.timeline[this.current].start();
  54833. return this;
  54834. },
  54835. /**
  54836. * Stops the tween if running and flags it for deletion from the TweenManager.
  54837. * If called directly the `Tween.onComplete` signal is not dispatched and no chained tweens are started unless the complete parameter is set to `true`.
  54838. * If you just wish to pause a tween then use Tween.pause instead.
  54839. *
  54840. * @method Phaser.Tween#stop
  54841. * @param {boolean} [complete=false] - Set to `true` to dispatch the Tween.onComplete signal.
  54842. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54843. */
  54844. stop: function (complete) {
  54845. if (complete === undefined) { complete = false; }
  54846. this.isRunning = false;
  54847. this._onUpdateCallback = null;
  54848. this._onUpdateCallbackContext = null;
  54849. if (complete)
  54850. {
  54851. this.onComplete.dispatch(this.target, this);
  54852. this._hasStarted = false;
  54853. if (this.chainedTween)
  54854. {
  54855. this.chainedTween.start();
  54856. }
  54857. }
  54858. this.manager.remove(this);
  54859. return this;
  54860. },
  54861. /**
  54862. * Updates either a single TweenData or all TweenData objects properties to the given value.
  54863. * Used internally by methods like Tween.delay, Tween.yoyo, etc. but can also be called directly if you know which property you want to tweak.
  54864. * The property is not checked, so if you pass an invalid one you'll generate a run-time error.
  54865. *
  54866. * @method Phaser.Tween#updateTweenData
  54867. * @param {string} property - The property to update.
  54868. * @param {number|function} value - The value to set the property to.
  54869. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set the delay on all the children.
  54870. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54871. */
  54872. updateTweenData: function (property, value, index) {
  54873. if (this.timeline.length === 0) { return this; }
  54874. if (index === undefined) { index = 0; }
  54875. if (index === -1)
  54876. {
  54877. for (var i = 0; i < this.timeline.length; i++)
  54878. {
  54879. this.timeline[i][property] = value;
  54880. }
  54881. }
  54882. else
  54883. {
  54884. this.timeline[index][property] = value;
  54885. }
  54886. return this;
  54887. },
  54888. /**
  54889. * Sets the delay in milliseconds before this tween will start. If there are child tweens it sets the delay before the first child starts.
  54890. * The delay is invoked as soon as you call `Tween.start`. If the tween is already running this method doesn't do anything for the current active tween.
  54891. * If you have not yet called `Tween.to` or `Tween.from` at least once then this method will do nothing, as there are no tweens to delay.
  54892. * If you have child tweens and pass -1 as the index value it sets the delay across all of them.
  54893. *
  54894. * @method Phaser.Tween#delay
  54895. * @param {number} duration - The amount of time in ms that the Tween should wait until it begins once started is called. Set to zero to remove any active delay.
  54896. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set the delay on all the children.
  54897. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54898. */
  54899. delay: function (duration, index) {
  54900. return this.updateTweenData('delay', duration, index);
  54901. },
  54902. /**
  54903. * Sets the number of times this tween will repeat.
  54904. * If you have not yet called `Tween.to` or `Tween.from` at least once then this method will do nothing, as there are no tweens to repeat.
  54905. * If you have child tweens and pass -1 as the index value it sets the number of times they'll repeat across all of them.
  54906. * If you wish to define how many times this Tween and all children will repeat see Tween.repeatAll.
  54907. *
  54908. * @method Phaser.Tween#repeat
  54909. * @param {number} total - How many times a tween should repeat before completing. Set to zero to remove an active repeat. Set to -1 to repeat forever.
  54910. * @param {number} [repeat=0] - This is the amount of time to pause (in ms) before the repeat will start.
  54911. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set the repeat value on all the children.
  54912. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54913. */
  54914. repeat: function (total, repeatDelay, index) {
  54915. if (repeatDelay === undefined) { repeatDelay = 0; }
  54916. this.updateTweenData('repeatCounter', total, index);
  54917. return this.updateTweenData('repeatDelay', repeatDelay, index);
  54918. },
  54919. /**
  54920. * Sets the delay in milliseconds before this tween will repeat itself.
  54921. * The repeatDelay is invoked as soon as you call `Tween.start`. If the tween is already running this method doesn't do anything for the current active tween.
  54922. * If you have not yet called `Tween.to` or `Tween.from` at least once then this method will do nothing, as there are no tweens to set repeatDelay on.
  54923. * If you have child tweens and pass -1 as the index value it sets the repeatDelay across all of them.
  54924. *
  54925. * @method Phaser.Tween#repeatDelay
  54926. * @param {number} duration - The amount of time in ms that the Tween should wait until it repeats or yoyos once start is called. Set to zero to remove any active repeatDelay.
  54927. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set the repeatDelay on all the children.
  54928. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54929. */
  54930. repeatDelay: function (duration, index) {
  54931. return this.updateTweenData('repeatDelay', duration, index);
  54932. },
  54933. /**
  54934. * A Tween that has yoyo set to true will run through from its starting values to its end values and then play back in reverse from end to start.
  54935. * Used in combination with repeat you can create endless loops.
  54936. * If you have not yet called `Tween.to` or `Tween.from` at least once then this method will do nothing, as there are no tweens to yoyo.
  54937. * If you have child tweens and pass -1 as the index value it sets the yoyo property across all of them.
  54938. * If you wish to yoyo this Tween and all of its children then see Tween.yoyoAll.
  54939. *
  54940. * @method Phaser.Tween#yoyo
  54941. * @param {boolean} enable - Set to true to yoyo this tween, or false to disable an already active yoyo.
  54942. * @param {number} [yoyoDelay=0] - This is the amount of time to pause (in ms) before the yoyo will start.
  54943. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set yoyo on all the children.
  54944. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54945. */
  54946. yoyo: function(enable, yoyoDelay, index) {
  54947. if (yoyoDelay === undefined) { yoyoDelay = 0; }
  54948. this.updateTweenData('yoyo', enable, index);
  54949. return this.updateTweenData('yoyoDelay', yoyoDelay, index);
  54950. },
  54951. /**
  54952. * Sets the delay in milliseconds before this tween will run a yoyo (only applies if yoyo is enabled).
  54953. * The repeatDelay is invoked as soon as you call `Tween.start`. If the tween is already running this method doesn't do anything for the current active tween.
  54954. * If you have not yet called `Tween.to` or `Tween.from` at least once then this method will do nothing, as there are no tweens to set repeatDelay on.
  54955. * If you have child tweens and pass -1 as the index value it sets the repeatDelay across all of them.
  54956. *
  54957. * @method Phaser.Tween#yoyoDelay
  54958. * @param {number} duration - The amount of time in ms that the Tween should wait until it repeats or yoyos once start is called. Set to zero to remove any active yoyoDelay.
  54959. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set the yoyoDelay on all the children.
  54960. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54961. */
  54962. yoyoDelay: function (duration, index) {
  54963. return this.updateTweenData('yoyoDelay', duration, index);
  54964. },
  54965. /**
  54966. * Set easing function this tween will use, i.e. Phaser.Easing.Linear.None.
  54967. * The ease function allows you define the rate of change. You can pass either a function such as Phaser.Easing.Circular.Out or a string such as "Circ".
  54968. * ".easeIn", ".easeOut" and "easeInOut" variants are all supported for all ease types.
  54969. * If you have child tweens and pass -1 as the index value it sets the easing function defined here across all of them.
  54970. *
  54971. * @method Phaser.Tween#easing
  54972. * @param {function|string} ease - The easing function this tween will use, i.e. Phaser.Easing.Linear.None.
  54973. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set the easing function on all children.
  54974. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54975. */
  54976. easing: function (ease, index) {
  54977. if (typeof ease === 'string' && this.manager.easeMap[ease])
  54978. {
  54979. ease = this.manager.easeMap[ease];
  54980. }
  54981. return this.updateTweenData('easingFunction', ease, index);
  54982. },
  54983. /**
  54984. * Sets the interpolation function the tween will use. By default it uses Phaser.Math.linearInterpolation.
  54985. * Also available: Phaser.Math.bezierInterpolation and Phaser.Math.catmullRomInterpolation.
  54986. * The interpolation function is only used if the target properties is an array.
  54987. * If you have child tweens and pass -1 as the index value and it will set the interpolation function across all of them.
  54988. *
  54989. * @method Phaser.Tween#interpolation
  54990. * @param {function} interpolation - The interpolation function to use (Phaser.Math.linearInterpolation by default)
  54991. * @param {object} [context] - The context under which the interpolation function will be run.
  54992. * @param {number} [index=0] - If this tween has more than one child this allows you to target a specific child. If set to -1 it will set the interpolation function on all children.
  54993. * @return {Phaser.Tween} This tween. Useful for method chaining.
  54994. */
  54995. interpolation: function (interpolation, context, index) {
  54996. if (context === undefined) { context = Phaser.Math; }
  54997. this.updateTweenData('interpolationFunction', interpolation, index);
  54998. return this.updateTweenData('interpolationContext', context, index);
  54999. },
  55000. /**
  55001. * Set how many times this tween and all of its children will repeat.
  55002. * A tween (A) with 3 children (B,C,D) with a `repeatAll` value of 2 would play as: ABCDABCD before completing.
  55003. *
  55004. * @method Phaser.Tween#repeatAll
  55005. * @param {number} [total=0] - How many times this tween and all children should repeat before completing. Set to zero to remove an active repeat. Set to -1 to repeat forever.
  55006. * @return {Phaser.Tween} This tween. Useful for method chaining.
  55007. */
  55008. repeatAll: function (total) {
  55009. if (total === undefined) { total = 0; }
  55010. this.repeatCounter = total;
  55011. return this;
  55012. },
  55013. /**
  55014. * This method allows you to chain tweens together. Any tween chained to this tween will have its `Tween.start` method called
  55015. * as soon as this tween completes. If this tween never completes (i.e. repeatAll or loop is set) then the chain will never progress.
  55016. * Note that `Tween.onComplete` will fire when *this* tween completes, not when the whole chain completes.
  55017. * For that you should listen to `onComplete` on the final tween in your chain.
  55018. *
  55019. * If you pass multiple tweens to this method they will be joined into a single long chain.
  55020. * For example if this is Tween A and you pass in B, C and D then B will be chained to A, C will be chained to B and D will be chained to C.
  55021. * Any previously chained tweens that may have been set will be overwritten.
  55022. *
  55023. * @method Phaser.Tween#chain
  55024. * @param {...Phaser.Tween} tweens - One or more tweens that will be chained to this one.
  55025. * @return {Phaser.Tween} This tween. Useful for method chaining.
  55026. */
  55027. chain: function () {
  55028. var i = arguments.length;
  55029. while (i--)
  55030. {
  55031. if (i > 0)
  55032. {
  55033. arguments[i - 1].chainedTween = arguments[i];
  55034. }
  55035. else
  55036. {
  55037. this.chainedTween = arguments[i];
  55038. }
  55039. }
  55040. return this;
  55041. },
  55042. /**
  55043. * Enables the looping of this tween. The tween will loop forever, and onComplete will never fire.
  55044. *
  55045. * If `value` is `true` then this is the same as setting `Tween.repeatAll(-1)`.
  55046. * If `value` is `false` it is the same as setting `Tween.repeatAll(0)` and will reset the `repeatCounter` to zero.
  55047. *
  55048. * Usage:
  55049. * game.add.tween(p).to({ x: 700 }, 1000, Phaser.Easing.Linear.None, true)
  55050. * .to({ y: 300 }, 1000, Phaser.Easing.Linear.None)
  55051. * .to({ x: 0 }, 1000, Phaser.Easing.Linear.None)
  55052. * .to({ y: 0 }, 1000, Phaser.Easing.Linear.None)
  55053. * .loop();
  55054. * @method Phaser.Tween#loop
  55055. * @param {boolean} [value=true] - If `true` this tween will loop once it reaches the end. Set to `false` to remove an active loop.
  55056. * @return {Phaser.Tween} This tween. Useful for method chaining.
  55057. */
  55058. loop: function (value) {
  55059. if (value === undefined) { value = true; }
  55060. this.repeatCounter = (value) ? -1 : 0;
  55061. return this;
  55062. },
  55063. /**
  55064. * Sets a callback to be fired each time this tween updates.
  55065. *
  55066. * The callback receives the current Tween, the {@link Phaser.TweenData#value 'value' of the current TweenData}, and the current {@link Phaser.TweenData TweenData}. The second parameter is most useful.
  55067. *
  55068. * ```javascript
  55069. * tween.onUpdateCallback(function (tween, value, tweenData) {
  55070. * console.log('Tween running -- percent: %.2f value: %.2f', tweenData.percent, value);
  55071. * });
  55072. * ```
  55073. *
  55074. * @method Phaser.Tween#onUpdateCallback
  55075. * @param {function} callback - The callback to invoke each time this tween is updated. Set to `null` to remove an already active callback.
  55076. * @param {object} callbackContext - The context in which to call the onUpdate callback.
  55077. * @return {Phaser.Tween} This tween. Useful for method chaining.
  55078. */
  55079. onUpdateCallback: function (callback, callbackContext) {
  55080. this._onUpdateCallback = callback;
  55081. this._onUpdateCallbackContext = callbackContext;
  55082. return this;
  55083. },
  55084. /**
  55085. * Pauses the tween. Resume playback with Tween.resume.
  55086. *
  55087. * @method Phaser.Tween#pause
  55088. */
  55089. pause: function () {
  55090. this.isPaused = true;
  55091. this._codePaused = true;
  55092. this._pausedTime = this.game.time.time;
  55093. },
  55094. /**
  55095. * This is called by the core Game loop. Do not call it directly, instead use Tween.pause.
  55096. *
  55097. * @private
  55098. * @method Phaser.Tween#_pause
  55099. */
  55100. _pause: function () {
  55101. if (!this._codePaused)
  55102. {
  55103. this.isPaused = true;
  55104. this._pausedTime = this.game.time.time;
  55105. }
  55106. },
  55107. /**
  55108. * Resumes a paused tween.
  55109. *
  55110. * @method Phaser.Tween#resume
  55111. */
  55112. resume: function () {
  55113. if (this.isPaused)
  55114. {
  55115. this.isPaused = false;
  55116. this._codePaused = false;
  55117. for (var i = 0; i < this.timeline.length; i++)
  55118. {
  55119. if (!this.timeline[i].isRunning)
  55120. {
  55121. this.timeline[i].startTime += (this.game.time.time - this._pausedTime);
  55122. }
  55123. }
  55124. }
  55125. },
  55126. /**
  55127. * This is called by the core Game loop. Do not call it directly, instead use Tween.pause.
  55128. * @method Phaser.Tween#_resume
  55129. * @private
  55130. */
  55131. _resume: function () {
  55132. if (this._codePaused)
  55133. {
  55134. return;
  55135. }
  55136. else
  55137. {
  55138. this.resume();
  55139. }
  55140. },
  55141. /**
  55142. * Core tween update function called by the TweenManager. Does not need to be invoked directly.
  55143. *
  55144. * @method Phaser.Tween#update
  55145. * @param {number} time - A timestamp passed in by the TweenManager.
  55146. * @return {boolean} false if the tween and all child tweens have completed and should be deleted from the manager, otherwise true (still active).
  55147. */
  55148. update: function (time) {
  55149. if (this.pendingDelete || !this.target)
  55150. {
  55151. return false;
  55152. }
  55153. if (this.isPaused)
  55154. {
  55155. return true;
  55156. }
  55157. var status = this.timeline[this.current].update(time);
  55158. if (status === Phaser.TweenData.PENDING)
  55159. {
  55160. return true;
  55161. }
  55162. else if (status === Phaser.TweenData.RUNNING)
  55163. {
  55164. if (!this._hasStarted)
  55165. {
  55166. this.onStart.dispatch(this.target, this);
  55167. this._hasStarted = true;
  55168. }
  55169. if (this._onUpdateCallback !== null)
  55170. {
  55171. this._onUpdateCallback.call(this._onUpdateCallbackContext, this, this.timeline[this.current].value, this.timeline[this.current]);
  55172. }
  55173. // In case the update callback modifies this tween
  55174. return this.isRunning;
  55175. }
  55176. else if (status === Phaser.TweenData.LOOPED)
  55177. {
  55178. if (this.timeline[this.current].repeatCounter === -1)
  55179. {
  55180. this.onLoop.dispatch(this.target, this);
  55181. }
  55182. else
  55183. {
  55184. this.onRepeat.dispatch(this.target, this);
  55185. }
  55186. return true;
  55187. }
  55188. else if (status === Phaser.TweenData.COMPLETE)
  55189. {
  55190. var complete = false;
  55191. // What now?
  55192. if (this.reverse)
  55193. {
  55194. this.current--;
  55195. if (this.current < 0)
  55196. {
  55197. this.current = this.timeline.length - 1;
  55198. complete = true;
  55199. }
  55200. }
  55201. else
  55202. {
  55203. this.current++;
  55204. if (this.current === this.timeline.length)
  55205. {
  55206. this.current = 0;
  55207. complete = true;
  55208. }
  55209. }
  55210. if (complete)
  55211. {
  55212. // We've reached the start or end of the child tweens (depending on Tween.reverse), should we repeat it?
  55213. if (this.repeatCounter === -1)
  55214. {
  55215. this.timeline[this.current].start();
  55216. this.onLoop.dispatch(this.target, this);
  55217. return true;
  55218. }
  55219. else if (this.repeatCounter > 0)
  55220. {
  55221. this.repeatCounter--;
  55222. this.timeline[this.current].start();
  55223. this.onRepeat.dispatch(this.target, this);
  55224. return true;
  55225. }
  55226. else
  55227. {
  55228. // No more repeats and no more children, so we're done
  55229. this.isRunning = false;
  55230. this.onComplete.dispatch(this.target, this);
  55231. this._hasStarted = false;
  55232. if (this.chainedTween)
  55233. {
  55234. this.chainedTween.start();
  55235. }
  55236. return false;
  55237. }
  55238. }
  55239. else
  55240. {
  55241. // We've still got some children to go
  55242. this.onChildComplete.dispatch(this.target, this);
  55243. this.timeline[this.current].start();
  55244. return true;
  55245. }
  55246. }
  55247. },
  55248. /**
  55249. * This will generate an array populated with the tweened object values from start to end.
  55250. * It works by running the tween simulation at the given frame rate based on the values set-up in Tween.to and Tween.from.
  55251. * It ignores delay and repeat counts and any chained tweens, but does include child tweens.
  55252. * Just one play through of the tween data is returned, including yoyo if set.
  55253. *
  55254. * @method Phaser.Tween#generateData
  55255. * @param {number} [frameRate=60] - The speed in frames per second that the data should be generated at. The higher the value, the larger the array it creates.
  55256. * @param {array} [data] - If given the generated data will be appended to this array, otherwise a new array will be returned.
  55257. * @return {array} An array of tweened values.
  55258. */
  55259. generateData: function (frameRate, data) {
  55260. if (this.game === null || this.target === null)
  55261. {
  55262. return null;
  55263. }
  55264. if (frameRate === undefined) { frameRate = 60; }
  55265. if (data === undefined) { data = []; }
  55266. // Populate the tween data
  55267. for (var i = 0; i < this.timeline.length; i++)
  55268. {
  55269. // Build our master property list with the starting values
  55270. for (var property in this.timeline[i].vEnd)
  55271. {
  55272. this.properties[property] = this.target[property] || 0;
  55273. if (!Array.isArray(this.properties[property]))
  55274. {
  55275. // Ensures we're using numbers, not strings
  55276. this.properties[property] *= 1.0;
  55277. }
  55278. }
  55279. }
  55280. for (var i = 0; i < this.timeline.length; i++)
  55281. {
  55282. this.timeline[i].loadValues();
  55283. }
  55284. for (var i = 0; i < this.timeline.length; i++)
  55285. {
  55286. data = data.concat(this.timeline[i].generateData(frameRate));
  55287. }
  55288. return data;
  55289. }
  55290. };
  55291. /**
  55292. * @name Phaser.Tween#totalDuration
  55293. * @property {Phaser.TweenData} totalDuration - Gets the total duration of this Tween, including all child tweens, in milliseconds.
  55294. */
  55295. Object.defineProperty(Phaser.Tween.prototype, 'totalDuration', {
  55296. get: function () {
  55297. var total = 0;
  55298. for (var i = 0; i < this.timeline.length; i++)
  55299. {
  55300. total += this.timeline[i].duration;
  55301. }
  55302. return total;
  55303. }
  55304. });
  55305. Phaser.Tween.prototype.constructor = Phaser.Tween;
  55306. /**
  55307. * @author Richard Davey <rich@photonstorm.com>
  55308. * @copyright 2016 Photon Storm Ltd.
  55309. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  55310. */
  55311. /**
  55312. * A Phaser.Tween contains at least one TweenData object. It contains all of the tween data values, such as the
  55313. * starting and ending values, the ease function, interpolation and duration. The Tween acts as a timeline manager for
  55314. * TweenData objects and can contain multiple TweenData objects.
  55315. *
  55316. * @class Phaser.TweenData
  55317. * @constructor
  55318. * @param {Phaser.Tween} parent - The Tween that owns this TweenData object.
  55319. */
  55320. Phaser.TweenData = function (parent) {
  55321. /**
  55322. * @property {Phaser.Tween} parent - The Tween which owns this TweenData.
  55323. */
  55324. this.parent = parent;
  55325. /**
  55326. * @property {Phaser.Game} game - A reference to the currently running Game.
  55327. */
  55328. this.game = parent.game;
  55329. /**
  55330. * @property {object} vStart - An object containing the values at the start of the tween.
  55331. * @private
  55332. */
  55333. this.vStart = {};
  55334. /**
  55335. * @property {object} vStartCache - Cached starting values.
  55336. * @private
  55337. */
  55338. this.vStartCache = {};
  55339. /**
  55340. * @property {object} vEnd - An object containing the values at the end of the tween.
  55341. * @private
  55342. */
  55343. this.vEnd = {};
  55344. /**
  55345. * @property {object} vEndCache - Cached ending values.
  55346. * @private
  55347. */
  55348. this.vEndCache = {};
  55349. /**
  55350. * @property {number} duration - The duration of the tween in ms.
  55351. * @default
  55352. */
  55353. this.duration = 1000;
  55354. /**
  55355. * @property {number} percent - A value between 0 and 1 that represents how far through the duration this tween is.
  55356. * @readonly
  55357. */
  55358. this.percent = 0;
  55359. /**
  55360. * @property {number} value - The output of the easing function for the current {@link #percent}. Depending on the easing function, this will be within [0, 1] or a slightly larger range (e.g., Bounce). When easing is Linear, this will be identical to {@link #percent}.
  55361. * @readonly
  55362. */
  55363. this.value = 0;
  55364. /**
  55365. * @property {number} repeatCounter - If the Tween is set to repeat this contains the current repeat count.
  55366. */
  55367. this.repeatCounter = 0;
  55368. /**
  55369. * @property {number} repeatDelay - The amount of time in ms between repeats of this tween.
  55370. */
  55371. this.repeatDelay = 0;
  55372. /**
  55373. * @property {number} repeatTotal - The total number of times this Tween will repeat.
  55374. * @readonly
  55375. */
  55376. this.repeatTotal = 0;
  55377. /**
  55378. * @property {boolean} interpolate - True if the Tween will use interpolation (i.e. is an Array to Array tween)
  55379. * @default
  55380. * @todo Appears unused.
  55381. */
  55382. this.interpolate = false;
  55383. /**
  55384. * @property {boolean} yoyo - True if the Tween is set to yoyo, otherwise false.
  55385. * @default
  55386. */
  55387. this.yoyo = false;
  55388. /**
  55389. * @property {number} yoyoDelay - The amount of time in ms between yoyos of this tween.
  55390. */
  55391. this.yoyoDelay = 0;
  55392. /**
  55393. * @property {boolean} inReverse - When a Tween is yoyoing this value holds if it's currently playing forwards (false) or in reverse (true).
  55394. * @default
  55395. */
  55396. this.inReverse = false;
  55397. /**
  55398. * @property {number} delay - The amount to delay by until the Tween starts (in ms). Only applies to the start, use repeatDelay to handle repeats.
  55399. * @default
  55400. */
  55401. this.delay = 0;
  55402. /**
  55403. * @property {number} dt - Current time value.
  55404. */
  55405. this.dt = 0;
  55406. /**
  55407. * @property {number} startTime - The time the Tween started or null if it hasn't yet started.
  55408. */
  55409. this.startTime = null;
  55410. /**
  55411. * @property {function} easingFunction - The easing function used for the Tween.
  55412. * @default Phaser.Easing.Default
  55413. */
  55414. this.easingFunction = Phaser.Easing.Default;
  55415. /**
  55416. * @property {function} interpolationFunction - The interpolation function used for Array-based Tween.
  55417. * @default Phaser.Math.linearInterpolation
  55418. */
  55419. this.interpolationFunction = Phaser.Math.linearInterpolation;
  55420. /**
  55421. * @property {object} interpolationContext - The interpolation function context used for the Tween.
  55422. * @default Phaser.Math
  55423. */
  55424. this.interpolationContext = Phaser.Math;
  55425. /**
  55426. * @property {boolean} isRunning - If the tween is running this is set to `true`. Unless Phaser.Tween a TweenData that is waiting for a delay to expire is *not* considered as running.
  55427. * @default
  55428. */
  55429. this.isRunning = false;
  55430. /**
  55431. * @property {boolean} isFrom - Is this a from tween or a to tween?
  55432. * @default
  55433. */
  55434. this.isFrom = false;
  55435. };
  55436. /**
  55437. * @constant
  55438. * @type {number}
  55439. */
  55440. Phaser.TweenData.PENDING = 0;
  55441. /**
  55442. * @constant
  55443. * @type {number}
  55444. */
  55445. Phaser.TweenData.RUNNING = 1;
  55446. /**
  55447. * @constant
  55448. * @type {number}
  55449. */
  55450. Phaser.TweenData.LOOPED = 2;
  55451. /**
  55452. * @constant
  55453. * @type {number}
  55454. */
  55455. Phaser.TweenData.COMPLETE = 3;
  55456. Phaser.TweenData.prototype = {
  55457. /**
  55458. * Sets this tween to be a `to` tween on the properties given. A `to` tween starts at the current value and tweens to the destination value given.
  55459. * For example a Sprite with an `x` coordinate of 100 could be tweened to `x` 200 by giving a properties object of `{ x: 200 }`.
  55460. *
  55461. * @method Phaser.TweenData#to
  55462. * @param {object} properties - The properties you want to tween, such as `Sprite.x` or `Sound.volume`. Given as a JavaScript object.
  55463. * @param {number} [duration=1000] - Duration of this tween in ms.
  55464. * @param {function} [ease=null] - Easing function. If not set it will default to Phaser.Easing.Default, which is Phaser.Easing.Linear.None by default but can be over-ridden at will.
  55465. * @param {number} [delay=0] - Delay before this tween will start, defaults to 0 (no delay). Value given is in ms.
  55466. * @param {number} [repeat=0] - Should the tween automatically restart once complete? If you want it to run forever set as -1. This ignores any chained tweens.
  55467. * @param {boolean} [yoyo=false] - A tween that yoyos will reverse itself and play backwards automatically. A yoyo'd tween doesn't fire the Tween.onComplete event, so listen for Tween.onLoop instead.
  55468. * @return {Phaser.TweenData} This Tween object.
  55469. */
  55470. to: function (properties, duration, ease, delay, repeat, yoyo) {
  55471. this.vEnd = properties;
  55472. this.duration = duration;
  55473. this.easingFunction = ease;
  55474. this.delay = delay;
  55475. this.repeatTotal = repeat;
  55476. this.yoyo = yoyo;
  55477. this.isFrom = false;
  55478. return this;
  55479. },
  55480. /**
  55481. * Sets this tween to be a `from` tween on the properties given. A `from` tween sets the target to the destination value and tweens to its current value.
  55482. * For example a Sprite with an `x` coordinate of 100 tweened from `x` 500 would be set to `x` 500 and then tweened to `x` 100 by giving a properties object of `{ x: 500 }`.
  55483. *
  55484. * @method Phaser.TweenData#from
  55485. * @param {object} properties - The properties you want to tween, such as `Sprite.x` or `Sound.volume`. Given as a JavaScript object.
  55486. * @param {number} [duration=1000] - Duration of this tween in ms.
  55487. * @param {function} [ease=null] - Easing function. If not set it will default to Phaser.Easing.Default, which is Phaser.Easing.Linear.None by default but can be over-ridden at will.
  55488. * @param {number} [delay=0] - Delay before this tween will start, defaults to 0 (no delay). Value given is in ms.
  55489. * @param {number} [repeat=0] - Should the tween automatically restart once complete? If you want it to run forever set as -1. This ignores any chained tweens.
  55490. * @param {boolean} [yoyo=false] - A tween that yoyos will reverse itself and play backwards automatically. A yoyo'd tween doesn't fire the Tween.onComplete event, so listen for Tween.onLoop instead.
  55491. * @return {Phaser.TweenData} This Tween object.
  55492. */
  55493. from: function (properties, duration, ease, delay, repeat, yoyo) {
  55494. this.vEnd = properties;
  55495. this.duration = duration;
  55496. this.easingFunction = ease;
  55497. this.delay = delay;
  55498. this.repeatTotal = repeat;
  55499. this.yoyo = yoyo;
  55500. this.isFrom = true;
  55501. return this;
  55502. },
  55503. /**
  55504. * Starts the Tween running.
  55505. *
  55506. * @method Phaser.TweenData#start
  55507. * @return {Phaser.TweenData} This Tween object.
  55508. */
  55509. start: function () {
  55510. this.startTime = this.game.time.time + this.delay;
  55511. if (this.parent.reverse)
  55512. {
  55513. this.dt = this.duration;
  55514. }
  55515. else
  55516. {
  55517. this.dt = 0;
  55518. }
  55519. if (this.delay > 0)
  55520. {
  55521. this.isRunning = false;
  55522. }
  55523. else
  55524. {
  55525. this.isRunning = true;
  55526. }
  55527. if (this.isFrom)
  55528. {
  55529. // Reverse them all and instant set them
  55530. for (var property in this.vStartCache)
  55531. {
  55532. this.vStart[property] = this.vEndCache[property];
  55533. this.vEnd[property] = this.vStartCache[property];
  55534. this.parent.target[property] = this.vStart[property];
  55535. }
  55536. }
  55537. this.value = 0;
  55538. this.yoyoCounter = 0;
  55539. this.repeatCounter = this.repeatTotal;
  55540. return this;
  55541. },
  55542. /**
  55543. * Loads the values from the target object into this Tween.
  55544. *
  55545. * @private
  55546. * @method Phaser.TweenData#loadValues
  55547. * @return {Phaser.TweenData} This Tween object.
  55548. */
  55549. loadValues: function () {
  55550. for (var property in this.parent.properties)
  55551. {
  55552. // Load the property from the parent object
  55553. this.vStart[property] = this.parent.properties[property];
  55554. // Check if an Array was provided as property value
  55555. if (Array.isArray(this.vEnd[property]))
  55556. {
  55557. if (this.vEnd[property].length === 0)
  55558. {
  55559. continue;
  55560. }
  55561. if (this.percent === 0)
  55562. {
  55563. // Put the start value at the beginning of the array
  55564. // but we only want to do this once, if the Tween hasn't run before
  55565. this.vEnd[property] = [this.vStart[property]].concat(this.vEnd[property]);
  55566. }
  55567. }
  55568. if (typeof this.vEnd[property] !== 'undefined')
  55569. {
  55570. if (typeof this.vEnd[property] === 'string')
  55571. {
  55572. // Parses relative end values with start as base (e.g.: +10, -3)
  55573. this.vEnd[property] = this.vStart[property] + parseFloat(this.vEnd[property], 10);
  55574. }
  55575. this.parent.properties[property] = this.vEnd[property];
  55576. }
  55577. else
  55578. {
  55579. // Null tween
  55580. this.vEnd[property] = this.vStart[property];
  55581. }
  55582. this.vStartCache[property] = this.vStart[property];
  55583. this.vEndCache[property] = this.vEnd[property];
  55584. }
  55585. return this;
  55586. },
  55587. /**
  55588. * Updates this Tween. This is called automatically by Phaser.Tween.
  55589. *
  55590. * @protected
  55591. * @method Phaser.TweenData#update
  55592. * @param {number} time - A timestamp passed in by the Tween parent.
  55593. * @return {number} The current status of this Tween. One of the Phaser.TweenData constants: PENDING, RUNNING, LOOPED or COMPLETE.
  55594. */
  55595. update: function (time) {
  55596. if (!this.isRunning)
  55597. {
  55598. if (time >= this.startTime)
  55599. {
  55600. this.isRunning = true;
  55601. }
  55602. else
  55603. {
  55604. return Phaser.TweenData.PENDING;
  55605. }
  55606. }
  55607. else
  55608. {
  55609. // Is Running, but is waiting to repeat
  55610. if (time < this.startTime)
  55611. {
  55612. return Phaser.TweenData.RUNNING;
  55613. }
  55614. }
  55615. var ms = (this.parent.frameBased) ? this.game.time.physicsElapsedMS : this.game.time.elapsedMS;
  55616. if (this.parent.reverse)
  55617. {
  55618. this.dt -= ms * this.parent.timeScale;
  55619. this.dt = Math.max(this.dt, 0);
  55620. }
  55621. else
  55622. {
  55623. this.dt += ms * this.parent.timeScale;
  55624. this.dt = Math.min(this.dt, this.duration);
  55625. }
  55626. this.percent = this.dt / this.duration;
  55627. this.value = this.easingFunction(this.percent);
  55628. for (var property in this.vEnd)
  55629. {
  55630. var start = this.vStart[property];
  55631. var end = this.vEnd[property];
  55632. if (Array.isArray(end))
  55633. {
  55634. this.parent.target[property] = this.interpolationFunction.call(this.interpolationContext, end, this.value);
  55635. }
  55636. else
  55637. {
  55638. this.parent.target[property] = start + ((end - start) * this.value);
  55639. }
  55640. }
  55641. if ((!this.parent.reverse && this.percent === 1) || (this.parent.reverse && this.percent === 0))
  55642. {
  55643. return this.repeat();
  55644. }
  55645. return Phaser.TweenData.RUNNING;
  55646. },
  55647. /**
  55648. * This will generate an array populated with the tweened object values from start to end.
  55649. * It works by running the tween simulation at the given frame rate based on the values set-up in Tween.to and Tween.from.
  55650. * Just one play through of the tween data is returned, including yoyo if set.
  55651. *
  55652. * @method Phaser.TweenData#generateData
  55653. * @param {number} [frameRate=60] - The speed in frames per second that the data should be generated at. The higher the value, the larger the array it creates.
  55654. * @return {array} An array of tweened values.
  55655. */
  55656. generateData: function (frameRate) {
  55657. if (this.parent.reverse)
  55658. {
  55659. this.dt = this.duration;
  55660. }
  55661. else
  55662. {
  55663. this.dt = 0;
  55664. }
  55665. var data = [];
  55666. var complete = false;
  55667. var fps = (1 / frameRate) * 1000;
  55668. do
  55669. {
  55670. if (this.parent.reverse)
  55671. {
  55672. this.dt -= fps;
  55673. this.dt = Math.max(this.dt, 0);
  55674. }
  55675. else
  55676. {
  55677. this.dt += fps;
  55678. this.dt = Math.min(this.dt, this.duration);
  55679. }
  55680. this.percent = this.dt / this.duration;
  55681. this.value = this.easingFunction(this.percent);
  55682. var blob = {};
  55683. for (var property in this.vEnd)
  55684. {
  55685. var start = this.vStart[property];
  55686. var end = this.vEnd[property];
  55687. if (Array.isArray(end))
  55688. {
  55689. blob[property] = this.interpolationFunction.call(this.interpolationContext, end, this.value);
  55690. }
  55691. else
  55692. {
  55693. blob[property] = start + ((end - start) * this.value);
  55694. }
  55695. }
  55696. data.push(blob);
  55697. if ((!this.parent.reverse && this.percent === 1) || (this.parent.reverse && this.percent === 0))
  55698. {
  55699. complete = true;
  55700. }
  55701. } while (!complete);
  55702. if (this.yoyo)
  55703. {
  55704. var reversed = data.slice();
  55705. reversed.reverse();
  55706. data = data.concat(reversed);
  55707. }
  55708. return data;
  55709. },
  55710. /**
  55711. * Checks if this Tween is meant to repeat or yoyo and handles doing so.
  55712. *
  55713. * @private
  55714. * @method Phaser.TweenData#repeat
  55715. * @return {number} Either Phaser.TweenData.LOOPED or Phaser.TweenData.COMPLETE.
  55716. */
  55717. repeat: function () {
  55718. // If not a yoyo and repeatCounter = 0 then we're done
  55719. if (this.yoyo)
  55720. {
  55721. // We're already in reverse mode, which means the yoyo has finished and there's no repeats, so end
  55722. if (this.inReverse && this.repeatCounter === 0)
  55723. {
  55724. // Restore the properties
  55725. for (var property in this.vStartCache)
  55726. {
  55727. this.vStart[property] = this.vStartCache[property];
  55728. this.vEnd[property] = this.vEndCache[property];
  55729. }
  55730. this.inReverse = false;
  55731. return Phaser.TweenData.COMPLETE;
  55732. }
  55733. this.inReverse = !this.inReverse;
  55734. }
  55735. else
  55736. {
  55737. if (this.repeatCounter === 0)
  55738. {
  55739. return Phaser.TweenData.COMPLETE;
  55740. }
  55741. }
  55742. if (this.inReverse)
  55743. {
  55744. // If inReverse we're going from vEnd to vStartCache
  55745. for (var property in this.vStartCache)
  55746. {
  55747. this.vStart[property] = this.vEndCache[property];
  55748. this.vEnd[property] = this.vStartCache[property];
  55749. }
  55750. }
  55751. else
  55752. {
  55753. // If not inReverse we're just repopulating the cache again
  55754. for (var property in this.vStartCache)
  55755. {
  55756. this.vStart[property] = this.vStartCache[property];
  55757. this.vEnd[property] = this.vEndCache[property];
  55758. }
  55759. // -1 means repeat forever, otherwise decrement the repeatCounter
  55760. // We only decrement this counter if the tween isn't doing a yoyo, as that doesn't count towards the repeat total
  55761. if (this.repeatCounter > 0)
  55762. {
  55763. this.repeatCounter--;
  55764. }
  55765. }
  55766. this.startTime = this.game.time.time;
  55767. if (this.yoyo && this.inReverse)
  55768. {
  55769. this.startTime += this.yoyoDelay;
  55770. }
  55771. else if (!this.inReverse)
  55772. {
  55773. this.startTime += this.repeatDelay;
  55774. }
  55775. if (this.parent.reverse)
  55776. {
  55777. this.dt = this.duration;
  55778. }
  55779. else
  55780. {
  55781. this.dt = 0;
  55782. }
  55783. return Phaser.TweenData.LOOPED;
  55784. }
  55785. };
  55786. Phaser.TweenData.prototype.constructor = Phaser.TweenData;
  55787. /* jshint curly: false */
  55788. /**
  55789. * @author Richard Davey <rich@photonstorm.com>
  55790. * @copyright 2016 Photon Storm Ltd.
  55791. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  55792. */
  55793. /**
  55794. * A collection of easing methods defining ease-in and ease-out curves.
  55795. *
  55796. * @class Phaser.Easing
  55797. */
  55798. Phaser.Easing = {
  55799. /**
  55800. * Linear easing.
  55801. *
  55802. * @class Phaser.Easing.Linear
  55803. */
  55804. Linear: {
  55805. /**
  55806. * Linear Easing (no variation).
  55807. *
  55808. * @method Phaser.Easing.Linear#None
  55809. * @param {number} k - The value to be tweened.
  55810. * @returns {number} k.
  55811. */
  55812. None: function ( k ) {
  55813. return k;
  55814. }
  55815. },
  55816. /**
  55817. * Quadratic easing.
  55818. *
  55819. * @class Phaser.Easing.Quadratic
  55820. */
  55821. Quadratic: {
  55822. /**
  55823. * Ease-in.
  55824. *
  55825. * @method Phaser.Easing.Quadratic#In
  55826. * @param {number} k - The value to be tweened.
  55827. * @returns {number} k^2.
  55828. */
  55829. In: function ( k ) {
  55830. return k * k;
  55831. },
  55832. /**
  55833. * Ease-out.
  55834. *
  55835. * @method Phaser.Easing.Quadratic#Out
  55836. * @param {number} k - The value to be tweened.
  55837. * @returns {number} k* (2-k).
  55838. */
  55839. Out: function ( k ) {
  55840. return k * ( 2 - k );
  55841. },
  55842. /**
  55843. * Ease-in/out.
  55844. *
  55845. * @method Phaser.Easing.Quadratic#InOut
  55846. * @param {number} k - The value to be tweened.
  55847. * @returns {number} The tweened value.
  55848. */
  55849. InOut: function ( k ) {
  55850. if ( ( k *= 2 ) < 1 ) return 0.5 * k * k;
  55851. return - 0.5 * ( --k * ( k - 2 ) - 1 );
  55852. }
  55853. },
  55854. /**
  55855. * Cubic easing.
  55856. *
  55857. * @class Phaser.Easing.Cubic
  55858. */
  55859. Cubic: {
  55860. /**
  55861. * Cubic ease-in.
  55862. *
  55863. * @method Phaser.Easing.Cubic#In
  55864. * @param {number} k - The value to be tweened.
  55865. * @returns {number} The tweened value.
  55866. */
  55867. In: function ( k ) {
  55868. return k * k * k;
  55869. },
  55870. /**
  55871. * Cubic ease-out.
  55872. *
  55873. * @method Phaser.Easing.Cubic#Out
  55874. * @param {number} k - The value to be tweened.
  55875. * @returns {number} The tweened value.
  55876. */
  55877. Out: function ( k ) {
  55878. return --k * k * k + 1;
  55879. },
  55880. /**
  55881. * Cubic ease-in/out.
  55882. *
  55883. * @method Phaser.Easing.Cubic#InOut
  55884. * @param {number} k - The value to be tweened.
  55885. * @returns {number} The tweened value.
  55886. */
  55887. InOut: function ( k ) {
  55888. if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k;
  55889. return 0.5 * ( ( k -= 2 ) * k * k + 2 );
  55890. }
  55891. },
  55892. /**
  55893. * Quartic easing.
  55894. *
  55895. * @class Phaser.Easing.Quartic
  55896. */
  55897. Quartic: {
  55898. /**
  55899. * Quartic ease-in.
  55900. *
  55901. * @method Phaser.Easing.Quartic#In
  55902. * @param {number} k - The value to be tweened.
  55903. * @returns {number} The tweened value.
  55904. */
  55905. In: function ( k ) {
  55906. return k * k * k * k;
  55907. },
  55908. /**
  55909. * Quartic ease-out.
  55910. *
  55911. * @method Phaser.Easing.Quartic#Out
  55912. * @param {number} k - The value to be tweened.
  55913. * @returns {number} The tweened value.
  55914. */
  55915. Out: function ( k ) {
  55916. return 1 - ( --k * k * k * k );
  55917. },
  55918. /**
  55919. * Quartic ease-in/out.
  55920. *
  55921. * @method Phaser.Easing.Quartic#InOut
  55922. * @param {number} k - The value to be tweened.
  55923. * @returns {number} The tweened value.
  55924. */
  55925. InOut: function ( k ) {
  55926. if ( ( k *= 2 ) < 1) return 0.5 * k * k * k * k;
  55927. return - 0.5 * ( ( k -= 2 ) * k * k * k - 2 );
  55928. }
  55929. },
  55930. /**
  55931. * Quintic easing.
  55932. *
  55933. * @class Phaser.Easing.Quintic
  55934. */
  55935. Quintic: {
  55936. /**
  55937. * Quintic ease-in.
  55938. *
  55939. * @method Phaser.Easing.Quintic#In
  55940. * @param {number} k - The value to be tweened.
  55941. * @returns {number} The tweened value.
  55942. */
  55943. In: function ( k ) {
  55944. return k * k * k * k * k;
  55945. },
  55946. /**
  55947. * Quintic ease-out.
  55948. *
  55949. * @method Phaser.Easing.Quintic#Out
  55950. * @param {number} k - The value to be tweened.
  55951. * @returns {number} The tweened value.
  55952. */
  55953. Out: function ( k ) {
  55954. return --k * k * k * k * k + 1;
  55955. },
  55956. /**
  55957. * Quintic ease-in/out.
  55958. *
  55959. * @method Phaser.Easing.Quintic#InOut
  55960. * @param {number} k - The value to be tweened.
  55961. * @returns {number} The tweened value.
  55962. */
  55963. InOut: function ( k ) {
  55964. if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k * k * k;
  55965. return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 );
  55966. }
  55967. },
  55968. /**
  55969. * Sinusoidal easing.
  55970. *
  55971. * @class Phaser.Easing.Sinusoidal
  55972. */
  55973. Sinusoidal: {
  55974. /**
  55975. * Sinusoidal ease-in.
  55976. *
  55977. * @method Phaser.Easing.Sinusoidal#In
  55978. * @param {number} k - The value to be tweened.
  55979. * @returns {number} The tweened value.
  55980. */
  55981. In: function ( k ) {
  55982. if (k === 0) return 0;
  55983. if (k === 1) return 1;
  55984. return 1 - Math.cos( k * Math.PI / 2 );
  55985. },
  55986. /**
  55987. * Sinusoidal ease-out.
  55988. *
  55989. * @method Phaser.Easing.Sinusoidal#Out
  55990. * @param {number} k - The value to be tweened.
  55991. * @returns {number} The tweened value.
  55992. */
  55993. Out: function ( k ) {
  55994. if (k === 0) return 0;
  55995. if (k === 1) return 1;
  55996. return Math.sin( k * Math.PI / 2 );
  55997. },
  55998. /**
  55999. * Sinusoidal ease-in/out.
  56000. *
  56001. * @method Phaser.Easing.Sinusoidal#InOut
  56002. * @param {number} k - The value to be tweened.
  56003. * @returns {number} The tweened value.
  56004. */
  56005. InOut: function ( k ) {
  56006. if (k === 0) return 0;
  56007. if (k === 1) return 1;
  56008. return 0.5 * ( 1 - Math.cos( Math.PI * k ) );
  56009. }
  56010. },
  56011. /**
  56012. * Exponential easing.
  56013. *
  56014. * @class Phaser.Easing.Exponential
  56015. */
  56016. Exponential: {
  56017. /**
  56018. * Exponential ease-in.
  56019. *
  56020. * @method Phaser.Easing.Exponential#In
  56021. * @param {number} k - The value to be tweened.
  56022. * @returns {number} The tweened value.
  56023. */
  56024. In: function ( k ) {
  56025. return k === 0 ? 0 : Math.pow( 1024, k - 1 );
  56026. },
  56027. /**
  56028. * Exponential ease-out.
  56029. *
  56030. * @method Phaser.Easing.Exponential#Out
  56031. * @param {number} k - The value to be tweened.
  56032. * @returns {number} The tweened value.
  56033. */
  56034. Out: function ( k ) {
  56035. return k === 1 ? 1 : 1 - Math.pow( 2, - 10 * k );
  56036. },
  56037. /**
  56038. * Exponential ease-in/out.
  56039. *
  56040. * @method Phaser.Easing.Exponential#InOut
  56041. * @param {number} k - The value to be tweened.
  56042. * @returns {number} The tweened value.
  56043. */
  56044. InOut: function ( k ) {
  56045. if ( k === 0 ) return 0;
  56046. if ( k === 1 ) return 1;
  56047. if ( ( k *= 2 ) < 1 ) return 0.5 * Math.pow( 1024, k - 1 );
  56048. return 0.5 * ( - Math.pow( 2, - 10 * ( k - 1 ) ) + 2 );
  56049. }
  56050. },
  56051. /**
  56052. * Circular easing.
  56053. *
  56054. * @class Phaser.Easing.Circular
  56055. */
  56056. Circular: {
  56057. /**
  56058. * Circular ease-in.
  56059. *
  56060. * @method Phaser.Easing.Circular#In
  56061. * @param {number} k - The value to be tweened.
  56062. * @returns {number} The tweened value.
  56063. */
  56064. In: function ( k ) {
  56065. return 1 - Math.sqrt( 1 - k * k );
  56066. },
  56067. /**
  56068. * Circular ease-out.
  56069. *
  56070. * @method Phaser.Easing.Circular#Out
  56071. * @param {number} k - The value to be tweened.
  56072. * @returns {number} The tweened value.
  56073. */
  56074. Out: function ( k ) {
  56075. return Math.sqrt( 1 - ( --k * k ) );
  56076. },
  56077. /**
  56078. * Circular ease-in/out.
  56079. *
  56080. * @method Phaser.Easing.Circular#InOut
  56081. * @param {number} k - The value to be tweened.
  56082. * @returns {number} The tweened value.
  56083. */
  56084. InOut: function ( k ) {
  56085. if ( ( k *= 2 ) < 1) return - 0.5 * ( Math.sqrt( 1 - k * k) - 1);
  56086. return 0.5 * ( Math.sqrt( 1 - ( k -= 2) * k) + 1);
  56087. }
  56088. },
  56089. /**
  56090. * Elastic easing.
  56091. *
  56092. * @class Phaser.Easing.Elastic
  56093. */
  56094. Elastic: {
  56095. /**
  56096. * Elastic ease-in.
  56097. *
  56098. * @method Phaser.Easing.Elastic#In
  56099. * @param {number} k - The value to be tweened.
  56100. * @returns {number} The tweened value.
  56101. */
  56102. In: function ( k ) {
  56103. var s, a = 0.1, p = 0.4;
  56104. if ( k === 0 ) return 0;
  56105. if ( k === 1 ) return 1;
  56106. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  56107. else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
  56108. return - ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
  56109. },
  56110. /**
  56111. * Elastic ease-out.
  56112. *
  56113. * @method Phaser.Easing.Elastic#Out
  56114. * @param {number} k - The value to be tweened.
  56115. * @returns {number} The tweened value.
  56116. */
  56117. Out: function ( k ) {
  56118. var s, a = 0.1, p = 0.4;
  56119. if ( k === 0 ) return 0;
  56120. if ( k === 1 ) return 1;
  56121. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  56122. else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
  56123. return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
  56124. },
  56125. /**
  56126. * Elastic ease-in/out.
  56127. *
  56128. * @method Phaser.Easing.Elastic#InOut
  56129. * @param {number} k - The value to be tweened.
  56130. * @returns {number} The tweened value.
  56131. */
  56132. InOut: function ( k ) {
  56133. var s, a = 0.1, p = 0.4;
  56134. if ( k === 0 ) return 0;
  56135. if ( k === 1 ) return 1;
  56136. if ( !a || a < 1 ) { a = 1; s = p / 4; }
  56137. else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
  56138. if ( ( k *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
  56139. return a * Math.pow( 2, -10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
  56140. }
  56141. },
  56142. /**
  56143. * Back easing.
  56144. *
  56145. * @class Phaser.Easing.Back
  56146. */
  56147. Back: {
  56148. /**
  56149. * Back ease-in.
  56150. *
  56151. * @method Phaser.Easing.Back#In
  56152. * @param {number} k - The value to be tweened.
  56153. * @returns {number} The tweened value.
  56154. */
  56155. In: function ( k ) {
  56156. var s = 1.70158;
  56157. return k * k * ( ( s + 1 ) * k - s );
  56158. },
  56159. /**
  56160. * Back ease-out.
  56161. *
  56162. * @method Phaser.Easing.Back#Out
  56163. * @param {number} k - The value to be tweened.
  56164. * @returns {number} The tweened value.
  56165. */
  56166. Out: function ( k ) {
  56167. var s = 1.70158;
  56168. return --k * k * ( ( s + 1 ) * k + s ) + 1;
  56169. },
  56170. /**
  56171. * Back ease-in/out.
  56172. *
  56173. * @method Phaser.Easing.Back#InOut
  56174. * @param {number} k - The value to be tweened.
  56175. * @returns {number} The tweened value.
  56176. */
  56177. InOut: function ( k ) {
  56178. var s = 1.70158 * 1.525;
  56179. if ( ( k *= 2 ) < 1 ) return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) );
  56180. return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 );
  56181. }
  56182. },
  56183. /**
  56184. * Bounce easing.
  56185. *
  56186. * @class Phaser.Easing.Bounce
  56187. */
  56188. Bounce: {
  56189. /**
  56190. * Bounce ease-in.
  56191. *
  56192. * @method Phaser.Easing.Bounce#In
  56193. * @param {number} k - The value to be tweened.
  56194. * @returns {number} The tweened value.
  56195. */
  56196. In: function ( k ) {
  56197. return 1 - Phaser.Easing.Bounce.Out( 1 - k );
  56198. },
  56199. /**
  56200. * Bounce ease-out.
  56201. *
  56202. * @method Phaser.Easing.Bounce#Out
  56203. * @param {number} k - The value to be tweened.
  56204. * @returns {number} The tweened value.
  56205. */
  56206. Out: function ( k ) {
  56207. if ( k < ( 1 / 2.75 ) ) {
  56208. return 7.5625 * k * k;
  56209. } else if ( k < ( 2 / 2.75 ) ) {
  56210. return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
  56211. } else if ( k < ( 2.5 / 2.75 ) ) {
  56212. return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
  56213. } else {
  56214. return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
  56215. }
  56216. },
  56217. /**
  56218. * Bounce ease-in/out.
  56219. *
  56220. * @method Phaser.Easing.Bounce#InOut
  56221. * @param {number} k - The value to be tweened.
  56222. * @returns {number} The tweened value.
  56223. */
  56224. InOut: function ( k ) {
  56225. if ( k < 0.5 ) return Phaser.Easing.Bounce.In( k * 2 ) * 0.5;
  56226. return Phaser.Easing.Bounce.Out( k * 2 - 1 ) * 0.5 + 0.5;
  56227. }
  56228. }
  56229. };
  56230. Phaser.Easing.Default = Phaser.Easing.Linear.None;
  56231. Phaser.Easing.Power0 = Phaser.Easing.Linear.None;
  56232. Phaser.Easing.Power1 = Phaser.Easing.Quadratic.Out;
  56233. Phaser.Easing.Power2 = Phaser.Easing.Cubic.Out;
  56234. Phaser.Easing.Power3 = Phaser.Easing.Quartic.Out;
  56235. Phaser.Easing.Power4 = Phaser.Easing.Quintic.Out;
  56236. /**
  56237. * @author Richard Davey <rich@photonstorm.com>
  56238. * @copyright 2016 Photon Storm Ltd.
  56239. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  56240. */
  56241. /**
  56242. * This is the core internal game clock.
  56243. *
  56244. * It manages the elapsed time and calculation of elapsed values, used for game object motion and tweens,
  56245. * and also handles the standard Timer pool.
  56246. *
  56247. * To create a general timed event, use the master {@link Phaser.Timer} accessible through {@link Phaser.Time.events events}.
  56248. *
  56249. * There are different *types* of time in Phaser:
  56250. *
  56251. * - ***Game time*** always runs at the speed of time in real life.
  56252. *
  56253. * Unlike wall-clock time, *game time stops when Phaser is paused*.
  56254. *
  56255. * Game time is used for {@link Phaser.Timer timer events}.
  56256. *
  56257. * - ***Physics time*** represents the amount of time given to physics calculations.
  56258. *
  56259. * *When {@link #slowMotion} is in effect physics time runs slower than game time.*
  56260. * Like game time, physics time stops when Phaser is paused.
  56261. *
  56262. * Physics time is used for physics calculations and {@link Phaser.Tween tweens}.
  56263. *
  56264. * - {@link https://en.wikipedia.org/wiki/Wall-clock_time ***Wall-clock time***} represents the duration between two events in real life time.
  56265. *
  56266. * This time is independent of Phaser and always progresses, regardless of if Phaser is paused.
  56267. *
  56268. * @class Phaser.Time
  56269. * @constructor
  56270. * @param {Phaser.Game} game A reference to the currently running game.
  56271. */
  56272. Phaser.Time = function (game) {
  56273. /**
  56274. * @property {Phaser.Game} game - Local reference to game.
  56275. * @protected
  56276. */
  56277. this.game = game;
  56278. /**
  56279. * The `Date.now()` value when the time was last updated.
  56280. * @property {integer} time
  56281. * @protected
  56282. */
  56283. this.time = 0;
  56284. /**
  56285. * The `now` when the previous update occurred.
  56286. * @property {number} prevTime
  56287. * @protected
  56288. */
  56289. this.prevTime = 0;
  56290. /**
  56291. * An increasing value representing cumulative milliseconds since an undisclosed epoch.
  56292. *
  56293. * While this value is in milliseconds and can be used to compute time deltas,
  56294. * it must must _not_ be used with `Date.now()` as it may not use the same epoch / starting reference.
  56295. *
  56296. * The source may either be from a high-res source (eg. if RAF is available) or the standard Date.now;
  56297. * the value can only be relied upon within a particular game instance.
  56298. *
  56299. * @property {number} now
  56300. * @protected
  56301. */
  56302. this.now = 0;
  56303. /**
  56304. * Elapsed time since the last time update, in milliseconds, based on `now`.
  56305. *
  56306. * This value _may_ include time that the game is paused/inactive.
  56307. *
  56308. * _Note:_ This is updated only once per game loop - even if multiple logic update steps are done.
  56309. * Use {@link Phaser.Timer#physicsTime physicsTime} as a basis of game/logic calculations instead.
  56310. *
  56311. * @property {number} elapsed
  56312. * @see Phaser.Time.time
  56313. * @protected
  56314. */
  56315. this.elapsed = 0;
  56316. /**
  56317. * The time in ms since the last time update, in milliseconds, based on `time`.
  56318. *
  56319. * This value is corrected for game pauses and will be "about zero" after a game is resumed.
  56320. *
  56321. * _Note:_ This is updated once per game loop - even if multiple logic update steps are done.
  56322. * Use {@link Phaser.Timer#physicsTime physicsTime} as a basis of game/logic calculations instead.
  56323. *
  56324. * @property {integer} elapsedMS
  56325. * @protected
  56326. */
  56327. this.elapsedMS = 0;
  56328. /**
  56329. * The physics update delta, in fractional seconds.
  56330. *
  56331. * This should be used as an applicable multiplier by all logic update steps (eg. `preUpdate/postUpdate/update`)
  56332. * to ensure consistent game timing. Game/logic timing can drift from real-world time if the system
  56333. * is unable to consistently maintain the desired FPS.
  56334. *
  56335. * With fixed-step updates this is normally equivalent to `1.0 / desiredFps`.
  56336. *
  56337. * @property {number} physicsElapsed
  56338. */
  56339. this.physicsElapsed = 1 / 60;
  56340. /**
  56341. * The physics update delta, in milliseconds - equivalent to `physicsElapsed * 1000`.
  56342. *
  56343. * @property {number} physicsElapsedMS
  56344. */
  56345. this.physicsElapsedMS = (1 / 60) * 1000;
  56346. /**
  56347. * The desiredFps multiplier as used by Game.update.
  56348. * @property {integer} desiredFpsMult
  56349. * @protected
  56350. */
  56351. this.desiredFpsMult = 1.0 / 60;
  56352. /**
  56353. * The desired frame rate of the game.
  56354. *
  56355. * This is used is used to calculate the physic/logic multiplier and how to apply catch-up logic updates.
  56356. *
  56357. * @property {number} _desiredFps
  56358. * @private
  56359. * @default
  56360. */
  56361. this._desiredFps = 60;
  56362. /**
  56363. * The suggested frame rate for your game, based on an averaged real frame rate.
  56364. * This value is only populated if `Time.advancedTiming` is enabled.
  56365. *
  56366. * _Note:_ This is not available until after a few frames have passed; until then
  56367. * it's set to the same value as desiredFps.
  56368. *
  56369. * @property {number} suggestedFps
  56370. * @default
  56371. */
  56372. this.suggestedFps = this.desiredFps;
  56373. /**
  56374. * Scaling factor to make the game move smoothly in slow motion (or fast motion)
  56375. *
  56376. * - 1.0 = normal speed
  56377. * - 2.0 = half speed
  56378. * - 0.5 = double speed
  56379. *
  56380. * You likely need to adjust {@link #desiredFps} as well such that `desiredFps / slowMotion === 60`.
  56381. *
  56382. * @property {number} slowMotion
  56383. * @default
  56384. */
  56385. this.slowMotion = 1.0;
  56386. /**
  56387. * If true then advanced profiling, including the fps rate, fps min/max, suggestedFps and msMin/msMax are updated. This isn't expensive, but displaying it with {@link Phaser.Utils.Debug#text} can be, especially in WebGL mode.
  56388. * @property {boolean} advancedTiming
  56389. * @default
  56390. */
  56391. this.advancedTiming = false;
  56392. /**
  56393. * Advanced timing result: The number of render frames record in the last second.
  56394. *
  56395. * Only calculated if {@link Phaser.Time#advancedTiming advancedTiming} is enabled.
  56396. * @property {integer} frames
  56397. * @readonly
  56398. */
  56399. this.frames = 0;
  56400. /**
  56401. * Advanced timing result: Frames per second.
  56402. *
  56403. * Only calculated if {@link Phaser.Time#advancedTiming advancedTiming} is enabled.
  56404. * @property {number} fps
  56405. * @readonly
  56406. */
  56407. this.fps = 0;
  56408. /**
  56409. * Advanced timing result: The lowest rate the fps has dropped to.
  56410. *
  56411. * Only calculated if {@link Phaser.Time#advancedTiming advancedTiming} is enabled.
  56412. * This value can be manually reset.
  56413. * @property {number} fpsMin
  56414. */
  56415. this.fpsMin = 1000;
  56416. /**
  56417. * Advanced timing result: The highest rate the fps has reached (usually no higher than 60fps).
  56418. *
  56419. * Only calculated if {@link Phaser.Time#advancedTiming advancedTiming} is enabled.
  56420. * This value can be manually reset.
  56421. * @property {number} fpsMax
  56422. */
  56423. this.fpsMax = 0;
  56424. /**
  56425. * Advanced timing result: The minimum amount of time the game has taken between consecutive frames.
  56426. *
  56427. * Only calculated if {@link Phaser.Time#advancedTiming advancedTiming} is enabled.
  56428. * This value can be manually reset.
  56429. * @property {number} msMin
  56430. * @default
  56431. */
  56432. this.msMin = 1000;
  56433. /**
  56434. * Advanced timing result: The maximum amount of time the game has taken between consecutive frames.
  56435. *
  56436. * Only calculated if {@link Phaser.Time#advancedTiming advancedTiming} is enabled.
  56437. * This value can be manually reset.
  56438. * @property {number} msMax
  56439. */
  56440. this.msMax = 0;
  56441. /**
  56442. * Records how long the game was last paused, in milliseconds.
  56443. * (This is not updated until the game is resumed.)
  56444. * @property {number} pauseDuration
  56445. */
  56446. this.pauseDuration = 0;
  56447. /**
  56448. * @property {number} timeToCall - The value that setTimeout needs to work out when to next update
  56449. * @protected
  56450. */
  56451. this.timeToCall = 0;
  56452. /**
  56453. * @property {number} timeExpected - The time when the next call is expected when using setTimer to control the update loop
  56454. * @protected
  56455. */
  56456. this.timeExpected = 0;
  56457. /**
  56458. * A {@link Phaser.Timer} object bound to the master clock (this Time object) which events can be added to.
  56459. * @property {Phaser.Timer} events
  56460. */
  56461. this.events = new Phaser.Timer(this.game, false);
  56462. /**
  56463. * @property {number} _frameCount - count the number of calls to time.update since the last suggestedFps was calculated
  56464. * @private
  56465. */
  56466. this._frameCount = 0;
  56467. /**
  56468. * @property {number} _elapsedAcumulator - sum of the elapsed time since the last suggestedFps was calculated
  56469. * @private
  56470. */
  56471. this._elapsedAccumulator = 0;
  56472. /**
  56473. * @property {number} _started - The time at which the Game instance started.
  56474. * @private
  56475. */
  56476. this._started = 0;
  56477. /**
  56478. * @property {number} _timeLastSecond - The time (in ms) that the last second counter ticked over.
  56479. * @private
  56480. */
  56481. this._timeLastSecond = 0;
  56482. /**
  56483. * @property {number} _pauseStarted - The time the game started being paused.
  56484. * @private
  56485. */
  56486. this._pauseStarted = 0;
  56487. /**
  56488. * @property {boolean} _justResumed - Internal value used to recover from the game pause state.
  56489. * @private
  56490. */
  56491. this._justResumed = false;
  56492. /**
  56493. * @property {Phaser.Timer[]} _timers - Internal store of Phaser.Timer objects.
  56494. * @private
  56495. */
  56496. this._timers = [];
  56497. };
  56498. Phaser.Time.prototype = {
  56499. /**
  56500. * Called automatically by Phaser.Game after boot. Should not be called directly.
  56501. *
  56502. * @method Phaser.Time#boot
  56503. * @protected
  56504. */
  56505. boot: function () {
  56506. this._started = Date.now();
  56507. this.time = Date.now();
  56508. this.events.start();
  56509. this.timeExpected = this.time;
  56510. },
  56511. /**
  56512. * Adds an existing Phaser.Timer object to the Timer pool.
  56513. *
  56514. * @method Phaser.Time#add
  56515. * @param {Phaser.Timer} timer - An existing Phaser.Timer object.
  56516. * @return {Phaser.Timer} The given Phaser.Timer object.
  56517. */
  56518. add: function (timer) {
  56519. this._timers.push(timer);
  56520. return timer;
  56521. },
  56522. /**
  56523. * Creates a new stand-alone Phaser.Timer object.
  56524. *
  56525. * @method Phaser.Time#create
  56526. * @param {boolean} [autoDestroy=true] - A Timer that is set to automatically destroy itself will do so after all of its events have been dispatched (assuming no looping events).
  56527. * @return {Phaser.Timer} The Timer object that was created.
  56528. */
  56529. create: function (autoDestroy) {
  56530. if (autoDestroy === undefined) { autoDestroy = true; }
  56531. var timer = new Phaser.Timer(this.game, autoDestroy);
  56532. this._timers.push(timer);
  56533. return timer;
  56534. },
  56535. /**
  56536. * Remove all Timer objects, regardless of their state and clears all Timers from the {@link Phaser.Time#events events} timer.
  56537. *
  56538. * @method Phaser.Time#removeAll
  56539. */
  56540. removeAll: function () {
  56541. for (var i = 0; i < this._timers.length; i++)
  56542. {
  56543. this._timers[i].destroy();
  56544. }
  56545. this._timers = [];
  56546. this.events.removeAll();
  56547. },
  56548. /**
  56549. * Refreshes the Time.time and Time.elapsedMS properties from the system clock.
  56550. *
  56551. * @method Phaser.Time#refresh
  56552. */
  56553. refresh: function () {
  56554. // Set to the old Date.now value
  56555. var previousDateNow = this.time;
  56556. // this.time always holds a Date.now value
  56557. this.time = Date.now();
  56558. // Adjust accordingly.
  56559. this.elapsedMS = this.time - previousDateNow;
  56560. },
  56561. /**
  56562. * Updates the game clock and if enabled the advanced timing data. This is called automatically by Phaser.Game.
  56563. *
  56564. * @method Phaser.Time#update
  56565. * @protected
  56566. * @param {number} time - The current relative timestamp; see {@link Phaser.Time#now now}.
  56567. */
  56568. update: function (time) {
  56569. // Set to the old Date.now value
  56570. var previousDateNow = this.time;
  56571. // this.time always holds a Date.now value
  56572. this.time = Date.now();
  56573. // Adjust accordingly.
  56574. this.elapsedMS = this.time - previousDateNow;
  56575. // 'now' is currently still holding the time of the last call, move it into prevTime
  56576. this.prevTime = this.now;
  56577. // update 'now' to hold the current time
  56578. // this.now may hold the RAF high resolution time value if RAF is available (otherwise it also holds Date.now)
  56579. this.now = time;
  56580. // elapsed time between previous call and now - this could be a high resolution value
  56581. this.elapsed = this.now - this.prevTime;
  56582. if (this.game.raf._isSetTimeOut)
  56583. {
  56584. // console.log('Time isSet', this._desiredFps, 'te', this.timeExpected, 'time', time);
  56585. // time to call this function again in ms in case we're using timers instead of RequestAnimationFrame to update the game
  56586. this.timeToCall = Math.floor(Math.max(0, (1000.0 / this._desiredFps) - (this.timeExpected - time)));
  56587. // time when the next call is expected if using timers
  56588. this.timeExpected = time + this.timeToCall;
  56589. // console.log('Time expect', this.timeExpected);
  56590. }
  56591. if (this.advancedTiming)
  56592. {
  56593. this.updateAdvancedTiming();
  56594. }
  56595. // Paused but still running?
  56596. if (!this.game.paused)
  56597. {
  56598. // Our internal Phaser.Timer
  56599. this.events.update(this.time);
  56600. if (this._timers.length)
  56601. {
  56602. this.updateTimers();
  56603. }
  56604. }
  56605. },
  56606. /**
  56607. * Handles the updating of the Phaser.Timers (if any)
  56608. * Called automatically by Time.update.
  56609. *
  56610. * @method Phaser.Time#updateTimers
  56611. * @private
  56612. */
  56613. updateTimers: function () {
  56614. // Any game level timers
  56615. var i = 0;
  56616. var len = this._timers.length;
  56617. while (i < len)
  56618. {
  56619. if (this._timers[i].update(this.time))
  56620. {
  56621. i++;
  56622. }
  56623. else
  56624. {
  56625. // Timer requests to be removed
  56626. this._timers.splice(i, 1);
  56627. len--;
  56628. }
  56629. }
  56630. },
  56631. /**
  56632. * Handles the updating of the advanced timing values (if enabled)
  56633. * Called automatically by Time.update.
  56634. *
  56635. * @method Phaser.Time#updateAdvancedTiming
  56636. * @private
  56637. */
  56638. updateAdvancedTiming: function () {
  56639. // count the number of time.update calls
  56640. this._frameCount++;
  56641. this._elapsedAccumulator += this.elapsed;
  56642. // occasionally recalculate the suggestedFps based on the accumulated elapsed time
  56643. if (this._frameCount >= this._desiredFps * 2)
  56644. {
  56645. // this formula calculates suggestedFps in multiples of 5 fps
  56646. this.suggestedFps = Math.floor(200 / (this._elapsedAccumulator / this._frameCount)) * 5;
  56647. this._frameCount = 0;
  56648. this._elapsedAccumulator = 0;
  56649. }
  56650. this.msMin = Math.min(this.msMin, this.elapsed);
  56651. this.msMax = Math.max(this.msMax, this.elapsed);
  56652. this.frames++;
  56653. if (this.now > this._timeLastSecond + 1000)
  56654. {
  56655. this.fps = Math.round((this.frames * 1000) / (this.now - this._timeLastSecond));
  56656. this.fpsMin = Math.min(this.fpsMin, this.fps);
  56657. this.fpsMax = Math.max(this.fpsMax, this.fps);
  56658. this._timeLastSecond = this.now;
  56659. this.frames = 0;
  56660. }
  56661. },
  56662. /**
  56663. * Called when the game enters a paused state.
  56664. *
  56665. * @method Phaser.Time#gamePaused
  56666. * @private
  56667. */
  56668. gamePaused: function () {
  56669. this._pauseStarted = Date.now();
  56670. this.events.pause();
  56671. var i = this._timers.length;
  56672. while (i--)
  56673. {
  56674. this._timers[i]._pause();
  56675. }
  56676. },
  56677. /**
  56678. * Called when the game resumes from a paused state.
  56679. *
  56680. * @method Phaser.Time#gameResumed
  56681. * @private
  56682. */
  56683. gameResumed: function () {
  56684. // Set the parameter which stores Date.now() to make sure it's correct on resume
  56685. this.time = Date.now();
  56686. this.pauseDuration = this.time - this._pauseStarted;
  56687. this.events.resume();
  56688. var i = this._timers.length;
  56689. while (i--)
  56690. {
  56691. this._timers[i]._resume();
  56692. }
  56693. },
  56694. /**
  56695. * The number of seconds that have elapsed since the game was started.
  56696. *
  56697. * @method Phaser.Time#totalElapsedSeconds
  56698. * @return {number} The number of seconds that have elapsed since the game was started.
  56699. */
  56700. totalElapsedSeconds: function() {
  56701. return (this.time - this._started) * 0.001;
  56702. },
  56703. /**
  56704. * How long has passed since the given time.
  56705. *
  56706. * @method Phaser.Time#elapsedSince
  56707. * @param {number} since - The time you want to measure against.
  56708. * @return {number} The difference between the given time and now.
  56709. */
  56710. elapsedSince: function (since) {
  56711. return this.time - since;
  56712. },
  56713. /**
  56714. * How long has passed since the given time (in seconds).
  56715. *
  56716. * @method Phaser.Time#elapsedSecondsSince
  56717. * @param {number} since - The time you want to measure (in seconds).
  56718. * @return {number} Duration between given time and now (in seconds).
  56719. */
  56720. elapsedSecondsSince: function (since) {
  56721. return (this.time - since) * 0.001;
  56722. },
  56723. /**
  56724. * Resets the private _started value to now and removes all currently running Timers.
  56725. *
  56726. * @method Phaser.Time#reset
  56727. */
  56728. reset: function () {
  56729. this._started = this.time;
  56730. this.removeAll();
  56731. }
  56732. };
  56733. /**
  56734. * The desired frame rate of the game.
  56735. *
  56736. * This is used is used to calculate the physic / logic multiplier and how to apply catch-up logic updates.
  56737. *
  56738. * @name Phaser.Time#desiredFps
  56739. * @property {integer} desiredFps - The desired frame rate of the game. Defaults to 60.
  56740. */
  56741. Object.defineProperty(Phaser.Time.prototype, "desiredFps", {
  56742. get: function () {
  56743. return this._desiredFps;
  56744. },
  56745. set: function (value) {
  56746. this._desiredFps = value;
  56747. // Set the physics elapsed time... this will always be 1 / this.desiredFps
  56748. // because we're using fixed time steps in game.update
  56749. this.physicsElapsed = 1 / value;
  56750. this.physicsElapsedMS = this.physicsElapsed * 1000;
  56751. this.desiredFpsMult = 1.0 / value;
  56752. }
  56753. });
  56754. Phaser.Time.prototype.constructor = Phaser.Time;
  56755. /**
  56756. * @author Richard Davey <rich@photonstorm.com>
  56757. * @copyright 2016 Photon Storm Ltd.
  56758. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  56759. */
  56760. /**
  56761. * A Timer is a way to create and manage {@link Phaser.TimerEvent timer events} that wait for a specific duration and then run a callback.
  56762. * Many different timer events, with individual delays, can be added to the same Timer.
  56763. *
  56764. * All Timer delays are in milliseconds (there are 1000 ms in 1 second); so a delay value of 250 represents a quarter of a second.
  56765. *
  56766. * Timers are based on real life time, adjusted for game pause durations.
  56767. * That is, *timer events are based on elapsed {@link Phaser.Time game time}* and do *not* take physics time or slow motion into account.
  56768. *
  56769. * @class Phaser.Timer
  56770. * @constructor
  56771. * @param {Phaser.Game} game - A reference to the currently running game.
  56772. * @param {boolean} [autoDestroy=true] - If true, the timer will automatically destroy itself after all the events have been dispatched (assuming no looping events).
  56773. */
  56774. Phaser.Timer = function (game, autoDestroy) {
  56775. if (autoDestroy === undefined) { autoDestroy = true; }
  56776. /**
  56777. * @property {Phaser.Game} game - Local reference to game.
  56778. * @protected
  56779. */
  56780. this.game = game;
  56781. /**
  56782. * True if the Timer is actively running.
  56783. *
  56784. * Do not modify this boolean - use {@link Phaser.Timer#pause pause} (and {@link Phaser.Timer#resume resume}) to pause the timer.
  56785. * @property {boolean} running
  56786. * @default
  56787. * @readonly
  56788. */
  56789. this.running = false;
  56790. /**
  56791. * If true, the timer will automatically destroy itself after all the events have been dispatched (assuming no looping events).
  56792. * @property {boolean} autoDestroy
  56793. */
  56794. this.autoDestroy = autoDestroy;
  56795. /**
  56796. * @property {boolean} expired - An expired Timer is one in which all of its events have been dispatched and none are pending.
  56797. * @readonly
  56798. * @default
  56799. */
  56800. this.expired = false;
  56801. /**
  56802. * @property {number} elapsed - Elapsed time since the last frame (in ms).
  56803. * @protected
  56804. */
  56805. this.elapsed = 0;
  56806. /**
  56807. * @property {Phaser.TimerEvent[]} events - An array holding all of this timers Phaser.TimerEvent objects. Use the methods add, repeat and loop to populate it.
  56808. */
  56809. this.events = [];
  56810. /**
  56811. * This signal will be dispatched when this Timer has completed which means that there are no more events in the queue.
  56812. *
  56813. * The signal is supplied with one argument, `timer`, which is this Timer object.
  56814. *
  56815. * @property {Phaser.Signal} onComplete
  56816. */
  56817. this.onComplete = new Phaser.Signal();
  56818. /**
  56819. * @property {number} nextTick - The time the next tick will occur.
  56820. * @readonly
  56821. * @protected
  56822. */
  56823. this.nextTick = 0;
  56824. /**
  56825. * @property {number} timeCap - If the difference in time between two frame updates exceeds this value, the event times are reset to avoid catch-up situations.
  56826. */
  56827. this.timeCap = 1000;
  56828. /**
  56829. * @property {boolean} paused - The paused state of the Timer. You can pause the timer by calling Timer.pause() and Timer.resume() or by the game pausing.
  56830. * @readonly
  56831. * @default
  56832. */
  56833. this.paused = false;
  56834. /**
  56835. * @property {boolean} _codePaused - Was the Timer paused by code or by Game focus loss?
  56836. * @private
  56837. */
  56838. this._codePaused = false;
  56839. /**
  56840. * @property {number} _started - The time at which this Timer instance started running.
  56841. * @private
  56842. * @default
  56843. */
  56844. this._started = 0;
  56845. /**
  56846. * @property {number} _pauseStarted - The time the game started being paused.
  56847. * @private
  56848. */
  56849. this._pauseStarted = 0;
  56850. /**
  56851. * @property {number} _pauseTotal - Total paused time.
  56852. * @private
  56853. */
  56854. this._pauseTotal = 0;
  56855. /**
  56856. * @property {number} _now - The current start-time adjusted time.
  56857. * @private
  56858. */
  56859. this._now = Date.now();
  56860. /**
  56861. * @property {number} _len - Temp. array length variable.
  56862. * @private
  56863. */
  56864. this._len = 0;
  56865. /**
  56866. * @property {number} _marked - Temp. counter variable.
  56867. * @private
  56868. */
  56869. this._marked = 0;
  56870. /**
  56871. * @property {number} _i - Temp. array counter variable.
  56872. * @private
  56873. */
  56874. this._i = 0;
  56875. /**
  56876. * @property {number} _diff - Internal cache var.
  56877. * @private
  56878. */
  56879. this._diff = 0;
  56880. /**
  56881. * @property {number} _newTick - Internal cache var.
  56882. * @private
  56883. */
  56884. this._newTick = 0;
  56885. };
  56886. /**
  56887. * Number of milliseconds in a minute.
  56888. * @constant
  56889. * @type {integer}
  56890. */
  56891. Phaser.Timer.MINUTE = 60000;
  56892. /**
  56893. * Number of milliseconds in a second.
  56894. * @constant
  56895. * @type {integer}
  56896. */
  56897. Phaser.Timer.SECOND = 1000;
  56898. /**
  56899. * Number of milliseconds in half a second.
  56900. * @constant
  56901. * @type {integer}
  56902. */
  56903. Phaser.Timer.HALF = 500;
  56904. /**
  56905. * Number of milliseconds in a quarter of a second.
  56906. * @constant
  56907. * @type {integer}
  56908. */
  56909. Phaser.Timer.QUARTER = 250;
  56910. Phaser.Timer.prototype = {
  56911. /**
  56912. * Creates a new TimerEvent on this Timer.
  56913. *
  56914. * Use {@link Phaser.Timer#add}, {@link Phaser.Timer#repeat}, or {@link Phaser.Timer#loop} methods to create a new event.
  56915. *
  56916. * @method Phaser.Timer#create
  56917. * @private
  56918. * @param {integer} delay - The number of milliseconds, in {@link Phaser.Time game time}, before the timer event occurs.
  56919. * @param {boolean} loop - Should the event loop or not?
  56920. * @param {number} repeatCount - The number of times the event will repeat.
  56921. * @param {function} callback - The callback that will be called when the timer event occurs.
  56922. * @param {object} callbackContext - The context in which the callback will be called.
  56923. * @param {any[]} arguments - The values to be sent to your callback function when it is called.
  56924. * @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
  56925. */
  56926. create: function (delay, loop, repeatCount, callback, callbackContext, args) {
  56927. delay = Math.round(delay);
  56928. var tick = delay;
  56929. if (this._now === 0)
  56930. {
  56931. tick += this.game.time.time;
  56932. }
  56933. else
  56934. {
  56935. tick += this._now;
  56936. }
  56937. var event = new Phaser.TimerEvent(this, delay, tick, repeatCount, loop, callback, callbackContext, args);
  56938. this.events.push(event);
  56939. this.order();
  56940. this.expired = false;
  56941. return event;
  56942. },
  56943. /**
  56944. * Adds a new Event to this Timer.
  56945. *
  56946. * The event will fire after the given amount of `delay` in milliseconds has passed, once the Timer has started running.
  56947. * The delay is in relation to when the Timer starts, not the time it was added. If the Timer is already running the delay will be calculated based on the timers current time.
  56948. *
  56949. * Make sure to call {@link Phaser.Timer#start start} after adding all of the Events you require for this Timer.
  56950. *
  56951. * @method Phaser.Timer#add
  56952. * @param {integer} delay - The number of milliseconds, in {@link Phaser.Time game time}, before the timer event occurs.
  56953. * @param {function} callback - The callback that will be called when the timer event occurs.
  56954. * @param {object} callbackContext - The context in which the callback will be called.
  56955. * @param {...*} arguments - Additional arguments that will be supplied to the callback.
  56956. * @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
  56957. */
  56958. add: function (delay, callback, callbackContext) {
  56959. return this.create(delay, false, 0, callback, callbackContext, Array.prototype.slice.call(arguments, 3));
  56960. },
  56961. /**
  56962. * Adds a new TimerEvent that will always play through once and then repeat for the given number of iterations.
  56963. *
  56964. * The event will fire after the given amount of `delay` in milliseconds has passed, once the Timer has started running.
  56965. * The delay is in relation to when the Timer starts, not the time it was added.
  56966. * If the Timer is already running the delay will be calculated based on the timers current time.
  56967. *
  56968. * Make sure to call {@link Phaser.Timer#start start} after adding all of the Events you require for this Timer.
  56969. *
  56970. * @method Phaser.Timer#repeat
  56971. * @param {integer} delay - The number of milliseconds, in {@link Phaser.Time game time}, before the timer event occurs.
  56972. * @param {number} repeatCount - The number of times the event will repeat once is has finished playback. A repeatCount of 1 means it will repeat itself once, playing the event twice in total.
  56973. * @param {function} callback - The callback that will be called when the timer event occurs.
  56974. * @param {object} callbackContext - The context in which the callback will be called.
  56975. * @param {...*} arguments - Additional arguments that will be supplied to the callback.
  56976. * @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
  56977. */
  56978. repeat: function (delay, repeatCount, callback, callbackContext) {
  56979. return this.create(delay, false, repeatCount, callback, callbackContext, Array.prototype.slice.call(arguments, 4));
  56980. },
  56981. /**
  56982. * Adds a new looped Event to this Timer that will repeat forever or until the Timer is stopped.
  56983. *
  56984. * The event will fire after the given amount of `delay` in milliseconds has passed, once the Timer has started running.
  56985. * The delay is in relation to when the Timer starts, not the time it was added. If the Timer is already running the delay will be calculated based on the timers current time.
  56986. *
  56987. * Make sure to call {@link Phaser.Timer#start start} after adding all of the Events you require for this Timer.
  56988. *
  56989. * @method Phaser.Timer#loop
  56990. * @param {integer} delay - The number of milliseconds, in {@link Phaser.Time game time}, before the timer event occurs.
  56991. * @param {function} callback - The callback that will be called when the timer event occurs.
  56992. * @param {object} callbackContext - The context in which the callback will be called.
  56993. * @param {...*} arguments - Additional arguments that will be supplied to the callback.
  56994. * @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
  56995. */
  56996. loop: function (delay, callback, callbackContext) {
  56997. return this.create(delay, true, 0, callback, callbackContext, Array.prototype.slice.call(arguments, 3));
  56998. },
  56999. /**
  57000. * Starts this Timer running.
  57001. * @method Phaser.Timer#start
  57002. * @param {integer} [delay=0] - The number of milliseconds, in {@link Phaser.Time game time}, that should elapse before the Timer will start.
  57003. */
  57004. start: function (delay) {
  57005. if (this.running)
  57006. {
  57007. return;
  57008. }
  57009. this._started = this.game.time.time + (delay || 0);
  57010. this.running = true;
  57011. for (var i = 0; i < this.events.length; i++)
  57012. {
  57013. this.events[i].tick = this.events[i].delay + this._started;
  57014. }
  57015. },
  57016. /**
  57017. * Stops this Timer from running. Does not cause it to be destroyed if autoDestroy is set to true.
  57018. * @method Phaser.Timer#stop
  57019. * @param {boolean} [clearEvents=true] - If true all the events in Timer will be cleared, otherwise they will remain.
  57020. */
  57021. stop: function (clearEvents) {
  57022. this.running = false;
  57023. if (clearEvents === undefined) { clearEvents = true; }
  57024. if (clearEvents)
  57025. {
  57026. this.events.length = 0;
  57027. }
  57028. },
  57029. /**
  57030. * Removes a pending TimerEvent from the queue.
  57031. * @param {Phaser.TimerEvent} event - The event to remove from the queue.
  57032. * @method Phaser.Timer#remove
  57033. */
  57034. remove: function (event) {
  57035. for (var i = 0; i < this.events.length; i++)
  57036. {
  57037. if (this.events[i] === event)
  57038. {
  57039. this.events[i].pendingDelete = true;
  57040. return true;
  57041. }
  57042. }
  57043. return false;
  57044. },
  57045. /**
  57046. * Orders the events on this Timer so they are in tick order.
  57047. * This is called automatically when new events are created.
  57048. * @method Phaser.Timer#order
  57049. * @protected
  57050. */
  57051. order: function () {
  57052. if (this.events.length > 0)
  57053. {
  57054. // Sort the events so the one with the lowest tick is first
  57055. this.events.sort(this.sortHandler);
  57056. this.nextTick = this.events[0].tick;
  57057. }
  57058. },
  57059. /**
  57060. * Sort handler used by Phaser.Timer.order.
  57061. * @method Phaser.Timer#sortHandler
  57062. * @private
  57063. */
  57064. sortHandler: function (a, b) {
  57065. if (a.tick < b.tick)
  57066. {
  57067. return -1;
  57068. }
  57069. else if (a.tick > b.tick)
  57070. {
  57071. return 1;
  57072. }
  57073. return 0;
  57074. },
  57075. /**
  57076. * Clears any events from the Timer which have pendingDelete set to true and then resets the private _len and _i values.
  57077. *
  57078. * @method Phaser.Timer#clearPendingEvents
  57079. * @protected
  57080. */
  57081. clearPendingEvents: function () {
  57082. this._i = this.events.length;
  57083. while (this._i--)
  57084. {
  57085. if (this.events[this._i].pendingDelete)
  57086. {
  57087. this.events.splice(this._i, 1);
  57088. }
  57089. }
  57090. this._len = this.events.length;
  57091. this._i = 0;
  57092. },
  57093. /**
  57094. * The main Timer update event, called automatically by Phaser.Time.update.
  57095. *
  57096. * @method Phaser.Timer#update
  57097. * @protected
  57098. * @param {number} time - The time from the core game clock.
  57099. * @return {boolean} True if there are still events waiting to be dispatched, otherwise false if this Timer can be destroyed.
  57100. */
  57101. update: function (time) {
  57102. if (this.paused)
  57103. {
  57104. return true;
  57105. }
  57106. this.elapsed = time - this._now;
  57107. this._now = time;
  57108. // spike-dislike
  57109. if (this.elapsed > this.timeCap)
  57110. {
  57111. // For some reason the time between now and the last time the game was updated was larger than our timeCap.
  57112. // This can happen if the Stage.disableVisibilityChange is true and you swap tabs, which makes the raf pause.
  57113. // In this case we need to adjust the TimerEvents and nextTick.
  57114. this.adjustEvents(time - this.elapsed);
  57115. }
  57116. this._marked = 0;
  57117. // Clears events marked for deletion and resets _len and _i to 0.
  57118. this.clearPendingEvents();
  57119. if (this.running && this._now >= this.nextTick && this._len > 0)
  57120. {
  57121. while (this._i < this._len && this.running)
  57122. {
  57123. var event = this.events[this._i];
  57124. if (this._now >= event.tick && !event.pendingDelete)
  57125. {
  57126. // (now + delay) - (time difference from last tick to now)
  57127. this._newTick = (this._now + event.delay) - (this._now - event.tick);
  57128. if (this._newTick < 0)
  57129. {
  57130. this._newTick = this._now + event.delay;
  57131. }
  57132. if (event.loop === true)
  57133. {
  57134. event.tick = this._newTick;
  57135. event.callback.apply(event.callbackContext, event.args);
  57136. }
  57137. else if (event.repeatCount > 0)
  57138. {
  57139. event.repeatCount--;
  57140. event.tick = this._newTick;
  57141. event.callback.apply(event.callbackContext, event.args);
  57142. }
  57143. else
  57144. {
  57145. this._marked++;
  57146. event.pendingDelete = true;
  57147. event.callback.apply(event.callbackContext, event.args);
  57148. }
  57149. this._i++;
  57150. }
  57151. else
  57152. {
  57153. break;
  57154. }
  57155. }
  57156. // Are there any events left?
  57157. if (this.events.length > this._marked)
  57158. {
  57159. this.order();
  57160. }
  57161. else
  57162. {
  57163. this.expired = true;
  57164. this.onComplete.dispatch(this);
  57165. }
  57166. }
  57167. if (this.expired && this.autoDestroy)
  57168. {
  57169. return false;
  57170. }
  57171. else
  57172. {
  57173. return true;
  57174. }
  57175. },
  57176. /**
  57177. * Pauses the Timer and all events in the queue.
  57178. * @method Phaser.Timer#pause
  57179. */
  57180. pause: function () {
  57181. if (!this.running)
  57182. {
  57183. return;
  57184. }
  57185. this._codePaused = true;
  57186. if (this.paused)
  57187. {
  57188. return;
  57189. }
  57190. this._pauseStarted = this.game.time.time;
  57191. this.paused = true;
  57192. },
  57193. /**
  57194. * Internal pause/resume control - user code should use Timer.pause instead.
  57195. * @method Phaser.Timer#_pause
  57196. * @private
  57197. */
  57198. _pause: function () {
  57199. if (this.paused || !this.running)
  57200. {
  57201. return;
  57202. }
  57203. this._pauseStarted = this.game.time.time;
  57204. this.paused = true;
  57205. },
  57206. /**
  57207. * Adjusts the time of all pending events and the nextTick by the given baseTime.
  57208. *
  57209. * @method Phaser.Timer#adjustEvents
  57210. * @protected
  57211. */
  57212. adjustEvents: function (baseTime) {
  57213. for (var i = 0; i < this.events.length; i++)
  57214. {
  57215. if (!this.events[i].pendingDelete)
  57216. {
  57217. // Work out how long there would have been from when the game paused until the events next tick
  57218. var t = this.events[i].tick - baseTime;
  57219. if (t < 0)
  57220. {
  57221. t = 0;
  57222. }
  57223. // Add the difference on to the time now
  57224. this.events[i].tick = this._now + t;
  57225. }
  57226. }
  57227. var d = this.nextTick - baseTime;
  57228. if (d < 0)
  57229. {
  57230. this.nextTick = this._now;
  57231. }
  57232. else
  57233. {
  57234. this.nextTick = this._now + d;
  57235. }
  57236. },
  57237. /**
  57238. * Resumes the Timer and updates all pending events.
  57239. *
  57240. * @method Phaser.Timer#resume
  57241. */
  57242. resume: function () {
  57243. if (!this.paused)
  57244. {
  57245. return;
  57246. }
  57247. var now = this.game.time.time;
  57248. this._pauseTotal += now - this._now;
  57249. this._now = now;
  57250. this.adjustEvents(this._pauseStarted);
  57251. this.paused = false;
  57252. this._codePaused = false;
  57253. },
  57254. /**
  57255. * Internal pause/resume control - user code should use Timer.resume instead.
  57256. * @method Phaser.Timer#_resume
  57257. * @private
  57258. */
  57259. _resume: function () {
  57260. if (this._codePaused)
  57261. {
  57262. return;
  57263. }
  57264. else
  57265. {
  57266. this.resume();
  57267. }
  57268. },
  57269. /**
  57270. * Removes all Events from this Timer and all callbacks linked to onComplete, but leaves the Timer running.
  57271. * The onComplete callbacks won't be called.
  57272. *
  57273. * @method Phaser.Timer#removeAll
  57274. */
  57275. removeAll: function () {
  57276. this.onComplete.removeAll();
  57277. this.events.length = 0;
  57278. this._len = 0;
  57279. this._i = 0;
  57280. },
  57281. /**
  57282. * Destroys this Timer. Any pending Events are not dispatched.
  57283. * The onComplete callbacks won't be called.
  57284. *
  57285. * @method Phaser.Timer#destroy
  57286. */
  57287. destroy: function () {
  57288. this.onComplete.removeAll();
  57289. this.running = false;
  57290. this.expired = true;
  57291. this.events = [];
  57292. this._len = 0;
  57293. this._i = 0;
  57294. }
  57295. };
  57296. /**
  57297. * @name Phaser.Timer#next
  57298. * @property {number} next - The time at which the next event will occur.
  57299. * @readonly
  57300. */
  57301. Object.defineProperty(Phaser.Timer.prototype, "next", {
  57302. get: function () {
  57303. return this.nextTick;
  57304. }
  57305. });
  57306. /**
  57307. * @name Phaser.Timer#duration
  57308. * @property {number} duration - The duration in ms remaining until the next event will occur.
  57309. * @readonly
  57310. */
  57311. Object.defineProperty(Phaser.Timer.prototype, "duration", {
  57312. get: function () {
  57313. if (this.running && this.nextTick > this._now)
  57314. {
  57315. return this.nextTick - this._now;
  57316. }
  57317. else
  57318. {
  57319. return 0;
  57320. }
  57321. }
  57322. });
  57323. /**
  57324. * @name Phaser.Timer#length
  57325. * @property {number} length - The number of pending events in the queue.
  57326. * @readonly
  57327. */
  57328. Object.defineProperty(Phaser.Timer.prototype, "length", {
  57329. get: function () {
  57330. return this.events.length;
  57331. }
  57332. });
  57333. /**
  57334. * @name Phaser.Timer#ms
  57335. * @property {number} ms - The duration in milliseconds that this Timer has been running for.
  57336. * @readonly
  57337. */
  57338. Object.defineProperty(Phaser.Timer.prototype, "ms", {
  57339. get: function () {
  57340. if (this.running)
  57341. {
  57342. return this._now - this._started - this._pauseTotal;
  57343. }
  57344. else
  57345. {
  57346. return 0;
  57347. }
  57348. }
  57349. });
  57350. /**
  57351. * @name Phaser.Timer#seconds
  57352. * @property {number} seconds - The duration in seconds that this Timer has been running for.
  57353. * @readonly
  57354. */
  57355. Object.defineProperty(Phaser.Timer.prototype, "seconds", {
  57356. get: function () {
  57357. if (this.running)
  57358. {
  57359. return this.ms * 0.001;
  57360. }
  57361. else
  57362. {
  57363. return 0;
  57364. }
  57365. }
  57366. });
  57367. Phaser.Timer.prototype.constructor = Phaser.Timer;
  57368. /**
  57369. * @author Richard Davey <rich@photonstorm.com>
  57370. * @copyright 2016 Photon Storm Ltd.
  57371. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  57372. */
  57373. /**
  57374. * A TimerEvent is a single event that is processed by a Phaser.Timer.
  57375. *
  57376. * It consists of a delay, which is a value in milliseconds after which the event will fire.
  57377. * When the event fires it calls a specific callback with the specified arguments.
  57378. *
  57379. * TimerEvents are removed by their parent timer once finished firing or repeating.
  57380. *
  57381. * Use {@link Phaser.Timer#add}, {@link Phaser.Timer#repeat}, or {@link Phaser.Timer#loop} methods to create a new event.
  57382. *
  57383. * @class Phaser.TimerEvent
  57384. * @constructor
  57385. * @param {Phaser.Timer} timer - The Timer object that this TimerEvent belongs to.
  57386. * @param {number} delay - The delay in ms at which this TimerEvent fires.
  57387. * @param {number} tick - The tick is the next game clock time that this event will fire at.
  57388. * @param {number} repeatCount - If this TimerEvent repeats it will do so this many times.
  57389. * @param {boolean} loop - True if this TimerEvent loops, otherwise false.
  57390. * @param {function} callback - The callback that will be called when the TimerEvent occurs.
  57391. * @param {object} callbackContext - The context in which the callback will be called.
  57392. * @param {any[]} arguments - Additional arguments to be passed to the callback.
  57393. */
  57394. Phaser.TimerEvent = function (timer, delay, tick, repeatCount, loop, callback, callbackContext, args) {
  57395. /**
  57396. * @property {Phaser.Timer} timer - The Timer object that this TimerEvent belongs to.
  57397. * @protected
  57398. * @readonly
  57399. */
  57400. this.timer = timer;
  57401. /**
  57402. * @property {number} delay - The delay in ms at which this TimerEvent fires.
  57403. */
  57404. this.delay = delay;
  57405. /**
  57406. * @property {number} tick - The tick is the next game clock time that this event will fire at.
  57407. */
  57408. this.tick = tick;
  57409. /**
  57410. * @property {number} repeatCount - If this TimerEvent repeats it will do so this many times.
  57411. */
  57412. this.repeatCount = repeatCount - 1;
  57413. /**
  57414. * @property {boolean} loop - True if this TimerEvent loops, otherwise false.
  57415. */
  57416. this.loop = loop;
  57417. /**
  57418. * @property {function} callback - The callback that will be called when the TimerEvent occurs.
  57419. */
  57420. this.callback = callback;
  57421. /**
  57422. * @property {object} callbackContext - The context in which the callback will be called.
  57423. */
  57424. this.callbackContext = callbackContext;
  57425. /**
  57426. * @property {any[]} arguments - Additional arguments to be passed to the callback.
  57427. */
  57428. this.args = args;
  57429. /**
  57430. * @property {boolean} pendingDelete - A flag that controls if the TimerEvent is pending deletion.
  57431. * @protected
  57432. */
  57433. this.pendingDelete = false;
  57434. };
  57435. Phaser.TimerEvent.prototype.constructor = Phaser.TimerEvent;
  57436. /**
  57437. * @author Richard Davey <rich@photonstorm.com>
  57438. * @copyright 2016 Photon Storm Ltd.
  57439. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  57440. */
  57441. /**
  57442. * The Animation Manager is used to add, play and update Phaser Animations.
  57443. * Any Game Object such as Phaser.Sprite that supports animation contains a single AnimationManager instance.
  57444. *
  57445. * @class Phaser.AnimationManager
  57446. * @constructor
  57447. * @param {Phaser.Sprite} sprite - A reference to the Game Object that owns this AnimationManager.
  57448. */
  57449. Phaser.AnimationManager = function (sprite) {
  57450. /**
  57451. * @property {Phaser.Sprite} sprite - A reference to the parent Sprite that owns this AnimationManager.
  57452. */
  57453. this.sprite = sprite;
  57454. /**
  57455. * @property {Phaser.Game} game - A reference to the currently running Game.
  57456. */
  57457. this.game = sprite.game;
  57458. /**
  57459. * The currently displayed Frame of animation, if any.
  57460. * This property is only set once an Animation starts playing. Until that point it remains set as `null`.
  57461. *
  57462. * @property {Phaser.Frame} currentFrame
  57463. * @default
  57464. */
  57465. this.currentFrame = null;
  57466. /**
  57467. * @property {Phaser.Animation} currentAnim - The currently displayed animation, if any.
  57468. * @default
  57469. */
  57470. this.currentAnim = null;
  57471. /**
  57472. * @property {boolean} updateIfVisible - Update the animation data only while the the sprite is {@link Phaser.Sprite#visible}. Set to `false` to continue updating while the sprite is invisible.
  57473. * @default
  57474. */
  57475. this.updateIfVisible = true;
  57476. /**
  57477. * @property {boolean} isLoaded - Set to true once animation data has been loaded.
  57478. * @default
  57479. */
  57480. this.isLoaded = false;
  57481. /**
  57482. * @property {Phaser.FrameData} _frameData - A temp. var for holding the currently playing Animations FrameData.
  57483. * @private
  57484. * @default
  57485. */
  57486. this._frameData = null;
  57487. /**
  57488. * @property {object} _anims - An internal object that stores all of the Animation instances.
  57489. * @private
  57490. */
  57491. this._anims = {};
  57492. /**
  57493. * @property {object} _outputFrames - An internal object to help avoid gc.
  57494. * @private
  57495. */
  57496. this._outputFrames = [];
  57497. };
  57498. Phaser.AnimationManager.prototype = {
  57499. /**
  57500. * Loads FrameData into the internal temporary vars and resets the frame index to zero.
  57501. * This is called automatically when a new Sprite is created.
  57502. *
  57503. * @method Phaser.AnimationManager#loadFrameData
  57504. * @private
  57505. * @param {Phaser.FrameData} frameData - The FrameData set to load.
  57506. * @param {string|number} frame - The frame to default to.
  57507. * @return {boolean} Returns `true` if the frame data was loaded successfully, otherwise `false`
  57508. */
  57509. loadFrameData: function (frameData, frame) {
  57510. if (frameData === undefined)
  57511. {
  57512. return false;
  57513. }
  57514. if (this.isLoaded)
  57515. {
  57516. // We need to update the frameData that the animations are using
  57517. for (var anim in this._anims)
  57518. {
  57519. this._anims[anim].updateFrameData(frameData);
  57520. }
  57521. }
  57522. this._frameData = frameData;
  57523. if (frame === undefined || frame === null)
  57524. {
  57525. this.frame = 0;
  57526. }
  57527. else
  57528. {
  57529. if (typeof frame === 'string')
  57530. {
  57531. this.frameName = frame;
  57532. }
  57533. else
  57534. {
  57535. this.frame = frame;
  57536. }
  57537. }
  57538. this.isLoaded = true;
  57539. return true;
  57540. },
  57541. /**
  57542. * Loads FrameData into the internal temporary vars and resets the frame index to zero.
  57543. * This is called automatically when a new Sprite is created.
  57544. *
  57545. * @method Phaser.AnimationManager#copyFrameData
  57546. * @private
  57547. * @param {Phaser.FrameData} frameData - The FrameData set to load.
  57548. * @param {string|number} frame - The frame to default to.
  57549. * @return {boolean} Returns `true` if the frame data was loaded successfully, otherwise `false`
  57550. */
  57551. copyFrameData: function (frameData, frame) {
  57552. this._frameData = frameData.clone();
  57553. if (this.isLoaded)
  57554. {
  57555. // We need to update the frameData that the animations are using
  57556. for (var anim in this._anims)
  57557. {
  57558. this._anims[anim].updateFrameData(this._frameData);
  57559. }
  57560. }
  57561. if (frame === undefined || frame === null)
  57562. {
  57563. this.frame = 0;
  57564. }
  57565. else
  57566. {
  57567. if (typeof frame === 'string')
  57568. {
  57569. this.frameName = frame;
  57570. }
  57571. else
  57572. {
  57573. this.frame = frame;
  57574. }
  57575. }
  57576. this.isLoaded = true;
  57577. return true;
  57578. },
  57579. /**
  57580. * Adds a new animation under the given key. Optionally set the frames, frame rate and loop.
  57581. * Animations added in this way are played back with the play function.
  57582. *
  57583. * @method Phaser.AnimationManager#add
  57584. * @param {string} name - The unique (within this Sprite) name for the animation, i.e. "run", "fire", "walk".
  57585. * @param {Array} [frames=null] - An array of numbers/strings that correspond to the frames to add to this animation and in which order. e.g. [1, 2, 3] or ['run0', 'run1', run2]). If null then all frames will be used.
  57586. * @param {number} [frameRate=60] - The speed at which the animation should play. The speed is given in frames per second.
  57587. * @param {boolean} [loop=false] - Whether or not the animation is looped or just plays once.
  57588. * @param {boolean} [useNumericIndex=true] - Are the given frames using numeric indexes (default) or strings?
  57589. * @return {Phaser.Animation} The Animation object that was created.
  57590. */
  57591. add: function (name, frames, frameRate, loop, useNumericIndex) {
  57592. frames = frames || [];
  57593. frameRate = frameRate || 60;
  57594. if (loop === undefined) { loop = false; }
  57595. // If they didn't set the useNumericIndex then let's at least try and guess it
  57596. if (useNumericIndex === undefined)
  57597. {
  57598. if (frames && typeof frames[0] === 'number')
  57599. {
  57600. useNumericIndex = true;
  57601. }
  57602. else
  57603. {
  57604. useNumericIndex = false;
  57605. }
  57606. }
  57607. this._outputFrames = [];
  57608. this._frameData.getFrameIndexes(frames, useNumericIndex, this._outputFrames);
  57609. this._anims[name] = new Phaser.Animation(this.game, this.sprite, name, this._frameData, this._outputFrames, frameRate, loop);
  57610. this.currentAnim = this._anims[name];
  57611. if (this.sprite.tilingTexture)
  57612. {
  57613. this.sprite.refreshTexture = true;
  57614. }
  57615. return this._anims[name];
  57616. },
  57617. /**
  57618. * Check whether the frames in the given array are valid and exist.
  57619. *
  57620. * @method Phaser.AnimationManager#validateFrames
  57621. * @param {Array} frames - An array of frames to be validated.
  57622. * @param {boolean} [useNumericIndex=true] - Validate the frames based on their numeric index (true) or string index (false)
  57623. * @return {boolean} True if all given Frames are valid, otherwise false.
  57624. */
  57625. validateFrames: function (frames, useNumericIndex) {
  57626. if (useNumericIndex === undefined) { useNumericIndex = true; }
  57627. for (var i = 0; i < frames.length; i++)
  57628. {
  57629. if (useNumericIndex === true)
  57630. {
  57631. if (frames[i] > this._frameData.total)
  57632. {
  57633. return false;
  57634. }
  57635. }
  57636. else
  57637. {
  57638. if (this._frameData.checkFrameName(frames[i]) === false)
  57639. {
  57640. return false;
  57641. }
  57642. }
  57643. }
  57644. return true;
  57645. },
  57646. /**
  57647. * Play an animation based on the given key. The animation should previously have been added via `animations.add`
  57648. *
  57649. * If the requested animation is already playing this request will be ignored.
  57650. * If you need to reset an already running animation do so directly on the Animation object itself.
  57651. *
  57652. * If you need to jump to a specific frame of this animation, then call `play` and immediately after it,
  57653. * set the frame you require (i.e. `animation.play(); animation.frame = 4`).
  57654. *
  57655. * @method Phaser.AnimationManager#play
  57656. * @param {string} name - The name of the animation to be played, e.g. "fire", "walk", "jump".
  57657. * @param {number} [frameRate=null] - The framerate to play the animation at. The speed is given in frames per second. If not provided the previously set frameRate of the Animation is used.
  57658. * @param {boolean} [loop=false] - Should the animation be looped after playback. If not provided the previously set loop value of the Animation is used.
  57659. * @param {boolean} [killOnComplete=false] - If set to true when the animation completes (only happens if loop=false) the parent Sprite will be killed.
  57660. * @return {Phaser.Animation} A reference to playing Animation instance.
  57661. */
  57662. play: function (name, frameRate, loop, killOnComplete) {
  57663. if (this._anims[name])
  57664. {
  57665. if (this.currentAnim === this._anims[name])
  57666. {
  57667. if (this.currentAnim.isPlaying === false)
  57668. {
  57669. this.currentAnim.paused = false;
  57670. return this.currentAnim.play(frameRate, loop, killOnComplete);
  57671. }
  57672. return this.currentAnim;
  57673. }
  57674. else
  57675. {
  57676. if (this.currentAnim && this.currentAnim.isPlaying)
  57677. {
  57678. this.currentAnim.stop();
  57679. }
  57680. this.currentAnim = this._anims[name];
  57681. this.currentAnim.paused = false;
  57682. this.currentFrame = this.currentAnim.currentFrame;
  57683. return this.currentAnim.play(frameRate, loop, killOnComplete);
  57684. }
  57685. }
  57686. },
  57687. /**
  57688. * Stop playback of an animation. If a name is given that specific animation is stopped, otherwise the current animation is stopped.
  57689. * The currentAnim property of the AnimationManager is automatically set to the animation given.
  57690. *
  57691. * @method Phaser.AnimationManager#stop
  57692. * @param {string} [name=null] - The name of the animation to be stopped, e.g. "fire". If none is given the currently running animation is stopped.
  57693. * @param {boolean} [resetFrame=false] - When the animation is stopped should the currentFrame be set to the first frame of the animation (true) or paused on the last frame displayed (false)
  57694. */
  57695. stop: function (name, resetFrame) {
  57696. if (resetFrame === undefined) { resetFrame = false; }
  57697. if (this.currentAnim && (typeof name !== 'string' || name === this.currentAnim.name))
  57698. {
  57699. this.currentAnim.stop(resetFrame);
  57700. }
  57701. },
  57702. /**
  57703. * The main update function is called by the Sprites update loop. It's responsible for updating animation frames and firing related events.
  57704. *
  57705. * @method Phaser.AnimationManager#update
  57706. * @protected
  57707. * @return {boolean} True if a new animation frame has been set, otherwise false.
  57708. */
  57709. update: function () {
  57710. if (this.updateIfVisible && !this.sprite.visible)
  57711. {
  57712. return false;
  57713. }
  57714. if (this.currentAnim && this.currentAnim.update())
  57715. {
  57716. this.currentFrame = this.currentAnim.currentFrame;
  57717. return true;
  57718. }
  57719. return false;
  57720. },
  57721. /**
  57722. * Advances by the given number of frames in the current animation, taking the loop value into consideration.
  57723. *
  57724. * @method Phaser.AnimationManager#next
  57725. * @param {number} [quantity=1] - The number of frames to advance.
  57726. */
  57727. next: function (quantity) {
  57728. if (this.currentAnim)
  57729. {
  57730. this.currentAnim.next(quantity);
  57731. this.currentFrame = this.currentAnim.currentFrame;
  57732. }
  57733. },
  57734. /**
  57735. * Moves backwards the given number of frames in the current animation, taking the loop value into consideration.
  57736. *
  57737. * @method Phaser.AnimationManager#previous
  57738. * @param {number} [quantity=1] - The number of frames to move back.
  57739. */
  57740. previous: function (quantity) {
  57741. if (this.currentAnim)
  57742. {
  57743. this.currentAnim.previous(quantity);
  57744. this.currentFrame = this.currentAnim.currentFrame;
  57745. }
  57746. },
  57747. /**
  57748. * Returns an animation that was previously added by name.
  57749. *
  57750. * @method Phaser.AnimationManager#getAnimation
  57751. * @param {string} name - The name of the animation to be returned, e.g. "fire".
  57752. * @return {Phaser.Animation} The Animation instance, if found, otherwise null.
  57753. */
  57754. getAnimation: function (name) {
  57755. if (typeof name === 'string')
  57756. {
  57757. if (this._anims[name])
  57758. {
  57759. return this._anims[name];
  57760. }
  57761. }
  57762. return null;
  57763. },
  57764. /**
  57765. * Refreshes the current frame data back to the parent Sprite and also resets the texture data.
  57766. *
  57767. * @method Phaser.AnimationManager#refreshFrame
  57768. */
  57769. refreshFrame: function () {
  57770. // TODO
  57771. // this.sprite.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
  57772. },
  57773. /**
  57774. * Destroys all references this AnimationManager contains.
  57775. * Iterates through the list of animations stored in this manager and calls destroy on each of them.
  57776. *
  57777. * @method Phaser.AnimationManager#destroy
  57778. */
  57779. destroy: function () {
  57780. var anim = null;
  57781. for (var anim in this._anims)
  57782. {
  57783. if (this._anims.hasOwnProperty(anim))
  57784. {
  57785. this._anims[anim].destroy();
  57786. }
  57787. }
  57788. this._anims = {};
  57789. this._outputFrames = [];
  57790. this._frameData = null;
  57791. this.currentAnim = null;
  57792. this.currentFrame = null;
  57793. this.sprite = null;
  57794. this.game = null;
  57795. }
  57796. };
  57797. Phaser.AnimationManager.prototype.constructor = Phaser.AnimationManager;
  57798. /**
  57799. * @name Phaser.AnimationManager#frameData
  57800. * @property {Phaser.FrameData} frameData - The current animations FrameData.
  57801. * @readonly
  57802. */
  57803. Object.defineProperty(Phaser.AnimationManager.prototype, 'frameData', {
  57804. get: function () {
  57805. return this._frameData;
  57806. }
  57807. });
  57808. /**
  57809. * @name Phaser.AnimationManager#frameTotal
  57810. * @property {number} frameTotal - The total number of frames in the currently loaded FrameData, or -1 if no FrameData is loaded.
  57811. * @readonly
  57812. */
  57813. Object.defineProperty(Phaser.AnimationManager.prototype, 'frameTotal', {
  57814. get: function () {
  57815. return this._frameData.total;
  57816. }
  57817. });
  57818. /**
  57819. * @name Phaser.AnimationManager#paused
  57820. * @property {boolean} paused - Gets and sets the paused state of the current animation.
  57821. */
  57822. Object.defineProperty(Phaser.AnimationManager.prototype, 'paused', {
  57823. get: function () {
  57824. return this.currentAnim.isPaused;
  57825. },
  57826. set: function (value) {
  57827. this.currentAnim.paused = value;
  57828. }
  57829. });
  57830. /**
  57831. * @name Phaser.AnimationManager#name
  57832. * @property {string} name - Gets the current animation name, if set.
  57833. */
  57834. Object.defineProperty(Phaser.AnimationManager.prototype, 'name', {
  57835. get: function () {
  57836. if (this.currentAnim)
  57837. {
  57838. return this.currentAnim.name;
  57839. }
  57840. }
  57841. });
  57842. /**
  57843. * @name Phaser.AnimationManager#frame
  57844. * @property {number} frame - Gets or sets the current frame index and updates the Texture Cache for display.
  57845. */
  57846. Object.defineProperty(Phaser.AnimationManager.prototype, 'frame', {
  57847. get: function () {
  57848. if (this.currentFrame)
  57849. {
  57850. return this.currentFrame.index;
  57851. }
  57852. },
  57853. set: function (value) {
  57854. var gotFrame;
  57855. if (typeof value === 'number' && this._frameData && (gotFrame = this._frameData.getFrame(value)))
  57856. {
  57857. this.currentFrame = gotFrame;
  57858. this.sprite.setFrame(this.currentFrame);
  57859. }
  57860. }
  57861. });
  57862. /**
  57863. * @name Phaser.AnimationManager#frameName
  57864. * @property {string} frameName - Gets or sets the current frame name and updates the Texture Cache for display.
  57865. */
  57866. Object.defineProperty(Phaser.AnimationManager.prototype, 'frameName', {
  57867. get: function () {
  57868. if (this.currentFrame)
  57869. {
  57870. return this.currentFrame.name;
  57871. }
  57872. },
  57873. set: function (value) {
  57874. var gotFrame;
  57875. if (typeof value === 'string' && this._frameData && (gotFrame = this._frameData.getFrameByName(value)))
  57876. {
  57877. this.currentFrame = gotFrame;
  57878. this._frameIndex = this.currentFrame.index;
  57879. this.sprite.setFrame(this.currentFrame);
  57880. }
  57881. else
  57882. {
  57883. console.warn('Cannot set frameName: ' + value);
  57884. }
  57885. }
  57886. });
  57887. /**
  57888. * @author Richard Davey <rich@photonstorm.com>
  57889. * @copyright 2016 Photon Storm Ltd.
  57890. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  57891. */
  57892. /**
  57893. * An Animation instance contains a single animation and the controls to play it.
  57894. *
  57895. * It is created by the AnimationManager, consists of Animation.Frame objects and belongs to a single Game Object such as a Sprite.
  57896. *
  57897. * @class Phaser.Animation
  57898. * @constructor
  57899. * @param {Phaser.Game} game - A reference to the currently running game.
  57900. * @param {Phaser.Sprite} parent - A reference to the owner of this Animation.
  57901. * @param {string} name - The unique name for this animation, used in playback commands.
  57902. * @param {Phaser.FrameData} frameData - The FrameData object that contains all frames used by this Animation.
  57903. * @param {number[]|string[]} frames - An array of numbers or strings indicating which frames to play in which order.
  57904. * @param {number} [frameRate=60] - The speed at which the animation should play. The speed is given in frames per second.
  57905. * @param {boolean} [loop=false] - Whether or not the animation is looped or just plays once.
  57906. */
  57907. Phaser.Animation = function (game, parent, name, frameData, frames, frameRate, loop) {
  57908. if (loop === undefined) { loop = false; }
  57909. /**
  57910. * @property {Phaser.Game} game - A reference to the currently running Game.
  57911. */
  57912. this.game = game;
  57913. /**
  57914. * @property {Phaser.Sprite} _parent - A reference to the parent Sprite that owns this Animation.
  57915. * @private
  57916. */
  57917. this._parent = parent;
  57918. /**
  57919. * @property {Phaser.FrameData} _frameData - The FrameData the Animation uses.
  57920. * @private
  57921. */
  57922. this._frameData = frameData;
  57923. /**
  57924. * @property {string} name - The user defined name given to this Animation.
  57925. */
  57926. this.name = name;
  57927. /**
  57928. * @property {array} _frames
  57929. * @private
  57930. */
  57931. this._frames = [];
  57932. this._frames = this._frames.concat(frames);
  57933. /**
  57934. * @property {number} delay - The delay in ms between each frame of the Animation, based on the given frameRate.
  57935. */
  57936. this.delay = 1000 / frameRate;
  57937. /**
  57938. * @property {boolean} loop - The loop state of the Animation.
  57939. */
  57940. this.loop = loop;
  57941. /**
  57942. * @property {number} loopCount - The number of times the animation has looped since it was last started.
  57943. */
  57944. this.loopCount = 0;
  57945. /**
  57946. * @property {boolean} killOnComplete - Should the parent of this Animation be killed when the animation completes?
  57947. * @default
  57948. */
  57949. this.killOnComplete = false;
  57950. /**
  57951. * @property {boolean} isFinished - The finished state of the Animation. Set to true once playback completes, false during playback.
  57952. * @default
  57953. */
  57954. this.isFinished = false;
  57955. /**
  57956. * @property {boolean} isPlaying - The playing state of the Animation. Set to false once playback completes, true during playback.
  57957. * @default
  57958. */
  57959. this.isPlaying = false;
  57960. /**
  57961. * @property {boolean} isPaused - The paused state of the Animation.
  57962. * @default
  57963. */
  57964. this.isPaused = false;
  57965. /**
  57966. * @property {boolean} _pauseStartTime - The time the animation paused.
  57967. * @private
  57968. * @default
  57969. */
  57970. this._pauseStartTime = 0;
  57971. /**
  57972. * @property {number} _frameIndex
  57973. * @private
  57974. * @default
  57975. */
  57976. this._frameIndex = 0;
  57977. /**
  57978. * @property {number} _frameDiff
  57979. * @private
  57980. * @default
  57981. */
  57982. this._frameDiff = 0;
  57983. /**
  57984. * @property {number} _frameSkip
  57985. * @private
  57986. * @default
  57987. */
  57988. this._frameSkip = 1;
  57989. /**
  57990. * @property {Phaser.Frame} currentFrame - The currently displayed frame of the Animation.
  57991. */
  57992. this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
  57993. /**
  57994. * @property {Phaser.Signal} onStart - This event is dispatched when this Animation starts playback.
  57995. */
  57996. this.onStart = new Phaser.Signal();
  57997. /**
  57998. * This event is dispatched when the Animation changes frame.
  57999. * By default this event is disabled due to its intensive nature. Enable it with: `Animation.enableUpdate = true`.
  58000. * Note that the event is only dispatched with the current frame. In a low-FPS environment Animations
  58001. * will automatically frame-skip to try and claw back time, so do not base your code on expecting to
  58002. * receive a perfectly sequential set of frames from this event.
  58003. * @property {Phaser.Signal|null} onUpdate
  58004. * @default
  58005. */
  58006. this.onUpdate = null;
  58007. /**
  58008. * @property {Phaser.Signal} onComplete - This event is dispatched when this Animation completes playback. If the animation is set to loop this is never fired, listen for onLoop instead.
  58009. */
  58010. this.onComplete = new Phaser.Signal();
  58011. /**
  58012. * @property {Phaser.Signal} onLoop - This event is dispatched when this Animation loops.
  58013. */
  58014. this.onLoop = new Phaser.Signal();
  58015. /**
  58016. * @property {boolean} isReversed - Indicates if the animation will play backwards.
  58017. * @default
  58018. */
  58019. this.isReversed = false;
  58020. // Set-up some event listeners
  58021. this.game.onPause.add(this.onPause, this);
  58022. this.game.onResume.add(this.onResume, this);
  58023. };
  58024. Phaser.Animation.prototype = {
  58025. /**
  58026. * Plays this animation.
  58027. *
  58028. * If you need to jump to a specific frame of this animation, then call `play` and immediately after it,
  58029. * set the frame you require (i.e. `animation.play(); animation.frame = 4`).
  58030. *
  58031. * @method Phaser.Animation#play
  58032. * @param {number} [frameRate=null] - The framerate to play the animation at. The speed is given in frames per second. If not provided the previously set frameRate of the Animation is used.
  58033. * @param {boolean} [loop=false] - Should the animation be looped after playback. If not provided the previously set loop value of the Animation is used.
  58034. * @param {boolean} [killOnComplete=false] - If set to true when the animation completes (only happens if loop=false) the parent Sprite will be killed.
  58035. * @return {Phaser.Animation} - A reference to this Animation instance.
  58036. */
  58037. play: function (frameRate, loop, killOnComplete) {
  58038. if (typeof frameRate === 'number')
  58039. {
  58040. // If they set a new frame rate then use it, otherwise use the one set on creation
  58041. this.delay = 1000 / frameRate;
  58042. }
  58043. if (typeof loop === 'boolean')
  58044. {
  58045. // If they set a new loop value then use it, otherwise use the one set on creation
  58046. this.loop = loop;
  58047. }
  58048. if (typeof killOnComplete !== 'undefined')
  58049. {
  58050. // Remove the parent sprite once the animation has finished?
  58051. this.killOnComplete = killOnComplete;
  58052. }
  58053. this.isPlaying = true;
  58054. this.isFinished = false;
  58055. this.paused = false;
  58056. this.loopCount = 0;
  58057. this._timeLastFrame = this.game.time.time;
  58058. this._timeNextFrame = this.game.time.time + this.delay;
  58059. this._frameIndex = this.isReversed ? this._frames.length - 1 : 0;
  58060. this.updateCurrentFrame(false, true);
  58061. this._parent.events.onAnimationStart$dispatch(this._parent, this);
  58062. this.onStart.dispatch(this._parent, this);
  58063. this._parent.animations.currentAnim = this;
  58064. this._parent.animations.currentFrame = this.currentFrame;
  58065. return this;
  58066. },
  58067. /**
  58068. * Sets this animation back to the first frame and restarts the animation.
  58069. *
  58070. * @method Phaser.Animation#restart
  58071. */
  58072. restart: function () {
  58073. this.isPlaying = true;
  58074. this.isFinished = false;
  58075. this.paused = false;
  58076. this.loopCount = 0;
  58077. this._timeLastFrame = this.game.time.time;
  58078. this._timeNextFrame = this.game.time.time + this.delay;
  58079. this._frameIndex = 0;
  58080. this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
  58081. this._parent.setFrame(this.currentFrame);
  58082. this._parent.animations.currentAnim = this;
  58083. this._parent.animations.currentFrame = this.currentFrame;
  58084. this.onStart.dispatch(this._parent, this);
  58085. },
  58086. /**
  58087. * Reverses the animation direction.
  58088. *
  58089. * @method Phaser.Animation#reverse
  58090. * @return {Phaser.Animation} The animation instance.
  58091. */
  58092. reverse: function () {
  58093. this.reversed = !this.reversed;
  58094. return this;
  58095. },
  58096. /**
  58097. * Reverses the animation direction for the current/next animation only
  58098. * Once the onComplete event is called this method will be called again and revert
  58099. * the reversed state.
  58100. *
  58101. * @method Phaser.Animation#reverseOnce
  58102. * @return {Phaser.Animation} The animation instance.
  58103. */
  58104. reverseOnce: function () {
  58105. this.onComplete.addOnce(this.reverse, this);
  58106. return this.reverse();
  58107. },
  58108. /**
  58109. * Sets this animations playback to a given frame with the given ID.
  58110. *
  58111. * @method Phaser.Animation#setFrame
  58112. * @param {string|number} [frameId] - The identifier of the frame to set. Can be the name of the frame, the sprite index of the frame, or the animation-local frame index.
  58113. * @param {boolean} [useLocalFrameIndex=false] - If you provide a number for frameId, should it use the numeric indexes of the frameData, or the 0-indexed frame index local to the animation.
  58114. */
  58115. setFrame: function(frameId, useLocalFrameIndex) {
  58116. var frameIndex;
  58117. if (useLocalFrameIndex === undefined)
  58118. {
  58119. useLocalFrameIndex = false;
  58120. }
  58121. // Find the index to the desired frame.
  58122. if (typeof frameId === "string")
  58123. {
  58124. for (var i = 0; i < this._frames.length; i++)
  58125. {
  58126. if (this._frameData.getFrame(this._frames[i]).name === frameId)
  58127. {
  58128. frameIndex = i;
  58129. }
  58130. }
  58131. }
  58132. else if (typeof frameId === "number")
  58133. {
  58134. if (useLocalFrameIndex)
  58135. {
  58136. frameIndex = frameId;
  58137. }
  58138. else
  58139. {
  58140. for (var i = 0; i < this._frames.length; i++)
  58141. {
  58142. if (this._frames[i] === frameId)
  58143. {
  58144. frameIndex = i;
  58145. }
  58146. }
  58147. }
  58148. }
  58149. if (frameIndex)
  58150. {
  58151. // Set the current frame index to the found index. Subtract a directional offset so that it animates to the desired frame on update.
  58152. var directionalOffset = this.isReversed ? -1 : 1;
  58153. this._frameIndex = frameIndex - directionalOffset;
  58154. // Make the animation update at next update
  58155. this._timeNextFrame = this.game.time.time;
  58156. this.update();
  58157. }
  58158. },
  58159. /**
  58160. * Stops playback of this animation and set it to a finished state. If a resetFrame is provided it will stop playback and set frame to the first in the animation.
  58161. * If `dispatchComplete` is true it will dispatch the complete events, otherwise they'll be ignored.
  58162. *
  58163. * @method Phaser.Animation#stop
  58164. * @param {boolean} [resetFrame=false] - If true after the animation stops the currentFrame value will be set to the first frame in this animation.
  58165. * @param {boolean} [dispatchComplete=false] - Dispatch the Animation.onComplete and parent.onAnimationComplete events?
  58166. */
  58167. stop: function (resetFrame, dispatchComplete) {
  58168. if (resetFrame === undefined) { resetFrame = false; }
  58169. if (dispatchComplete === undefined) { dispatchComplete = false; }
  58170. this.isPlaying = false;
  58171. this.isFinished = true;
  58172. this.paused = false;
  58173. if (resetFrame)
  58174. {
  58175. this.currentFrame = this._frameData.getFrame(this._frames[0]);
  58176. this._parent.setFrame(this.currentFrame);
  58177. }
  58178. if (dispatchComplete)
  58179. {
  58180. this._parent.events.onAnimationComplete$dispatch(this._parent, this);
  58181. this.onComplete.dispatch(this._parent, this);
  58182. }
  58183. },
  58184. /**
  58185. * Called when the Game enters a paused state.
  58186. *
  58187. * @method Phaser.Animation#onPause
  58188. */
  58189. onPause: function () {
  58190. if (this.isPlaying)
  58191. {
  58192. this._frameDiff = this._timeNextFrame - this.game.time.time;
  58193. }
  58194. },
  58195. /**
  58196. * Called when the Game resumes from a paused state.
  58197. *
  58198. * @method Phaser.Animation#onResume
  58199. */
  58200. onResume: function () {
  58201. if (this.isPlaying)
  58202. {
  58203. this._timeNextFrame = this.game.time.time + this._frameDiff;
  58204. }
  58205. },
  58206. /**
  58207. * Updates this animation. Called automatically by the AnimationManager.
  58208. *
  58209. * @method Phaser.Animation#update
  58210. */
  58211. update: function () {
  58212. if (this.isPaused)
  58213. {
  58214. return false;
  58215. }
  58216. if (this.isPlaying && this.game.time.time >= this._timeNextFrame)
  58217. {
  58218. this._frameSkip = 1;
  58219. // Lagging?
  58220. this._frameDiff = this.game.time.time - this._timeNextFrame;
  58221. this._timeLastFrame = this.game.time.time;
  58222. if (this._frameDiff > this.delay)
  58223. {
  58224. // We need to skip a frame, work out how many
  58225. this._frameSkip = Math.floor(this._frameDiff / this.delay);
  58226. this._frameDiff -= (this._frameSkip * this.delay);
  58227. }
  58228. else
  58229. {
  58230. this._frameDiff = 0;
  58231. }
  58232. // And what's left now?
  58233. this._timeNextFrame = this.game.time.time + (this.delay - this._frameDiff);
  58234. if (this.isReversed)
  58235. {
  58236. this._frameIndex -= this._frameSkip;
  58237. }
  58238. else
  58239. {
  58240. this._frameIndex += this._frameSkip;
  58241. }
  58242. if (!this.isReversed && this._frameIndex >= this._frames.length || this.isReversed && this._frameIndex <= -1)
  58243. {
  58244. if (this.loop)
  58245. {
  58246. // Update current state before event callback
  58247. this._frameIndex = Math.abs(this._frameIndex) % this._frames.length;
  58248. if (this.isReversed)
  58249. {
  58250. this._frameIndex = this._frames.length - 1 - this._frameIndex;
  58251. }
  58252. this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
  58253. // Instead of calling updateCurrentFrame we do it here instead
  58254. if (this.currentFrame)
  58255. {
  58256. this._parent.setFrame(this.currentFrame);
  58257. }
  58258. this.loopCount++;
  58259. this._parent.events.onAnimationLoop$dispatch(this._parent, this);
  58260. this.onLoop.dispatch(this._parent, this);
  58261. if (this.onUpdate)
  58262. {
  58263. this.onUpdate.dispatch(this, this.currentFrame);
  58264. // False if the animation was destroyed from within a callback
  58265. return !!this._frameData;
  58266. }
  58267. else
  58268. {
  58269. return true;
  58270. }
  58271. }
  58272. else
  58273. {
  58274. this.complete();
  58275. return false;
  58276. }
  58277. }
  58278. else
  58279. {
  58280. return this.updateCurrentFrame(true);
  58281. }
  58282. }
  58283. return false;
  58284. },
  58285. /**
  58286. * Changes the currentFrame per the _frameIndex, updates the display state,
  58287. * and triggers the update signal.
  58288. *
  58289. * Returns true if the current frame update was 'successful', false otherwise.
  58290. *
  58291. * @method Phaser.Animation#updateCurrentFrame
  58292. * @private
  58293. * @param {boolean} signalUpdate - If true the `Animation.onUpdate` signal will be dispatched.
  58294. * @param {boolean} fromPlay - Was this call made from the playing of a new animation?
  58295. * @return {boolean} True if the current frame was updated, otherwise false.
  58296. */
  58297. updateCurrentFrame: function (signalUpdate, fromPlay) {
  58298. if (fromPlay === undefined) { fromPlay = false; }
  58299. if (!this._frameData)
  58300. {
  58301. // The animation is already destroyed, probably from a callback
  58302. return false;
  58303. }
  58304. // Previous index
  58305. var idx = this.currentFrame.index;
  58306. this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
  58307. if (this.currentFrame && (fromPlay || (!fromPlay && idx !== this.currentFrame.index)))
  58308. {
  58309. this._parent.setFrame(this.currentFrame);
  58310. }
  58311. if (this.onUpdate && signalUpdate)
  58312. {
  58313. this.onUpdate.dispatch(this, this.currentFrame);
  58314. // False if the animation was destroyed from within a callback
  58315. return !!this._frameData;
  58316. }
  58317. else
  58318. {
  58319. return true;
  58320. }
  58321. },
  58322. /**
  58323. * Advances by the given number of frames in the Animation, taking the loop value into consideration.
  58324. *
  58325. * @method Phaser.Animation#next
  58326. * @param {number} [quantity=1] - The number of frames to advance.
  58327. */
  58328. next: function (quantity) {
  58329. if (quantity === undefined) { quantity = 1; }
  58330. var frame = this._frameIndex + quantity;
  58331. if (frame >= this._frames.length)
  58332. {
  58333. if (this.loop)
  58334. {
  58335. frame %= this._frames.length;
  58336. }
  58337. else
  58338. {
  58339. frame = this._frames.length - 1;
  58340. }
  58341. }
  58342. if (frame !== this._frameIndex)
  58343. {
  58344. this._frameIndex = frame;
  58345. this.updateCurrentFrame(true);
  58346. }
  58347. },
  58348. /**
  58349. * Moves backwards the given number of frames in the Animation, taking the loop value into consideration.
  58350. *
  58351. * @method Phaser.Animation#previous
  58352. * @param {number} [quantity=1] - The number of frames to move back.
  58353. */
  58354. previous: function (quantity) {
  58355. if (quantity === undefined) { quantity = 1; }
  58356. var frame = this._frameIndex - quantity;
  58357. if (frame < 0)
  58358. {
  58359. if (this.loop)
  58360. {
  58361. frame = this._frames.length + frame;
  58362. }
  58363. else
  58364. {
  58365. frame++;
  58366. }
  58367. }
  58368. if (frame !== this._frameIndex)
  58369. {
  58370. this._frameIndex = frame;
  58371. this.updateCurrentFrame(true);
  58372. }
  58373. },
  58374. /**
  58375. * Changes the FrameData object this Animation is using.
  58376. *
  58377. * @method Phaser.Animation#updateFrameData
  58378. * @param {Phaser.FrameData} frameData - The FrameData object that contains all frames used by this Animation.
  58379. */
  58380. updateFrameData: function (frameData) {
  58381. this._frameData = frameData;
  58382. this.currentFrame = this._frameData ? this._frameData.getFrame(this._frames[this._frameIndex % this._frames.length]) : null;
  58383. },
  58384. /**
  58385. * Cleans up this animation ready for deletion. Nulls all values and references.
  58386. *
  58387. * @method Phaser.Animation#destroy
  58388. */
  58389. destroy: function () {
  58390. if (!this._frameData)
  58391. {
  58392. // Already destroyed
  58393. return;
  58394. }
  58395. this.game.onPause.remove(this.onPause, this);
  58396. this.game.onResume.remove(this.onResume, this);
  58397. this.game = null;
  58398. this._parent = null;
  58399. this._frames = null;
  58400. this._frameData = null;
  58401. this.currentFrame = null;
  58402. this.isPlaying = false;
  58403. this.onStart.dispose();
  58404. this.onLoop.dispose();
  58405. this.onComplete.dispose();
  58406. if (this.onUpdate)
  58407. {
  58408. this.onUpdate.dispose();
  58409. }
  58410. },
  58411. /**
  58412. * Called internally when the animation finishes playback.
  58413. * Sets the isPlaying and isFinished states and dispatches the onAnimationComplete event if it exists on the parent and local onComplete event.
  58414. *
  58415. * @method Phaser.Animation#complete
  58416. */
  58417. complete: function () {
  58418. this._frameIndex = this._frames.length - 1;
  58419. this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
  58420. this.isPlaying = false;
  58421. this.isFinished = true;
  58422. this.paused = false;
  58423. this._parent.events.onAnimationComplete$dispatch(this._parent, this);
  58424. this.onComplete.dispatch(this._parent, this);
  58425. if (this.killOnComplete)
  58426. {
  58427. this._parent.kill();
  58428. }
  58429. }
  58430. };
  58431. Phaser.Animation.prototype.constructor = Phaser.Animation;
  58432. /**
  58433. * @name Phaser.Animation#paused
  58434. * @property {boolean} paused - Gets and sets the paused state of this Animation.
  58435. */
  58436. Object.defineProperty(Phaser.Animation.prototype, 'paused', {
  58437. get: function () {
  58438. return this.isPaused;
  58439. },
  58440. set: function (value) {
  58441. this.isPaused = value;
  58442. if (value)
  58443. {
  58444. // Paused
  58445. this._pauseStartTime = this.game.time.time;
  58446. }
  58447. else
  58448. {
  58449. // Un-paused
  58450. if (this.isPlaying)
  58451. {
  58452. this._timeNextFrame = this.game.time.time + this.delay;
  58453. }
  58454. }
  58455. }
  58456. });
  58457. /**
  58458. * @name Phaser.Animation#reversed
  58459. * @property {boolean} reversed - Gets and sets the isReversed state of this Animation.
  58460. */
  58461. Object.defineProperty(Phaser.Animation.prototype, 'reversed', {
  58462. get: function () {
  58463. return this.isReversed;
  58464. },
  58465. set: function (value) {
  58466. this.isReversed = value;
  58467. }
  58468. });
  58469. /**
  58470. * @name Phaser.Animation#frameTotal
  58471. * @property {number} frameTotal - The total number of frames in the currently loaded FrameData, or -1 if no FrameData is loaded.
  58472. * @readonly
  58473. */
  58474. Object.defineProperty(Phaser.Animation.prototype, 'frameTotal', {
  58475. get: function () {
  58476. return this._frames.length;
  58477. }
  58478. });
  58479. /**
  58480. * @name Phaser.Animation#frame
  58481. * @property {number} frame - Gets or sets the current frame index and updates the Texture Cache for display.
  58482. */
  58483. Object.defineProperty(Phaser.Animation.prototype, 'frame', {
  58484. get: function () {
  58485. if (this.currentFrame !== null)
  58486. {
  58487. return this.currentFrame.index;
  58488. }
  58489. else
  58490. {
  58491. return this._frameIndex;
  58492. }
  58493. },
  58494. set: function (value) {
  58495. this.currentFrame = this._frameData.getFrame(this._frames[value]);
  58496. if (this.currentFrame !== null)
  58497. {
  58498. this._frameIndex = value;
  58499. this._parent.setFrame(this.currentFrame);
  58500. if (this.onUpdate)
  58501. {
  58502. this.onUpdate.dispatch(this, this.currentFrame);
  58503. }
  58504. }
  58505. }
  58506. });
  58507. /**
  58508. * @name Phaser.Animation#speed
  58509. * @property {number} speed - Gets or sets the current speed of the animation in frames per second. Changing this in a playing animation will take effect from the next frame. Value must be greater than 0.
  58510. */
  58511. Object.defineProperty(Phaser.Animation.prototype, 'speed', {
  58512. get: function () {
  58513. return 1000 / this.delay;
  58514. },
  58515. set: function (value) {
  58516. if (value > 0)
  58517. {
  58518. this.delay = 1000 / value;
  58519. }
  58520. }
  58521. });
  58522. /**
  58523. * @name Phaser.Animation#enableUpdate
  58524. * @property {boolean} enableUpdate - Gets or sets if this animation will dispatch the onUpdate events upon changing frame.
  58525. */
  58526. Object.defineProperty(Phaser.Animation.prototype, 'enableUpdate', {
  58527. get: function () {
  58528. return (this.onUpdate !== null);
  58529. },
  58530. set: function (value) {
  58531. if (value && this.onUpdate === null)
  58532. {
  58533. this.onUpdate = new Phaser.Signal();
  58534. }
  58535. else if (!value && this.onUpdate !== null)
  58536. {
  58537. this.onUpdate.dispose();
  58538. this.onUpdate = null;
  58539. }
  58540. }
  58541. });
  58542. /**
  58543. * Really handy function for when you are creating arrays of animation data but it's using frame names and not numbers.
  58544. * For example imagine you've got 30 frames named: 'explosion_0001-large' to 'explosion_0030-large'
  58545. * You could use this function to generate those by doing: Phaser.Animation.generateFrameNames('explosion_', 1, 30, '-large', 4);
  58546. *
  58547. * @method Phaser.Animation.generateFrameNames
  58548. * @static
  58549. * @param {string} prefix - The start of the filename. If the filename was 'explosion_0001-large' the prefix would be 'explosion_'.
  58550. * @param {number} start - The number to start sequentially counting from. If your frames are named 'explosion_0001' to 'explosion_0034' the start is 1.
  58551. * @param {number} stop - The number to count to. If your frames are named 'explosion_0001' to 'explosion_0034' the stop value is 34.
  58552. * @param {string} [suffix=''] - The end of the filename. If the filename was 'explosion_0001-large' the prefix would be '-large'.
  58553. * @param {number} [zeroPad=0] - The number of zeros to pad the min and max values with. If your frames are named 'explosion_0001' to 'explosion_0034' then the zeroPad is 4.
  58554. * @return {string[]} An array of framenames.
  58555. */
  58556. Phaser.Animation.generateFrameNames = function (prefix, start, stop, suffix, zeroPad) {
  58557. if (suffix === undefined) { suffix = ''; }
  58558. var output = [];
  58559. var frame = '';
  58560. if (start < stop)
  58561. {
  58562. for (var i = start; i <= stop; i++)
  58563. {
  58564. if (typeof zeroPad === 'number')
  58565. {
  58566. // str, len, pad, dir
  58567. frame = Phaser.Utils.pad(i.toString(), zeroPad, '0', 1);
  58568. }
  58569. else
  58570. {
  58571. frame = i.toString();
  58572. }
  58573. frame = prefix + frame + suffix;
  58574. output.push(frame);
  58575. }
  58576. }
  58577. else
  58578. {
  58579. for (var i = start; i >= stop; i--)
  58580. {
  58581. if (typeof zeroPad === 'number')
  58582. {
  58583. // str, len, pad, dir
  58584. frame = Phaser.Utils.pad(i.toString(), zeroPad, '0', 1);
  58585. }
  58586. else
  58587. {
  58588. frame = i.toString();
  58589. }
  58590. frame = prefix + frame + suffix;
  58591. output.push(frame);
  58592. }
  58593. }
  58594. return output;
  58595. };
  58596. /**
  58597. * @author Richard Davey <rich@photonstorm.com>
  58598. * @copyright 2016 Photon Storm Ltd.
  58599. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  58600. */
  58601. /**
  58602. * A Frame is a single frame of an animation and is part of a FrameData collection.
  58603. *
  58604. * @class Phaser.Frame
  58605. * @constructor
  58606. * @param {number} index - The index of this Frame within the FrameData set it is being added to.
  58607. * @param {number} x - X position of the frame within the texture image.
  58608. * @param {number} y - Y position of the frame within the texture image.
  58609. * @param {number} width - Width of the frame within the texture image.
  58610. * @param {number} height - Height of the frame within the texture image.
  58611. * @param {string} name - The name of the frame. In Texture Atlas data this is usually set to the filename.
  58612. */
  58613. Phaser.Frame = function (index, x, y, width, height, name) {
  58614. /**
  58615. * @property {number} index - The index of this Frame within the FrameData set it is being added to.
  58616. */
  58617. this.index = index;
  58618. /**
  58619. * @property {number} x - X position within the image to cut from.
  58620. */
  58621. this.x = x;
  58622. /**
  58623. * @property {number} y - Y position within the image to cut from.
  58624. */
  58625. this.y = y;
  58626. /**
  58627. * @property {number} width - Width of the frame.
  58628. */
  58629. this.width = width;
  58630. /**
  58631. * @property {number} height - Height of the frame.
  58632. */
  58633. this.height = height;
  58634. if (this.width === 0 || this.height === 0)
  58635. {
  58636. console.warn('Phaser.Frame: Frame "' + this.name + '" has a width or height of zero');
  58637. }
  58638. /**
  58639. * @property {string} name - Useful for Texture Atlas files (is set to the filename value).
  58640. */
  58641. this.name = name;
  58642. /**
  58643. * @property {number} centerX - Center X position within the image to cut from.
  58644. */
  58645. this.centerX = Math.floor(width / 2);
  58646. /**
  58647. * @property {number} centerY - Center Y position within the image to cut from.
  58648. */
  58649. this.centerY = Math.floor(height / 2);
  58650. /**
  58651. * @property {number} distance - The distance from the top left to the bottom-right of this Frame.
  58652. */
  58653. this.distance = Phaser.Math.distance(0, 0, width, height);
  58654. /**
  58655. * @property {boolean} rotated - Is the frame rotated in the source texture?
  58656. * @default
  58657. */
  58658. this.rotated = false;
  58659. /**
  58660. * @property {boolean} trimmed - Was it trimmed when packed?
  58661. * @default
  58662. */
  58663. this.trimmed = false;
  58664. /**
  58665. * @property {number} sourceSizeW - Width of the original sprite before it was trimmed.
  58666. */
  58667. this.sourceSizeW = width;
  58668. /**
  58669. * @property {number} sourceSizeH - Height of the original sprite before it was trimmed.
  58670. */
  58671. this.sourceSizeH = height;
  58672. /**
  58673. * @property {number} spriteSourceSizeX - X position of the trimmed sprite inside original sprite.
  58674. * @default
  58675. */
  58676. this.spriteSourceSizeX = 0;
  58677. /**
  58678. * @property {number} spriteSourceSizeY - Y position of the trimmed sprite inside original sprite.
  58679. * @default
  58680. */
  58681. this.spriteSourceSizeY = 0;
  58682. /**
  58683. * @property {number} spriteSourceSizeW - Width of the trimmed sprite.
  58684. * @default
  58685. */
  58686. this.spriteSourceSizeW = 0;
  58687. /**
  58688. * @property {number} spriteSourceSizeH - Height of the trimmed sprite.
  58689. * @default
  58690. */
  58691. this.spriteSourceSizeH = 0;
  58692. /**
  58693. * @property {number} right - The right of the Frame (x + width).
  58694. */
  58695. this.right = this.x + this.width;
  58696. /**
  58697. * @property {number} bottom - The bottom of the frame (y + height).
  58698. */
  58699. this.bottom = this.y + this.height;
  58700. };
  58701. Phaser.Frame.prototype = {
  58702. /**
  58703. * Adjusts of all the Frame properties based on the given width and height values.
  58704. *
  58705. * @method Phaser.Frame#resize
  58706. * @param {integer} width - The new width of the Frame.
  58707. * @param {integer} height - The new height of the Frame.
  58708. */
  58709. resize: function (width, height) {
  58710. this.width = width;
  58711. this.height = height;
  58712. this.centerX = Math.floor(width / 2);
  58713. this.centerY = Math.floor(height / 2);
  58714. this.distance = Phaser.Math.distance(0, 0, width, height);
  58715. this.sourceSizeW = width;
  58716. this.sourceSizeH = height;
  58717. this.right = this.x + width;
  58718. this.bottom = this.y + height;
  58719. },
  58720. /**
  58721. * If the frame was trimmed when added to the Texture Atlas this records the trim and source data.
  58722. *
  58723. * @method Phaser.Frame#setTrim
  58724. * @param {boolean} trimmed - If this frame was trimmed or not.
  58725. * @param {number} actualWidth - The width of the frame before being trimmed.
  58726. * @param {number} actualHeight - The height of the frame before being trimmed.
  58727. * @param {number} destX - The destination X position of the trimmed frame for display.
  58728. * @param {number} destY - The destination Y position of the trimmed frame for display.
  58729. * @param {number} destWidth - The destination width of the trimmed frame for display.
  58730. * @param {number} destHeight - The destination height of the trimmed frame for display.
  58731. */
  58732. setTrim: function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) {
  58733. this.trimmed = trimmed;
  58734. if (trimmed)
  58735. {
  58736. this.sourceSizeW = actualWidth;
  58737. this.sourceSizeH = actualHeight;
  58738. this.centerX = Math.floor(actualWidth / 2);
  58739. this.centerY = Math.floor(actualHeight / 2);
  58740. this.spriteSourceSizeX = destX;
  58741. this.spriteSourceSizeY = destY;
  58742. this.spriteSourceSizeW = destWidth;
  58743. this.spriteSourceSizeH = destHeight;
  58744. }
  58745. },
  58746. /**
  58747. * Clones this Frame into a new Phaser.Frame object and returns it.
  58748. * Note that all properties are cloned, including the name and index.
  58749. *
  58750. * @method Phaser.Frame#clone
  58751. * @return {Phaser.Frame} An exact copy of this Frame object.
  58752. */
  58753. clone: function () {
  58754. var output = new Phaser.Frame(this.index, this.x, this.y, this.width, this.height, this.name);
  58755. for (var prop in this)
  58756. {
  58757. if (this.hasOwnProperty(prop))
  58758. {
  58759. output[prop] = this[prop];
  58760. }
  58761. }
  58762. return output;
  58763. },
  58764. /**
  58765. * Returns a Rectangle set to the dimensions of this Frame.
  58766. *
  58767. * @method Phaser.Frame#getRect
  58768. * @param {Phaser.Rectangle} [out] - A rectangle to copy the frame dimensions to.
  58769. * @return {Phaser.Rectangle} A rectangle.
  58770. */
  58771. getRect: function (out) {
  58772. if (out === undefined)
  58773. {
  58774. out = new Phaser.Rectangle(this.x, this.y, this.width, this.height);
  58775. }
  58776. else
  58777. {
  58778. out.setTo(this.x, this.y, this.width, this.height);
  58779. }
  58780. return out;
  58781. }
  58782. };
  58783. Phaser.Frame.prototype.constructor = Phaser.Frame;
  58784. /**
  58785. * @author Richard Davey <rich@photonstorm.com>
  58786. * @copyright 2016 Photon Storm Ltd.
  58787. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  58788. */
  58789. /**
  58790. * FrameData is a container for Frame objects, which are the internal representation of animation data in Phaser.
  58791. *
  58792. * @class Phaser.FrameData
  58793. * @constructor
  58794. */
  58795. Phaser.FrameData = function () {
  58796. /**
  58797. * @property {Array} _frames - Local array of frames.
  58798. * @private
  58799. */
  58800. this._frames = [];
  58801. /**
  58802. * @property {Array} _frameNames - Local array of frame names for name to index conversions.
  58803. * @private
  58804. */
  58805. this._frameNames = [];
  58806. };
  58807. Phaser.FrameData.prototype = {
  58808. /**
  58809. * Adds a new Frame to this FrameData collection. Typically called by the Animation.Parser and not directly.
  58810. *
  58811. * @method Phaser.FrameData#addFrame
  58812. * @param {Phaser.Frame} frame - The frame to add to this FrameData set.
  58813. * @return {Phaser.Frame} The frame that was just added.
  58814. */
  58815. addFrame: function (frame) {
  58816. frame.index = this._frames.length;
  58817. this._frames.push(frame);
  58818. if (frame.name !== '')
  58819. {
  58820. this._frameNames[frame.name] = frame.index;
  58821. }
  58822. return frame;
  58823. },
  58824. /**
  58825. * Get a Frame by its numerical index.
  58826. *
  58827. * @method Phaser.FrameData#getFrame
  58828. * @param {number} index - The index of the frame you want to get.
  58829. * @return {Phaser.Frame} The frame, if found, or undefined.
  58830. */
  58831. getFrame: function (index) {
  58832. if (index >= this._frames.length)
  58833. {
  58834. index = 0;
  58835. }
  58836. return this._frames[index];
  58837. },
  58838. /**
  58839. * Get a Frame by its frame name.
  58840. *
  58841. * @method Phaser.FrameData#getFrameByName
  58842. * @param {string} name - The name of the frame you want to get.
  58843. * @return {Phaser.Frame} The frame, if found, or null.
  58844. */
  58845. getFrameByName: function (name) {
  58846. if (typeof this._frameNames[name] === 'number')
  58847. {
  58848. return this._frames[this._frameNames[name]];
  58849. }
  58850. return null;
  58851. },
  58852. /**
  58853. * Check if there is a Frame with the given name.
  58854. *
  58855. * @method Phaser.FrameData#checkFrameName
  58856. * @param {string} name - The name of the frame you want to check.
  58857. * @return {boolean} True if the frame is found, otherwise false.
  58858. */
  58859. checkFrameName: function (name) {
  58860. if (this._frameNames[name] == null)
  58861. {
  58862. return false;
  58863. }
  58864. return true;
  58865. },
  58866. /**
  58867. * Makes a copy of this FrameData including copies (not references) to all of the Frames it contains.
  58868. *
  58869. * @method Phaser.FrameData#clone
  58870. * @return {Phaser.FrameData} A clone of this object, including clones of the Frame objects it contains.
  58871. */
  58872. clone: function () {
  58873. var output = new Phaser.FrameData();
  58874. // No input array, so we loop through all frames
  58875. for (var i = 0; i < this._frames.length; i++)
  58876. {
  58877. output._frames.push(this._frames[i].clone());
  58878. }
  58879. for (var p in this._frameNames)
  58880. {
  58881. if (this._frameNames.hasOwnProperty(p))
  58882. {
  58883. output._frameNames.push(this._frameNames[p]);
  58884. }
  58885. }
  58886. return output;
  58887. },
  58888. /**
  58889. * Returns a range of frames based on the given start and end frame indexes and returns them in an Array.
  58890. *
  58891. * @method Phaser.FrameData#getFrameRange
  58892. * @param {number} start - The starting frame index.
  58893. * @param {number} end - The ending frame index.
  58894. * @param {Array} [output] - If given the results will be appended to the end of this array otherwise a new array will be created.
  58895. * @return {Array} An array of Frames between the start and end index values, or an empty array if none were found.
  58896. */
  58897. getFrameRange: function (start, end, output) {
  58898. if (output === undefined) { output = []; }
  58899. for (var i = start; i <= end; i++)
  58900. {
  58901. output.push(this._frames[i]);
  58902. }
  58903. return output;
  58904. },
  58905. /**
  58906. * Returns all of the Frames in this FrameData set where the frame index is found in the input array.
  58907. * The frames are returned in the output array, or if none is provided in a new Array object.
  58908. *
  58909. * @method Phaser.FrameData#getFrames
  58910. * @param {Array} [frames] - An Array containing the indexes of the frames to retrieve. If the array is empty or undefined then all frames in the FrameData are returned.
  58911. * @param {boolean} [useNumericIndex=true] - Are the given frames using numeric indexes (default) or strings? (false)
  58912. * @param {Array} [output] - If given the results will be appended to the end of this array otherwise a new array will be created.
  58913. * @return {Array} An array of all Frames in this FrameData set matching the given names or IDs.
  58914. */
  58915. getFrames: function (frames, useNumericIndex, output) {
  58916. if (useNumericIndex === undefined) { useNumericIndex = true; }
  58917. if (output === undefined) { output = []; }
  58918. if (frames === undefined || frames.length === 0)
  58919. {
  58920. // No input array, so we loop through all frames
  58921. for (var i = 0; i < this._frames.length; i++)
  58922. {
  58923. // We only need the indexes
  58924. output.push(this._frames[i]);
  58925. }
  58926. }
  58927. else
  58928. {
  58929. // Input array given, loop through that instead
  58930. for (var i = 0; i < frames.length; i++)
  58931. {
  58932. // Does the input array contain names or indexes?
  58933. if (useNumericIndex)
  58934. {
  58935. // The actual frame
  58936. output.push(this.getFrame(frames[i]));
  58937. }
  58938. else
  58939. {
  58940. // The actual frame
  58941. output.push(this.getFrameByName(frames[i]));
  58942. }
  58943. }
  58944. }
  58945. return output;
  58946. },
  58947. /**
  58948. * Returns all of the Frame indexes in this FrameData set.
  58949. * The frames indexes are returned in the output array, or if none is provided in a new Array object.
  58950. *
  58951. * @method Phaser.FrameData#getFrameIndexes
  58952. * @param {Array} [frames] - An Array containing the indexes of the frames to retrieve. If undefined or the array is empty then all frames in the FrameData are returned.
  58953. * @param {boolean} [useNumericIndex=true] - Are the given frames using numeric indexes (default) or strings? (false)
  58954. * @param {Array} [output] - If given the results will be appended to the end of this array otherwise a new array will be created.
  58955. * @return {Array} An array of all Frame indexes matching the given names or IDs.
  58956. */
  58957. getFrameIndexes: function (frames, useNumericIndex, output) {
  58958. if (useNumericIndex === undefined) { useNumericIndex = true; }
  58959. if (output === undefined) { output = []; }
  58960. if (frames === undefined || frames.length === 0)
  58961. {
  58962. // No frames array, so we loop through all frames
  58963. for (var i = 0; i < this._frames.length; i++)
  58964. {
  58965. output.push(this._frames[i].index);
  58966. }
  58967. }
  58968. else
  58969. {
  58970. // Input array given, loop through that instead
  58971. for (var i = 0; i < frames.length; i++)
  58972. {
  58973. // Does the frames array contain names or indexes?
  58974. if (useNumericIndex && this._frames[frames[i]])
  58975. {
  58976. output.push(this._frames[frames[i]].index);
  58977. }
  58978. else
  58979. {
  58980. if (this.getFrameByName(frames[i]))
  58981. {
  58982. output.push(this.getFrameByName(frames[i]).index);
  58983. }
  58984. }
  58985. }
  58986. }
  58987. return output;
  58988. },
  58989. /**
  58990. * Destroys this FrameData collection by nulling the _frames and _frameNames arrays.
  58991. *
  58992. * @method Phaser.FrameData#destroy
  58993. */
  58994. destroy: function () {
  58995. this._frames = null;
  58996. this._frameNames = null;
  58997. }
  58998. };
  58999. Phaser.FrameData.prototype.constructor = Phaser.FrameData;
  59000. /**
  59001. * @name Phaser.FrameData#total
  59002. * @property {number} total - The total number of frames in this FrameData set.
  59003. * @readonly
  59004. */
  59005. Object.defineProperty(Phaser.FrameData.prototype, "total", {
  59006. get: function () {
  59007. return this._frames.length;
  59008. }
  59009. });
  59010. /**
  59011. * @author Richard Davey <rich@photonstorm.com>
  59012. * @copyright 2016 Photon Storm Ltd.
  59013. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  59014. */
  59015. /**
  59016. * Responsible for parsing sprite sheet and JSON data into the internal FrameData format that Phaser uses for animations.
  59017. *
  59018. * @class Phaser.AnimationParser
  59019. * @static
  59020. */
  59021. Phaser.AnimationParser = {
  59022. /**
  59023. * Parse a Sprite Sheet and extract the animation frame data from it.
  59024. *
  59025. * @method Phaser.AnimationParser.spriteSheet
  59026. * @param {Phaser.Game} game - A reference to the currently running game.
  59027. * @param {string|Image} key - The Game.Cache asset key of the Sprite Sheet image or an actual HTML Image element.
  59028. * @param {number} frameWidth - The fixed width of each frame of the animation.
  59029. * @param {number} frameHeight - The fixed height of each frame of the animation.
  59030. * @param {number} [frameMax=-1] - The total number of animation frames to extract from the Sprite Sheet. The default value of -1 means "extract all frames".
  59031. * @param {number} [margin=0] - If the frames have been drawn with a margin, specify the amount here.
  59032. * @param {number} [spacing=0] - If the frames have been drawn with spacing between them, specify the amount here.
  59033. * @param {number} [skipFrames=0] - Skip a number of frames. Useful when there are multiple sprite sheets in one image.
  59034. * @return {Phaser.FrameData} A FrameData object containing the parsed frames.
  59035. */
  59036. spriteSheet: function (game, key, frameWidth, frameHeight, frameMax, margin, spacing, skipFrames) {
  59037. if (frameMax === undefined) { frameMax = -1; }
  59038. if (margin === undefined) { margin = 0; }
  59039. if (spacing === undefined) { spacing = 0; }
  59040. if (skipFrames === undefined) { skipFrames = 0; }
  59041. var img = key;
  59042. if (typeof key === 'string')
  59043. {
  59044. img = game.cache.getImage(key);
  59045. }
  59046. if (img === null)
  59047. {
  59048. return null;
  59049. }
  59050. var width = img.width;
  59051. var height = img.height;
  59052. if (frameWidth <= 0)
  59053. {
  59054. frameWidth = Math.floor(-width / Math.min(-1, frameWidth));
  59055. }
  59056. if (frameHeight <= 0)
  59057. {
  59058. frameHeight = Math.floor(-height / Math.min(-1, frameHeight));
  59059. }
  59060. var row = Math.floor((width - margin) / (frameWidth + spacing));
  59061. var column = Math.floor((height - margin) / (frameHeight + spacing));
  59062. var total = row * column;
  59063. if (skipFrames > total || skipFrames < -total)
  59064. {
  59065. console.warn(
  59066. "Phaser.AnimationParser.spriteSheet: skipFrames = " +
  59067. skipFrames.toString() + " is larger than total sprite number " +
  59068. total.toString());
  59069. return null;
  59070. }
  59071. if (skipFrames < 0)
  59072. {
  59073. // Allow negative skipframes.
  59074. skipFrames = total + skipFrames;
  59075. }
  59076. if (frameMax !== -1)
  59077. {
  59078. total = skipFrames + frameMax;
  59079. }
  59080. // Zero or smaller than frame sizes?
  59081. if (width === 0 || height === 0 || width < frameWidth || height < frameHeight || total === 0)
  59082. {
  59083. console.warn("Phaser.AnimationParser.spriteSheet: '" + key + "'s width/height zero or width/height < given frameWidth/frameHeight");
  59084. return null;
  59085. }
  59086. // Let's create some frames then
  59087. var data = new Phaser.FrameData();
  59088. var x = margin;
  59089. var y = margin;
  59090. for (var i = 0; i < total; i++)
  59091. {
  59092. data.addFrame(new Phaser.Frame(i, x, y, frameWidth, frameHeight, ''));
  59093. x += frameWidth + spacing;
  59094. if (x + frameWidth > width)
  59095. {
  59096. x = margin;
  59097. y += frameHeight + spacing;
  59098. }
  59099. }
  59100. return data;
  59101. },
  59102. /**
  59103. * Parse the JSON data and extract the animation frame data from it.
  59104. *
  59105. * @method Phaser.AnimationParser.JSONData
  59106. * @param {Phaser.Game} game - A reference to the currently running game.
  59107. * @param {object} json - The JSON data from the Texture Atlas. Must be in Array format.
  59108. * @return {Phaser.FrameData} A FrameData object containing the parsed frames.
  59109. */
  59110. JSONData: function (game, json) {
  59111. // Malformed?
  59112. if (!json['frames'])
  59113. {
  59114. console.warn("Phaser.AnimationParser.JSONData: Invalid Texture Atlas JSON given, missing 'frames' array");
  59115. console.log(json);
  59116. return;
  59117. }
  59118. // Let's create some frames then
  59119. var data = new Phaser.FrameData();
  59120. // By this stage frames is a fully parsed array
  59121. var frames = json['frames'];
  59122. var newFrame;
  59123. for (var i = 0; i < frames.length; i++)
  59124. {
  59125. newFrame = data.addFrame(new Phaser.Frame(
  59126. i,
  59127. frames[i].frame.x,
  59128. frames[i].frame.y,
  59129. frames[i].frame.w,
  59130. frames[i].frame.h,
  59131. frames[i].filename
  59132. ));
  59133. if (frames[i].trimmed)
  59134. {
  59135. newFrame.setTrim(
  59136. frames[i].trimmed,
  59137. frames[i].sourceSize.w,
  59138. frames[i].sourceSize.h,
  59139. frames[i].spriteSourceSize.x,
  59140. frames[i].spriteSourceSize.y,
  59141. frames[i].spriteSourceSize.w,
  59142. frames[i].spriteSourceSize.h
  59143. );
  59144. }
  59145. if (frames[i].rotated)
  59146. {
  59147. newFrame.rotated = true;
  59148. }
  59149. }
  59150. return data;
  59151. },
  59152. /**
  59153. * Parse the JSON data and extract the animation frame data from it.
  59154. *
  59155. * @method Phaser.AnimationParser.JSONDataPyxel
  59156. * @param {Phaser.Game} game - A reference to the currently running game.
  59157. * @param {object} json - The JSON data from the Texture Atlas. Must be in Pyxel JSON format.
  59158. * @return {Phaser.FrameData} A FrameData object containing the parsed frames.
  59159. */
  59160. JSONDataPyxel: function (game, json) {
  59161. // Malformed? There are a few keys to check here.
  59162. var signature = ['layers', 'tilewidth','tileheight','tileswide', 'tileshigh'];
  59163. signature.forEach( function(key) {
  59164. if (!json[key])
  59165. {
  59166. console.warn('Phaser.AnimationParser.JSONDataPyxel: Invalid Pyxel Tilemap JSON given, missing "' + key + '" key.');
  59167. console.log(json);
  59168. return;
  59169. }
  59170. });
  59171. // For this purpose, I only care about parsing tilemaps with a single layer.
  59172. if (json['layers'].length !== 1)
  59173. {
  59174. console.warn('Phaser.AnimationParser.JSONDataPyxel: Too many layers, this parser only supports flat Tilemaps.');
  59175. console.log(json);
  59176. return;
  59177. }
  59178. var data = new Phaser.FrameData();
  59179. var tileheight = json['tileheight'];
  59180. var tilewidth = json['tilewidth'];
  59181. var frames = json['layers'][0]['tiles'];
  59182. var newFrame;
  59183. for (var i = 0; i < frames.length; i++)
  59184. {
  59185. newFrame = data.addFrame(new Phaser.Frame(
  59186. i,
  59187. frames[i].x,
  59188. frames[i].y,
  59189. tilewidth,
  59190. tileheight,
  59191. "frame_" + i // No names are included in pyxel tilemap data.
  59192. ));
  59193. // No trim data is included.
  59194. newFrame.setTrim(false);
  59195. }
  59196. return data;
  59197. },
  59198. /**
  59199. * Parse the JSON data and extract the animation frame data from it.
  59200. *
  59201. * @method Phaser.AnimationParser.JSONDataHash
  59202. * @param {Phaser.Game} game - A reference to the currently running game.
  59203. * @param {object} json - The JSON data from the Texture Atlas. Must be in JSON Hash format.
  59204. * @return {Phaser.FrameData} A FrameData object containing the parsed frames.
  59205. */
  59206. JSONDataHash: function (game, json) {
  59207. // Malformed?
  59208. if (!json['frames'])
  59209. {
  59210. console.warn("Phaser.AnimationParser.JSONDataHash: Invalid Texture Atlas JSON given, missing 'frames' object");
  59211. console.log(json);
  59212. return;
  59213. }
  59214. // Let's create some frames then
  59215. var data = new Phaser.FrameData();
  59216. // By this stage frames is a fully parsed array
  59217. var frames = json['frames'];
  59218. var newFrame;
  59219. var i = 0;
  59220. for (var key in frames)
  59221. {
  59222. newFrame = data.addFrame(new Phaser.Frame(
  59223. i,
  59224. frames[key].frame.x,
  59225. frames[key].frame.y,
  59226. frames[key].frame.w,
  59227. frames[key].frame.h,
  59228. key
  59229. ));
  59230. if (frames[key].trimmed)
  59231. {
  59232. newFrame.setTrim(
  59233. frames[key].trimmed,
  59234. frames[key].sourceSize.w,
  59235. frames[key].sourceSize.h,
  59236. frames[key].spriteSourceSize.x,
  59237. frames[key].spriteSourceSize.y,
  59238. frames[key].spriteSourceSize.w,
  59239. frames[key].spriteSourceSize.h
  59240. );
  59241. }
  59242. if (frames[key].rotated)
  59243. {
  59244. newFrame.rotated = true;
  59245. }
  59246. i++;
  59247. }
  59248. return data;
  59249. },
  59250. /**
  59251. * Parse the XML data and extract the animation frame data from it.
  59252. *
  59253. * @method Phaser.AnimationParser.XMLData
  59254. * @param {Phaser.Game} game - A reference to the currently running game.
  59255. * @param {object} xml - The XML data from the Texture Atlas. Must be in Starling XML format.
  59256. * @return {Phaser.FrameData} A FrameData object containing the parsed frames.
  59257. */
  59258. XMLData: function (game, xml) {
  59259. // Malformed?
  59260. if (!xml.getElementsByTagName('TextureAtlas'))
  59261. {
  59262. console.warn("Phaser.AnimationParser.XMLData: Invalid Texture Atlas XML given, missing <TextureAtlas> tag");
  59263. return;
  59264. }
  59265. // Let's create some frames then
  59266. var data = new Phaser.FrameData();
  59267. var frames = xml.getElementsByTagName('SubTexture');
  59268. var newFrame;
  59269. var name;
  59270. var frame;
  59271. var x;
  59272. var y;
  59273. var width;
  59274. var height;
  59275. var frameX;
  59276. var frameY;
  59277. var frameWidth;
  59278. var frameHeight;
  59279. for (var i = 0; i < frames.length; i++)
  59280. {
  59281. frame = frames[i].attributes;
  59282. name = frame.name.value;
  59283. x = parseInt(frame.x.value, 10);
  59284. y = parseInt(frame.y.value, 10);
  59285. width = parseInt(frame.width.value, 10);
  59286. height = parseInt(frame.height.value, 10);
  59287. frameX = null;
  59288. frameY = null;
  59289. if (frame.frameX)
  59290. {
  59291. frameX = Math.abs(parseInt(frame.frameX.value, 10));
  59292. frameY = Math.abs(parseInt(frame.frameY.value, 10));
  59293. frameWidth = parseInt(frame.frameWidth.value, 10);
  59294. frameHeight = parseInt(frame.frameHeight.value, 10);
  59295. }
  59296. newFrame = data.addFrame(new Phaser.Frame(i, x, y, width, height, name));
  59297. // Trimmed?
  59298. if (frameX !== null || frameY !== null)
  59299. {
  59300. newFrame.setTrim(true, width, height, frameX, frameY, frameWidth, frameHeight);
  59301. }
  59302. }
  59303. return data;
  59304. }
  59305. };
  59306. /**
  59307. * @author Richard Davey <rich@photonstorm.com>
  59308. * @copyright 2016 Photon Storm Ltd.
  59309. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  59310. */
  59311. /**
  59312. * Phaser has one single cache in which it stores all assets.
  59313. *
  59314. * The cache is split up into sections, such as images, sounds, video, json, etc. All assets are stored using
  59315. * a unique string-based key as their identifier. Assets stored in different areas of the cache can have the
  59316. * same key, for example 'playerWalking' could be used as the key for both a sprite sheet and an audio file,
  59317. * because they are unique data types.
  59318. *
  59319. * The cache is automatically populated by the Phaser.Loader. When you use the loader to pull in external assets
  59320. * such as images they are automatically placed into their respective cache. Most common Game Objects, such as
  59321. * Sprites and Videos automatically query the cache to extract the assets they need on instantiation.
  59322. *
  59323. * You can access the cache from within a State via `this.cache`. From here you can call any public method it has,
  59324. * including adding new entries to it, deleting them or querying them.
  59325. *
  59326. * Understand that almost without exception when you get an item from the cache it will return a reference to the
  59327. * item stored in the cache, not a copy of it. Therefore if you retrieve an item and then modify it, the original
  59328. * object in the cache will also be updated, even if you don't put it back into the cache again.
  59329. *
  59330. * By default when you change State the cache is _not_ cleared, although there is an option to clear it should
  59331. * your game require it. In a typical game set-up the cache is populated once after the main game has loaded and
  59332. * then used as an asset store.
  59333. *
  59334. * @class Phaser.Cache
  59335. * @constructor
  59336. * @param {Phaser.Game} game - A reference to the currently running game.
  59337. */
  59338. Phaser.Cache = function (game) {
  59339. /**
  59340. * @property {Phaser.Game} game - Local reference to game.
  59341. */
  59342. this.game = game;
  59343. /**
  59344. * Automatically resolve resource URLs to absolute paths for use with the Cache.getURL method.
  59345. * @property {boolean} autoResolveURL
  59346. */
  59347. this.autoResolveURL = false;
  59348. /**
  59349. * The main cache object into which all resources are placed.
  59350. * @property {object} _cache
  59351. * @private
  59352. */
  59353. this._cache = {
  59354. canvas: {},
  59355. image: {},
  59356. texture: {},
  59357. sound: {},
  59358. video: {},
  59359. text: {},
  59360. json: {},
  59361. xml: {},
  59362. physics: {},
  59363. tilemap: {},
  59364. binary: {},
  59365. bitmapData: {},
  59366. bitmapFont: {},
  59367. shader: {},
  59368. renderTexture: {},
  59369. compressedTexture: {}
  59370. };
  59371. /**
  59372. * @property {object} _urlMap - Maps URLs to resources.
  59373. * @private
  59374. */
  59375. this._urlMap = {};
  59376. /**
  59377. * @property {Image} _urlResolver - Used to resolve URLs to the absolute path.
  59378. * @private
  59379. */
  59380. this._urlResolver = new Image();
  59381. /**
  59382. * @property {string} _urlTemp - Temporary variable to hold a resolved url.
  59383. * @private
  59384. */
  59385. this._urlTemp = null;
  59386. /**
  59387. * @property {Phaser.Signal} onSoundUnlock - This event is dispatched when the sound system is unlocked via a touch event on cellular devices.
  59388. */
  59389. this.onSoundUnlock = new Phaser.Signal();
  59390. /**
  59391. * @property {array} _cacheMap - Const to cache object look-up array.
  59392. * @private
  59393. */
  59394. this._cacheMap = [];
  59395. this._cacheMap[Phaser.Cache.CANVAS] = this._cache.canvas;
  59396. this._cacheMap[Phaser.Cache.IMAGE] = this._cache.image;
  59397. this._cacheMap[Phaser.Cache.TEXTURE] = this._cache.texture;
  59398. this._cacheMap[Phaser.Cache.SOUND] = this._cache.sound;
  59399. this._cacheMap[Phaser.Cache.TEXT] = this._cache.text;
  59400. this._cacheMap[Phaser.Cache.PHYSICS] = this._cache.physics;
  59401. this._cacheMap[Phaser.Cache.TILEMAP] = this._cache.tilemap;
  59402. this._cacheMap[Phaser.Cache.BINARY] = this._cache.binary;
  59403. this._cacheMap[Phaser.Cache.BITMAPDATA] = this._cache.bitmapData;
  59404. this._cacheMap[Phaser.Cache.BITMAPFONT] = this._cache.bitmapFont;
  59405. this._cacheMap[Phaser.Cache.JSON] = this._cache.json;
  59406. this._cacheMap[Phaser.Cache.XML] = this._cache.xml;
  59407. this._cacheMap[Phaser.Cache.VIDEO] = this._cache.video;
  59408. this._cacheMap[Phaser.Cache.SHADER] = this._cache.shader;
  59409. this._cacheMap[Phaser.Cache.RENDER_TEXTURE] = this._cache.renderTexture;
  59410. /**
  59411. * @property {number}
  59412. * @private
  59413. */
  59414. this._pendingCount = 0;
  59415. /**
  59416. * Dispatched when the DEFAULT and MISSING images have loaded (or the {@link #READY_TIMEOUT load timeout} was exceeded).
  59417. *
  59418. * @property {Phaser.Signal} onReady
  59419. */
  59420. this.onReady = new Phaser.Signal();
  59421. this._addImages();
  59422. };
  59423. /**
  59424. * @constant
  59425. * @type {number}
  59426. */
  59427. Phaser.Cache.CANVAS = 1;
  59428. /**
  59429. * @constant
  59430. * @type {number}
  59431. */
  59432. Phaser.Cache.IMAGE = 2;
  59433. /**
  59434. * @constant
  59435. * @type {number}
  59436. */
  59437. Phaser.Cache.TEXTURE = 3;
  59438. /**
  59439. * @constant
  59440. * @type {number}
  59441. */
  59442. Phaser.Cache.SOUND = 4;
  59443. /**
  59444. * @constant
  59445. * @type {number}
  59446. */
  59447. Phaser.Cache.TEXT = 5;
  59448. /**
  59449. * @constant
  59450. * @type {number}
  59451. */
  59452. Phaser.Cache.PHYSICS = 6;
  59453. /**
  59454. * @constant
  59455. * @type {number}
  59456. */
  59457. Phaser.Cache.TILEMAP = 7;
  59458. /**
  59459. * @constant
  59460. * @type {number}
  59461. */
  59462. Phaser.Cache.BINARY = 8;
  59463. /**
  59464. * @constant
  59465. * @type {number}
  59466. */
  59467. Phaser.Cache.BITMAPDATA = 9;
  59468. /**
  59469. * @constant
  59470. * @type {number}
  59471. */
  59472. Phaser.Cache.BITMAPFONT = 10;
  59473. /**
  59474. * @constant
  59475. * @type {number}
  59476. */
  59477. Phaser.Cache.JSON = 11;
  59478. /**
  59479. * @constant
  59480. * @type {number}
  59481. */
  59482. Phaser.Cache.XML = 12;
  59483. /**
  59484. * @constant
  59485. * @type {number}
  59486. */
  59487. Phaser.Cache.VIDEO = 13;
  59488. /**
  59489. * @constant
  59490. * @type {number}
  59491. */
  59492. Phaser.Cache.SHADER = 14;
  59493. /**
  59494. * @constant
  59495. * @type {number}
  59496. */
  59497. Phaser.Cache.RENDER_TEXTURE = 15;
  59498. /**
  59499. * The default image used for a texture when no other is specified.
  59500. * @constant
  59501. * @type {PIXI.Texture}
  59502. */
  59503. Phaser.Cache.DEFAULT = null;
  59504. /**
  59505. * Key for the DEFAULT texture.
  59506. * @constant
  59507. * @type {string}
  59508. */
  59509. Phaser.Cache.DEFAULT_KEY = '__default';
  59510. /**
  59511. * URL for the DEFAULT texture.
  59512. * @constant
  59513. * @type {string}
  59514. */
  59515. Phaser.Cache.DEFAULT_SRC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAAA1BMVEX///+nxBvIAAAAAXRSTlMAQObYZgAAABVJREFUeF7NwIEAAAAAgKD9qdeocAMAoAABm3DkcAAAAABJRU5ErkJggg==';
  59516. /**
  59517. * The default image used for a texture when the source image is missing.
  59518. * @constant
  59519. * @type {PIXI.Texture}
  59520. */
  59521. Phaser.Cache.MISSING = null;
  59522. /**
  59523. * Key for the MISSING texture.
  59524. * @constant
  59525. * @type {string}
  59526. */
  59527. Phaser.Cache.MISSING_KEY = '__missing';
  59528. /**
  59529. * URL for the MISSING texture.
  59530. * @constant
  59531. * @type {string}
  59532. */
  59533. Phaser.Cache.MISSING_SRC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJ9JREFUeNq01ssOwyAMRFG46v//Mt1ESmgh+DFmE2GPOBARKb2NVjo+17PXLD8a1+pl5+A+wSgFygymWYHBb0FtsKhJDdZlncG2IzJ4ayoMDv20wTmSMzClEgbWYNTAkQ0Z+OJ+A/eWnAaR9+oxCF4Os0H8htsMUp+pwcgBBiMNnAwF8GqIgL2hAzaGFFgZauDPKABmowZ4GL369/0rwACp2yA/ttmvsQAAAABJRU5ErkJggg==';
  59534. /**
  59535. * The maximum amount of time (ms) to wait for the built-in DEFAULT and MISSING images to load.
  59536. * @static
  59537. * @type {number}
  59538. * @default
  59539. */
  59540. Phaser.Cache.READY_TIMEOUT = 1000;
  59541. Phaser.Cache.prototype = {
  59542. //////////////////
  59543. // Add Methods //
  59544. //////////////////
  59545. /**
  59546. * Add a new canvas object in to the cache.
  59547. *
  59548. * @method Phaser.Cache#addCompressedTextureMetaData
  59549. * @private
  59550. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59551. * @param {string} url
  59552. * @param {string} extension
  59553. * @param {array} arrayBuffer
  59554. * @return {object} The compressed texture entry.
  59555. */
  59556. addCompressedTextureMetaData: function (key, url, extension, arrayBuffer) {
  59557. if (this.checkImageKey(key))
  59558. {
  59559. this.removeImage(key);
  59560. }
  59561. var data = (extension in Phaser.LoaderParser) ? Phaser.LoaderParser[extension](arrayBuffer) : arrayBuffer;
  59562. var texture = {
  59563. key: key,
  59564. url: url,
  59565. data: data,
  59566. base: new PIXI.BaseTexture(data, null, this.game.resolution),
  59567. frame: new Phaser.Frame(0, 0, 0, data.width, data.height, key),
  59568. frameData: new Phaser.FrameData(),
  59569. fileFormat: extension
  59570. };
  59571. texture.frameData.addFrame(new Phaser.Frame(0, 0, 0, data.width, data.height, url));
  59572. this._cache.image[key] = texture;
  59573. this._resolveURL(url, texture);
  59574. return texture;
  59575. },
  59576. /**
  59577. * Add a new canvas object in to the cache.
  59578. *
  59579. * @method Phaser.Cache#addCanvas
  59580. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59581. * @param {HTMLCanvasElement} canvas - The Canvas DOM element.
  59582. * @param {CanvasRenderingContext2D} [context] - The context of the canvas element. If not specified it will default go `getContext('2d')`.
  59583. */
  59584. addCanvas: function (key, canvas, context) {
  59585. if (context === undefined) { context = canvas.getContext('2d'); }
  59586. this._cache.canvas[key] = { canvas: canvas, context: context };
  59587. },
  59588. /**
  59589. * Adds an Image file into the Cache. The file must have already been loaded, typically via Phaser.Loader, but can also have been loaded into the DOM.
  59590. * If an image already exists in the cache with the same key then it is removed and destroyed, and the new image inserted in its place.
  59591. *
  59592. * If the image has not yet been fetched (successfully or not), a `console.warn` message will be displayed.
  59593. *
  59594. * @method Phaser.Cache#addImage
  59595. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59596. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59597. * @param {object} data - Extra image data.
  59598. * @return {object} The full image object that was added to the cache.
  59599. */
  59600. addImage: function (key, url, data) {
  59601. if (this.checkImageKey(key))
  59602. {
  59603. this.removeImage(key);
  59604. }
  59605. if (data.complete === false)
  59606. {
  59607. console.warn('Phaser.Cache.addImage: Image "' + key + '" hasn\'t been retrieved yet');
  59608. }
  59609. var img = {
  59610. key: key,
  59611. url: url,
  59612. data: data,
  59613. base: new PIXI.BaseTexture(data, null, this.game.resolution),
  59614. frame: new Phaser.Frame(0, 0, 0, data.width, data.height, key),
  59615. frameData: new Phaser.FrameData()
  59616. };
  59617. img.frameData.addFrame(new Phaser.Frame(0, 0, 0, data.width, data.height, url));
  59618. this._cache.image[key] = img;
  59619. this._resolveURL(url, img);
  59620. if (key === '__default')
  59621. {
  59622. Phaser.Cache.DEFAULT = new PIXI.Texture(img.base);
  59623. }
  59624. else if (key === '__missing')
  59625. {
  59626. Phaser.Cache.MISSING = new PIXI.Texture(img.base);
  59627. }
  59628. return img;
  59629. },
  59630. /**
  59631. * @method Phaser.Cache#addImageAsync
  59632. * @private
  59633. */
  59634. addImageAsync: function (key, src, callback) {
  59635. var self = this;
  59636. var img = new Image();
  59637. img.onload = function () {
  59638. callback.call(this, self.addImage(key, null, img));
  59639. self._removePending();
  59640. img.onload = null;
  59641. };
  59642. this._addPending();
  59643. img.src = src;
  59644. },
  59645. /**
  59646. * Adds a default image to be used in special cases such as WebGL Filters.
  59647. * It uses the special reserved key of `__default`.
  59648. * This method is called automatically when the Cache is created.
  59649. * This image is skipped when `Cache.destroy` is called due to its internal requirements.
  59650. *
  59651. * @method Phaser.Cache#addDefaultImage
  59652. * @protected
  59653. */
  59654. addDefaultImage: function () {
  59655. this.addImageAsync(Phaser.Cache.DEFAULT_KEY, Phaser.Cache.DEFAULT_SRC, function (obj) {
  59656. // Because we don't want to invalidate the sprite batch for an invisible texture
  59657. obj.base.skipRender = true;
  59658. // Make it easily available within the rest of Phaser / Pixi
  59659. Phaser.Cache.DEFAULT = new PIXI.Texture(obj.base);
  59660. });
  59661. },
  59662. /**
  59663. * Adds an image to be used when a key is wrong / missing.
  59664. * It uses the special reserved key of `__missing`.
  59665. * This method is called automatically when the Cache is created.
  59666. * This image is skipped when `Cache.destroy` is called due to its internal requirements.
  59667. *
  59668. * @method Phaser.Cache#addMissingImage
  59669. * @protected
  59670. */
  59671. addMissingImage: function () {
  59672. this.addImageAsync(Phaser.Cache.MISSING_KEY, Phaser.Cache.MISSING_SRC, function (obj) {
  59673. // Make it easily available within the rest of Phaser / Pixi
  59674. Phaser.Cache.MISSING = new PIXI.Texture(obj.base);
  59675. });
  59676. },
  59677. /**
  59678. * Adds a Sound file into the Cache. The file must have already been loaded, typically via Phaser.Loader.
  59679. *
  59680. * @method Phaser.Cache#addSound
  59681. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59682. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59683. * @param {object} data - Extra sound data.
  59684. * @param {boolean} webAudio - True if the file is using web audio.
  59685. * @param {boolean} audioTag - True if the file is using legacy HTML audio.
  59686. */
  59687. addSound: function (key, url, data, webAudio, audioTag) {
  59688. if (webAudio === undefined) { webAudio = true; audioTag = false; }
  59689. if (audioTag === undefined) { webAudio = false; audioTag = true; }
  59690. var decoded = false;
  59691. if (audioTag)
  59692. {
  59693. decoded = true;
  59694. }
  59695. this._cache.sound[key] = {
  59696. url: url,
  59697. data: data,
  59698. isDecoding: false,
  59699. decoded: decoded,
  59700. webAudio: webAudio,
  59701. audioTag: audioTag,
  59702. locked: this.game.sound.touchLocked
  59703. };
  59704. this._resolveURL(url, this._cache.sound[key]);
  59705. },
  59706. /**
  59707. * Add a new text data.
  59708. *
  59709. * @method Phaser.Cache#addText
  59710. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59711. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59712. * @param {object} data - Extra text data.
  59713. */
  59714. addText: function (key, url, data) {
  59715. this._cache.text[key] = { url: url, data: data };
  59716. this._resolveURL(url, this._cache.text[key]);
  59717. },
  59718. /**
  59719. * Add a new physics data object to the Cache.
  59720. *
  59721. * @method Phaser.Cache#addPhysicsData
  59722. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59723. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59724. * @param {object} JSONData - The physics data object (a JSON file).
  59725. * @param {number} format - The format of the physics data.
  59726. */
  59727. addPhysicsData: function (key, url, JSONData, format) {
  59728. this._cache.physics[key] = { url: url, data: JSONData, format: format };
  59729. this._resolveURL(url, this._cache.physics[key]);
  59730. },
  59731. /**
  59732. * Add a new tilemap to the Cache.
  59733. *
  59734. * @method Phaser.Cache#addTilemap
  59735. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59736. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59737. * @param {object} mapData - The tilemap data object (either a CSV or JSON file).
  59738. * @param {number} format - The format of the tilemap data.
  59739. */
  59740. addTilemap: function (key, url, mapData, format) {
  59741. this._cache.tilemap[key] = { url: url, data: mapData, format: format };
  59742. this._resolveURL(url, this._cache.tilemap[key]);
  59743. },
  59744. /**
  59745. * Add a binary object in to the cache.
  59746. *
  59747. * @method Phaser.Cache#addBinary
  59748. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59749. * @param {object} binaryData - The binary object to be added to the cache.
  59750. */
  59751. addBinary: function (key, binaryData) {
  59752. this._cache.binary[key] = binaryData;
  59753. },
  59754. /**
  59755. * Add a BitmapData object to the cache.
  59756. *
  59757. * @method Phaser.Cache#addBitmapData
  59758. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59759. * @param {Phaser.BitmapData} bitmapData - The BitmapData object to be addded to the cache.
  59760. * @param {Phaser.FrameData|null} [frameData=(auto create)] - Optional FrameData set associated with the given BitmapData. If not specified (or `undefined`) a new FrameData object is created containing the Bitmap's Frame. If `null` is supplied then no FrameData will be created.
  59761. * @return {Phaser.BitmapData} The BitmapData object to be addded to the cache.
  59762. */
  59763. addBitmapData: function (key, bitmapData, frameData) {
  59764. bitmapData.key = key;
  59765. if (frameData === undefined)
  59766. {
  59767. frameData = new Phaser.FrameData();
  59768. frameData.addFrame(bitmapData.textureFrame);
  59769. }
  59770. this._cache.bitmapData[key] = { data: bitmapData, frameData: frameData };
  59771. return bitmapData;
  59772. },
  59773. /**
  59774. * Add a new Bitmap Font to the Cache.
  59775. *
  59776. * @method Phaser.Cache#addBitmapFont
  59777. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59778. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59779. * @param {object} data - Extra font data.
  59780. * @param {object} atlasData - The Bitmap Font data.
  59781. * @param {string} [atlasType='xml'] - The format of the Bitmap Font data file: `json` or `xml`.
  59782. * @param {number} [xSpacing=0] - If you'd like to add additional horizontal spacing between the characters then set the pixel value here.
  59783. * @param {number} [ySpacing=0] - If you'd like to add additional vertical spacing between the lines then set the pixel value here.
  59784. */
  59785. addBitmapFont: function (key, url, data, atlasData, atlasType, xSpacing, ySpacing) {
  59786. var obj = {
  59787. url: url,
  59788. data: data,
  59789. font: null,
  59790. base: new PIXI.BaseTexture(data, null, this.game.resolution)
  59791. };
  59792. if (xSpacing === undefined) { xSpacing = 0; }
  59793. if (ySpacing === undefined) { ySpacing = 0; }
  59794. if (atlasType === 'json')
  59795. {
  59796. obj.font = Phaser.LoaderParser.jsonBitmapFont(atlasData, obj.base, xSpacing, ySpacing, false, this.game.resolution);
  59797. }
  59798. else
  59799. {
  59800. obj.font = Phaser.LoaderParser.xmlBitmapFont(atlasData, obj.base, xSpacing, ySpacing, false, this.game.resolution);
  59801. }
  59802. this._cache.bitmapFont[key] = obj;
  59803. this._resolveURL(url, obj);
  59804. },
  59805. /**
  59806. * Add a new Bitmap Font to the Cache, where the font texture is part of a Texture Atlas.
  59807. *
  59808. * The atlas must already exist in the cache, and be available based on the given `atlasKey`.
  59809. *
  59810. * The `atlasFrame` specifies the name of the frame within the atlas that the Bitmap Font is
  59811. * stored in.
  59812. *
  59813. * The `dataKey` is the key of the XML or JSON Bitmap Font Data, which must already be in
  59814. * the Cache.
  59815. *
  59816. * @method Phaser.Cache#addBitmapFontFromAtlas
  59817. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59818. * @param {string} atlasKey - The key of the Texture Atlas in the Cache.
  59819. * @param {string} atlasFrame - The frame of the Texture Atlas that the Bitmap Font is in.
  59820. * @param {string} dataKey - The key of the Bitmap Font data in the Cache
  59821. * @param {string} [dataType='xml'] - The format of the Bitmap Font data: `json` or `xml`.
  59822. * @param {number} [xSpacing=0] - If you'd like to add additional horizontal spacing between the characters then set the pixel value here.
  59823. * @param {number} [ySpacing=0] - If you'd like to add additional vertical spacing between the lines then set the pixel value here.
  59824. */
  59825. addBitmapFontFromAtlas: function (key, atlasKey, atlasFrame, dataKey, dataType, xSpacing, ySpacing) {
  59826. var frame = this.getFrameByName(atlasKey, atlasFrame);
  59827. if (!frame)
  59828. {
  59829. return;
  59830. }
  59831. var obj = {
  59832. font: null,
  59833. base: this.getBaseTexture(atlasKey),
  59834. frame: frame
  59835. };
  59836. if (xSpacing === undefined) { xSpacing = 0; }
  59837. if (ySpacing === undefined) { ySpacing = 0; }
  59838. var fontData;
  59839. if (dataType === 'json')
  59840. {
  59841. fontData = this.getJSON(dataKey);
  59842. obj.font = Phaser.LoaderParser.jsonBitmapFont(fontData, obj.base, xSpacing, ySpacing, frame, this.game.resolution);
  59843. }
  59844. else
  59845. {
  59846. fontData = this.getXML(dataKey);
  59847. obj.font = Phaser.LoaderParser.xmlBitmapFont(fontData, obj.base, xSpacing, ySpacing, frame, this.game.resolution);
  59848. }
  59849. this._cache.bitmapFont[key] = obj;
  59850. },
  59851. /**
  59852. * Add a new json object into the cache.
  59853. *
  59854. * @method Phaser.Cache#addJSON
  59855. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59856. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59857. * @param {object} data - Extra json data.
  59858. */
  59859. addJSON: function (key, url, data) {
  59860. this._cache.json[key] = { url: url, data: data };
  59861. this._resolveURL(url, this._cache.json[key]);
  59862. },
  59863. /**
  59864. * Add a new xml object into the cache.
  59865. *
  59866. * @method Phaser.Cache#addXML
  59867. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59868. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59869. * @param {object} data - Extra text data.
  59870. */
  59871. addXML: function (key, url, data) {
  59872. this._cache.xml[key] = { url: url, data: data };
  59873. this._resolveURL(url, this._cache.xml[key]);
  59874. },
  59875. /**
  59876. * Adds a Video file into the Cache. The file must have already been loaded, typically via Phaser.Loader.
  59877. *
  59878. * @method Phaser.Cache#addVideo
  59879. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59880. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59881. * @param {object} data - Extra video data.
  59882. * @param {boolean} isBlob - True if the file was preloaded via xhr and the data parameter is a Blob. false if a Video tag was created instead.
  59883. */
  59884. addVideo: function (key, url, data, isBlob) {
  59885. this._cache.video[key] = { url: url, data: data, isBlob: isBlob, locked: true };
  59886. this._resolveURL(url, this._cache.video[key]);
  59887. },
  59888. /**
  59889. * Adds a Fragment Shader in to the Cache. The file must have already been loaded, typically via Phaser.Loader.
  59890. *
  59891. * @method Phaser.Cache#addShader
  59892. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59893. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59894. * @param {object} data - Extra shader data.
  59895. */
  59896. addShader: function (key, url, data) {
  59897. this._cache.shader[key] = { url: url, data: data };
  59898. this._resolveURL(url, this._cache.shader[key]);
  59899. },
  59900. /**
  59901. * Add a new Phaser.RenderTexture in to the cache.
  59902. *
  59903. * @method Phaser.Cache#addRenderTexture
  59904. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59905. * @param {Phaser.RenderTexture} texture - The texture to use as the base of the RenderTexture.
  59906. */
  59907. addRenderTexture: function (key, texture) {
  59908. this._cache.renderTexture[key] = { texture: texture, frame: new Phaser.Frame(0, 0, 0, texture.width, texture.height, '', '') };
  59909. },
  59910. /**
  59911. * Add a new sprite sheet in to the cache.
  59912. *
  59913. * @method Phaser.Cache#addSpriteSheet
  59914. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59915. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59916. * @param {object} data - Extra sprite sheet data.
  59917. * @param {number} frameWidth - Width of the sprite sheet.
  59918. * @param {number} frameHeight - Height of the sprite sheet.
  59919. * @param {number} [frameMax=-1] - How many frames stored in the sprite sheet. If -1 then it divides the whole sheet evenly.
  59920. * @param {number} [margin=0] - If the frames have been drawn with a margin, specify the amount here.
  59921. * @param {number} [spacing=0] - If the frames have been drawn with spacing between them, specify the amount here.
  59922. * @param {number} [skipFrames=0] - Skip a number of frames. Useful when there are multiple sprite sheets in one image.
  59923. */
  59924. addSpriteSheet: function (key, url, data, frameWidth, frameHeight, frameMax, margin, spacing, skipFrames) {
  59925. if (frameMax === undefined) { frameMax = -1; }
  59926. if (margin === undefined) { margin = 0; }
  59927. if (spacing === undefined) { spacing = 0; }
  59928. var obj = {
  59929. key: key,
  59930. url: url,
  59931. data: data,
  59932. frameWidth: frameWidth,
  59933. frameHeight: frameHeight,
  59934. margin: margin,
  59935. spacing: spacing,
  59936. base: new PIXI.BaseTexture(data, null, this.game.resolution),
  59937. frameData: Phaser.AnimationParser.spriteSheet(this.game, data, frameWidth, frameHeight, frameMax, margin, spacing, skipFrames)
  59938. };
  59939. this._cache.image[key] = obj;
  59940. this._resolveURL(url, obj);
  59941. },
  59942. /**
  59943. * Add a new texture atlas to the Cache.
  59944. *
  59945. * @method Phaser.Cache#addTextureAtlas
  59946. * @param {string} key - The key that this asset will be stored in the cache under. This should be unique within this cache.
  59947. * @param {string} url - The URL the asset was loaded from. If the asset was not loaded externally set to `null`.
  59948. * @param {object} data - Extra texture atlas data.
  59949. * @param {object} atlasData - Texture atlas frames data.
  59950. * @param {number} format - The format of the texture atlas.
  59951. */
  59952. addTextureAtlas: function (key, url, data, atlasData, format) {
  59953. var obj = {
  59954. key: key,
  59955. url: url,
  59956. data: data,
  59957. base: new PIXI.BaseTexture(data, null, this.game.resolution)
  59958. };
  59959. if (format === Phaser.Loader.TEXTURE_ATLAS_XML_STARLING)
  59960. {
  59961. obj.frameData = Phaser.AnimationParser.XMLData(this.game, atlasData, key);
  59962. }
  59963. else if (format === Phaser.Loader.TEXTURE_ATLAS_JSON_PYXEL)
  59964. {
  59965. obj.frameData = Phaser.AnimationParser.JSONDataPyxel(this.game, atlasData, key);
  59966. }
  59967. else
  59968. {
  59969. // Let's just work it out from the frames array
  59970. if (Array.isArray(atlasData.frames))
  59971. {
  59972. obj.frameData = Phaser.AnimationParser.JSONData(this.game, atlasData, key);
  59973. }
  59974. else
  59975. {
  59976. obj.frameData = Phaser.AnimationParser.JSONDataHash(this.game, atlasData, key);
  59977. }
  59978. }
  59979. this._cache.image[key] = obj;
  59980. this._resolveURL(url, obj);
  59981. },
  59982. ////////////////////////////
  59983. // Sound Related Methods //
  59984. ////////////////////////////
  59985. /**
  59986. * Reload a Sound file from the server.
  59987. *
  59988. * @method Phaser.Cache#reloadSound
  59989. * @param {string} key - The key of the asset within the cache.
  59990. */
  59991. reloadSound: function (key) {
  59992. var _this = this;
  59993. var sound = this.getSound(key);
  59994. if (sound)
  59995. {
  59996. sound.data.src = sound.url;
  59997. sound.data.addEventListener('canplaythrough', function () {
  59998. return _this.reloadSoundComplete(key);
  59999. }, false);
  60000. sound.data.load();
  60001. }
  60002. },
  60003. /**
  60004. * Fires the onSoundUnlock event when the sound has completed reloading.
  60005. *
  60006. * @method Phaser.Cache#reloadSoundComplete
  60007. * @param {string} key - The key of the asset within the cache.
  60008. */
  60009. reloadSoundComplete: function (key) {
  60010. var sound = this.getSound(key);
  60011. if (sound)
  60012. {
  60013. sound.locked = false;
  60014. this.onSoundUnlock.dispatch(key);
  60015. }
  60016. },
  60017. /**
  60018. * Updates the sound object in the cache.
  60019. *
  60020. * @method Phaser.Cache#updateSound
  60021. * @param {string} key - The key of the asset within the cache.
  60022. */
  60023. updateSound: function (key, property, value) {
  60024. var sound = this.getSound(key);
  60025. if (sound)
  60026. {
  60027. sound[property] = value;
  60028. }
  60029. },
  60030. /**
  60031. * Add a new decoded sound.
  60032. *
  60033. * @method Phaser.Cache#decodedSound
  60034. * @param {string} key - The key of the asset within the cache.
  60035. * @param {object} data - Extra sound data.
  60036. */
  60037. decodedSound: function (key, data) {
  60038. var sound = this.getSound(key);
  60039. sound.data = data;
  60040. sound.decoded = true;
  60041. sound.isDecoding = false;
  60042. },
  60043. /**
  60044. * Check if the given sound has finished decoding.
  60045. *
  60046. * @method Phaser.Cache#isSoundDecoded
  60047. * @param {string} key - The key of the asset within the cache.
  60048. * @return {boolean} The decoded state of the Sound object.
  60049. */
  60050. isSoundDecoded: function (key) {
  60051. var sound = this.getItem(key, Phaser.Cache.SOUND, 'isSoundDecoded');
  60052. if (sound)
  60053. {
  60054. return sound.decoded;
  60055. }
  60056. },
  60057. /**
  60058. * Check if the given sound is ready for playback.
  60059. * A sound is considered ready when it has finished decoding and the device is no longer touch locked.
  60060. *
  60061. * @method Phaser.Cache#isSoundReady
  60062. * @param {string} key - The key of the asset within the cache.
  60063. * @return {boolean} True if the sound is decoded and the device is not touch locked.
  60064. */
  60065. isSoundReady: function (key) {
  60066. var sound = this.getItem(key, Phaser.Cache.SOUND, 'isSoundDecoded');
  60067. if (sound)
  60068. {
  60069. return (sound.decoded && !this.game.sound.touchLocked);
  60070. }
  60071. },
  60072. ////////////////////////
  60073. // Check Key Methods //
  60074. ////////////////////////
  60075. /**
  60076. * Checks if a key for the given cache object type exists.
  60077. *
  60078. * @method Phaser.Cache#checkKey
  60079. * @param {integer} cache - The cache to search. One of the Cache consts such as `Phaser.Cache.IMAGE` or `Phaser.Cache.SOUND`.
  60080. * @param {string} key - The key of the asset within the cache.
  60081. * @return {boolean} True if the key exists, otherwise false.
  60082. */
  60083. checkKey: function (cache, key) {
  60084. if (this._cacheMap[cache][key])
  60085. {
  60086. return true;
  60087. }
  60088. return false;
  60089. },
  60090. /**
  60091. * Checks if the given URL has been loaded into the Cache.
  60092. * This method will only work if Cache.autoResolveURL was set to `true` before any preloading took place.
  60093. * The method will make a DOM src call to the URL given, so please be aware of this for certain file types, such as Sound files on Firefox
  60094. * which may cause double-load instances.
  60095. *
  60096. * @method Phaser.Cache#checkURL
  60097. * @param {string} url - The url to check for in the cache.
  60098. * @return {boolean} True if the url exists, otherwise false.
  60099. */
  60100. checkURL: function (url) {
  60101. if (this._urlMap[this._resolveURL(url)])
  60102. {
  60103. return true;
  60104. }
  60105. return false;
  60106. },
  60107. /**
  60108. * Checks if the given key exists in the Canvas Cache.
  60109. *
  60110. * @method Phaser.Cache#checkCanvasKey
  60111. * @param {string} key - The key of the asset within the cache.
  60112. * @return {boolean} True if the key exists in the cache, otherwise false.
  60113. */
  60114. checkCanvasKey: function (key) {
  60115. return this.checkKey(Phaser.Cache.CANVAS, key);
  60116. },
  60117. /**
  60118. * Checks if the given key exists in the Image Cache. Note that this also includes Texture Atlases, Sprite Sheets and Retro Fonts.
  60119. *
  60120. * @method Phaser.Cache#checkImageKey
  60121. * @param {string} key - The key of the asset within the cache.
  60122. * @return {boolean} True if the key exists in the cache, otherwise false.
  60123. */
  60124. checkImageKey: function (key) {
  60125. return this.checkKey(Phaser.Cache.IMAGE, key);
  60126. },
  60127. /**
  60128. * Checks if the given key exists in the Texture Cache.
  60129. *
  60130. * @method Phaser.Cache#checkTextureKey
  60131. * @param {string} key - The key of the asset within the cache.
  60132. * @return {boolean} True if the key exists in the cache, otherwise false.
  60133. */
  60134. checkTextureKey: function (key) {
  60135. return this.checkKey(Phaser.Cache.TEXTURE, key);
  60136. },
  60137. /**
  60138. * Checks if the given key exists in the Sound Cache.
  60139. *
  60140. * @method Phaser.Cache#checkSoundKey
  60141. * @param {string} key - The key of the asset within the cache.
  60142. * @return {boolean} True if the key exists in the cache, otherwise false.
  60143. */
  60144. checkSoundKey: function (key) {
  60145. return this.checkKey(Phaser.Cache.SOUND, key);
  60146. },
  60147. /**
  60148. * Checks if the given key exists in the Text Cache.
  60149. *
  60150. * @method Phaser.Cache#checkTextKey
  60151. * @param {string} key - The key of the asset within the cache.
  60152. * @return {boolean} True if the key exists in the cache, otherwise false.
  60153. */
  60154. checkTextKey: function (key) {
  60155. return this.checkKey(Phaser.Cache.TEXT, key);
  60156. },
  60157. /**
  60158. * Checks if the given key exists in the Physics Cache.
  60159. *
  60160. * @method Phaser.Cache#checkPhysicsKey
  60161. * @param {string} key - The key of the asset within the cache.
  60162. * @return {boolean} True if the key exists in the cache, otherwise false.
  60163. */
  60164. checkPhysicsKey: function (key) {
  60165. return this.checkKey(Phaser.Cache.PHYSICS, key);
  60166. },
  60167. /**
  60168. * Checks if the given key exists in the Tilemap Cache.
  60169. *
  60170. * @method Phaser.Cache#checkTilemapKey
  60171. * @param {string} key - The key of the asset within the cache.
  60172. * @return {boolean} True if the key exists in the cache, otherwise false.
  60173. */
  60174. checkTilemapKey: function (key) {
  60175. return this.checkKey(Phaser.Cache.TILEMAP, key);
  60176. },
  60177. /**
  60178. * Checks if the given key exists in the Binary Cache.
  60179. *
  60180. * @method Phaser.Cache#checkBinaryKey
  60181. * @param {string} key - The key of the asset within the cache.
  60182. * @return {boolean} True if the key exists in the cache, otherwise false.
  60183. */
  60184. checkBinaryKey: function (key) {
  60185. return this.checkKey(Phaser.Cache.BINARY, key);
  60186. },
  60187. /**
  60188. * Checks if the given key exists in the BitmapData Cache.
  60189. *
  60190. * @method Phaser.Cache#checkBitmapDataKey
  60191. * @param {string} key - The key of the asset within the cache.
  60192. * @return {boolean} True if the key exists in the cache, otherwise false.
  60193. */
  60194. checkBitmapDataKey: function (key) {
  60195. return this.checkKey(Phaser.Cache.BITMAPDATA, key);
  60196. },
  60197. /**
  60198. * Checks if the given key exists in the BitmapFont Cache.
  60199. *
  60200. * @method Phaser.Cache#checkBitmapFontKey
  60201. * @param {string} key - The key of the asset within the cache.
  60202. * @return {boolean} True if the key exists in the cache, otherwise false.
  60203. */
  60204. checkBitmapFontKey: function (key) {
  60205. return this.checkKey(Phaser.Cache.BITMAPFONT, key);
  60206. },
  60207. /**
  60208. * Checks if the given key exists in the JSON Cache.
  60209. *
  60210. * @method Phaser.Cache#checkJSONKey
  60211. * @param {string} key - The key of the asset within the cache.
  60212. * @return {boolean} True if the key exists in the cache, otherwise false.
  60213. */
  60214. checkJSONKey: function (key) {
  60215. return this.checkKey(Phaser.Cache.JSON, key);
  60216. },
  60217. /**
  60218. * Checks if the given key exists in the XML Cache.
  60219. *
  60220. * @method Phaser.Cache#checkXMLKey
  60221. * @param {string} key - The key of the asset within the cache.
  60222. * @return {boolean} True if the key exists in the cache, otherwise false.
  60223. */
  60224. checkXMLKey: function (key) {
  60225. return this.checkKey(Phaser.Cache.XML, key);
  60226. },
  60227. /**
  60228. * Checks if the given key exists in the Video Cache.
  60229. *
  60230. * @method Phaser.Cache#checkVideoKey
  60231. * @param {string} key - The key of the asset within the cache.
  60232. * @return {boolean} True if the key exists in the cache, otherwise false.
  60233. */
  60234. checkVideoKey: function (key) {
  60235. return this.checkKey(Phaser.Cache.VIDEO, key);
  60236. },
  60237. /**
  60238. * Checks if the given key exists in the Fragment Shader Cache.
  60239. *
  60240. * @method Phaser.Cache#checkShaderKey
  60241. * @param {string} key - The key of the asset within the cache.
  60242. * @return {boolean} True if the key exists in the cache, otherwise false.
  60243. */
  60244. checkShaderKey: function (key) {
  60245. return this.checkKey(Phaser.Cache.SHADER, key);
  60246. },
  60247. /**
  60248. * Checks if the given key exists in the Render Texture Cache.
  60249. *
  60250. * @method Phaser.Cache#checkRenderTextureKey
  60251. * @param {string} key - The key of the asset within the cache.
  60252. * @return {boolean} True if the key exists in the cache, otherwise false.
  60253. */
  60254. checkRenderTextureKey: function (key) {
  60255. return this.checkKey(Phaser.Cache.RENDER_TEXTURE, key);
  60256. },
  60257. ////////////////
  60258. // Get Items //
  60259. ////////////////
  60260. /**
  60261. * Get an item from a cache based on the given key and property.
  60262. *
  60263. * This method is mostly used internally by other Cache methods such as `getImage` but is exposed
  60264. * publicly for your own use as well.
  60265. *
  60266. * @method Phaser.Cache#getItem
  60267. * @param {string} key - The key of the asset within the cache.
  60268. * @param {integer} cache - The cache to search. One of the Cache consts such as `Phaser.Cache.IMAGE` or `Phaser.Cache.SOUND`.
  60269. * @param {string} [method] - The string name of the method calling getItem. Can be empty, in which case no console warning is output.
  60270. * @param {string} [property] - If you require a specific property from the cache item, specify it here.
  60271. * @return {object} The cached item if found, otherwise `null`. If the key is invalid and `method` is set then a console.warn is output.
  60272. */
  60273. getItem: function (key, cache, method, property) {
  60274. if (!this.checkKey(cache, key))
  60275. {
  60276. if (method)
  60277. {
  60278. console.warn('Phaser.Cache.' + method + ': Key "' + key + '" not found in Cache.');
  60279. }
  60280. }
  60281. else
  60282. {
  60283. if (property === undefined)
  60284. {
  60285. return this._cacheMap[cache][key];
  60286. }
  60287. else
  60288. {
  60289. return this._cacheMap[cache][key][property];
  60290. }
  60291. }
  60292. return null;
  60293. },
  60294. /**
  60295. * Gets a Canvas object from the cache.
  60296. *
  60297. * The object is looked-up based on the key given.
  60298. *
  60299. * Note: If the object cannot be found a `console.warn` message is displayed.
  60300. *
  60301. * @method Phaser.Cache#getCanvas
  60302. * @param {string} key - The key of the asset to retrieve from the cache.
  60303. * @return {object} The canvas object or `null` if no item could be found matching the given key.
  60304. */
  60305. getCanvas: function (key) {
  60306. return this.getItem(key, Phaser.Cache.CANVAS, 'getCanvas', 'canvas');
  60307. },
  60308. /**
  60309. * Gets a Image object from the cache. This returns a DOM Image object, not a Phaser.Image object.
  60310. *
  60311. * The object is looked-up based on the key given.
  60312. *
  60313. * Note: If the object cannot be found a `console.warn` message is displayed.
  60314. *
  60315. * Only the Image cache is searched, which covers images loaded via Loader.image, Sprite Sheets and Texture Atlases.
  60316. *
  60317. * If you need the image used by a bitmap font or similar then please use those respective 'get' methods.
  60318. *
  60319. * @method Phaser.Cache#getImage
  60320. * @param {string} [key] - The key of the asset to retrieve from the cache. If not given or null it will return a default image. If given but not found in the cache it will throw a warning and return the missing image.
  60321. * @param {boolean} [full=false] - If true the full image object will be returned, if false just the HTML Image object is returned.
  60322. * @return {Image} The Image object if found in the Cache, otherwise `null`. If `full` was true then a JavaScript object is returned.
  60323. */
  60324. getImage: function (key, full) {
  60325. if (key === undefined || key === null)
  60326. {
  60327. key = '__default';
  60328. }
  60329. if (full === undefined) { full = false; }
  60330. var img = this.getItem(key, Phaser.Cache.IMAGE, 'getImage');
  60331. if (img === null)
  60332. {
  60333. img = this.getItem('__missing', Phaser.Cache.IMAGE, 'getImage');
  60334. }
  60335. if (full)
  60336. {
  60337. return img;
  60338. }
  60339. else
  60340. {
  60341. return img.data;
  60342. }
  60343. },
  60344. /**
  60345. * Get a single texture frame by key.
  60346. *
  60347. * You'd only do this to get the default Frame created for a non-atlas / spritesheet image.
  60348. *
  60349. * @method Phaser.Cache#getTextureFrame
  60350. * @param {string} key - The key of the asset to retrieve from the cache.
  60351. * @return {Phaser.Frame} The frame data.
  60352. */
  60353. getTextureFrame: function (key) {
  60354. return this.getItem(key, Phaser.Cache.TEXTURE, 'getTextureFrame', 'frame');
  60355. },
  60356. /**
  60357. * Gets a Phaser.Sound object from the cache.
  60358. *
  60359. * The object is looked-up based on the key given.
  60360. *
  60361. * Note: If the object cannot be found a `console.warn` message is displayed.
  60362. *
  60363. * @method Phaser.Cache#getSound
  60364. * @param {string} key - The key of the asset to retrieve from the cache.
  60365. * @return {Phaser.Sound} The sound object.
  60366. */
  60367. getSound: function (key) {
  60368. return this.getItem(key, Phaser.Cache.SOUND, 'getSound');
  60369. },
  60370. /**
  60371. * Gets a raw Sound data object from the cache.
  60372. *
  60373. * The object is looked-up based on the key given.
  60374. *
  60375. * Note: If the object cannot be found a `console.warn` message is displayed.
  60376. *
  60377. * @method Phaser.Cache#getSoundData
  60378. * @param {string} key - The key of the asset to retrieve from the cache.
  60379. * @return {object} The sound data.
  60380. */
  60381. getSoundData: function (key) {
  60382. return this.getItem(key, Phaser.Cache.SOUND, 'getSoundData', 'data');
  60383. },
  60384. /**
  60385. * Gets a Text object from the cache.
  60386. *
  60387. * The object is looked-up based on the key given.
  60388. *
  60389. * Note: If the object cannot be found a `console.warn` message is displayed.
  60390. *
  60391. * @method Phaser.Cache#getText
  60392. * @param {string} key - The key of the asset to retrieve from the cache.
  60393. * @return {object} The text data.
  60394. */
  60395. getText: function (key) {
  60396. return this.getItem(key, Phaser.Cache.TEXT, 'getText', 'data');
  60397. },
  60398. /**
  60399. * Gets a Physics Data object from the cache.
  60400. *
  60401. * The object is looked-up based on the key given.
  60402. *
  60403. * Note: If the object cannot be found a `console.warn` message is displayed.
  60404. *
  60405. * You can get either the entire data set, a single object or a single fixture of an object from it.
  60406. *
  60407. * @method Phaser.Cache#getPhysicsData
  60408. * @param {string} key - The key of the asset to retrieve from the cache.
  60409. * @param {string} [object=null] - If specified it will return just the physics object that is part of the given key, if null it will return them all.
  60410. * @param {string} fixtureKey - Fixture key of fixture inside an object. This key can be set per fixture with the Phaser Exporter.
  60411. * @return {object} The requested physics object data if found.
  60412. */
  60413. getPhysicsData: function (key, object, fixtureKey) {
  60414. var data = this.getItem(key, Phaser.Cache.PHYSICS, 'getPhysicsData', 'data');
  60415. if (data === null || object === undefined || object === null)
  60416. {
  60417. return data;
  60418. }
  60419. else
  60420. {
  60421. if (data[object])
  60422. {
  60423. var fixtures = data[object];
  60424. // Try to find a fixture by its fixture key if given
  60425. if (fixtures && fixtureKey)
  60426. {
  60427. for (var fixture in fixtures)
  60428. {
  60429. // This contains the fixture data of a polygon or a circle
  60430. fixture = fixtures[fixture];
  60431. // Test the key
  60432. if (fixture.fixtureKey === fixtureKey)
  60433. {
  60434. return fixture;
  60435. }
  60436. }
  60437. // We did not find the requested fixture
  60438. console.warn('Phaser.Cache.getPhysicsData: Could not find given fixtureKey: "' + fixtureKey + ' in ' + key + '"');
  60439. }
  60440. else
  60441. {
  60442. return fixtures;
  60443. }
  60444. }
  60445. else
  60446. {
  60447. console.warn('Phaser.Cache.getPhysicsData: Invalid key/object: "' + key + ' / ' + object + '"');
  60448. }
  60449. }
  60450. return null;
  60451. },
  60452. /**
  60453. * Gets a raw Tilemap data object from the cache. This will be in either CSV or JSON format.
  60454. *
  60455. * The object is looked-up based on the key given.
  60456. *
  60457. * Note: If the object cannot be found a `console.warn` message is displayed.
  60458. *
  60459. * @method Phaser.Cache#getTilemapData
  60460. * @param {string} key - The key of the asset to retrieve from the cache.
  60461. * @return {object} The raw tilemap data in CSV or JSON format.
  60462. */
  60463. getTilemapData: function (key) {
  60464. return this.getItem(key, Phaser.Cache.TILEMAP, 'getTilemapData');
  60465. },
  60466. /**
  60467. * Gets a binary object from the cache.
  60468. *
  60469. * The object is looked-up based on the key given.
  60470. *
  60471. * Note: If the object cannot be found a `console.warn` message is displayed.
  60472. *
  60473. * @method Phaser.Cache#getBinary
  60474. * @param {string} key - The key of the asset to retrieve from the cache.
  60475. * @return {object} The binary data object.
  60476. */
  60477. getBinary: function (key) {
  60478. return this.getItem(key, Phaser.Cache.BINARY, 'getBinary');
  60479. },
  60480. /**
  60481. * Gets a BitmapData object from the cache.
  60482. *
  60483. * The object is looked-up based on the key given.
  60484. *
  60485. * Note: If the object cannot be found a `console.warn` message is displayed.
  60486. *
  60487. * @method Phaser.Cache#getBitmapData
  60488. * @param {string} key - The key of the asset to retrieve from the cache.
  60489. * @return {Phaser.BitmapData} The requested BitmapData object if found, or null if not.
  60490. */
  60491. getBitmapData: function (key) {
  60492. return this.getItem(key, Phaser.Cache.BITMAPDATA, 'getBitmapData', 'data');
  60493. },
  60494. /**
  60495. * Gets a Bitmap Font object from the cache.
  60496. *
  60497. * The object is looked-up based on the key given.
  60498. *
  60499. * Note: If the object cannot be found a `console.warn` message is displayed.
  60500. *
  60501. * @method Phaser.Cache#getBitmapFont
  60502. * @param {string} key - The key of the asset to retrieve from the cache.
  60503. * @return {Phaser.BitmapFont} The requested BitmapFont object if found, or null if not.
  60504. */
  60505. getBitmapFont: function (key) {
  60506. return this.getItem(key, Phaser.Cache.BITMAPFONT, 'getBitmapFont');
  60507. },
  60508. /**
  60509. * Gets a JSON object from the cache.
  60510. *
  60511. * The object is looked-up based on the key given.
  60512. *
  60513. * Note: If the object cannot be found a `console.warn` message is displayed.
  60514. *
  60515. * You can either return the object by reference (the default), or return a clone
  60516. * of it by setting the `clone` argument to `true`.
  60517. *
  60518. * @method Phaser.Cache#getJSON
  60519. * @param {string} key - The key of the asset to retrieve from the cache.
  60520. * @param {boolean} [clone=false] - Return a clone of the original object (true) or a reference to it? (false)
  60521. * @return {object} The JSON object, or an Array if the key points to an Array property. If the property wasn't found, it returns null.
  60522. */
  60523. getJSON: function (key, clone) {
  60524. var data = this.getItem(key, Phaser.Cache.JSON, 'getJSON', 'data');
  60525. if (data)
  60526. {
  60527. if (clone)
  60528. {
  60529. return Phaser.Utils.extend(true, Array.isArray(data) ? [] : {}, data);
  60530. }
  60531. else
  60532. {
  60533. return data;
  60534. }
  60535. }
  60536. else
  60537. {
  60538. return null;
  60539. }
  60540. },
  60541. /**
  60542. * Gets an XML object from the cache.
  60543. *
  60544. * The object is looked-up based on the key given.
  60545. *
  60546. * Note: If the object cannot be found a `console.warn` message is displayed.
  60547. *
  60548. * @method Phaser.Cache#getXML
  60549. * @param {string} key - The key of the asset to retrieve from the cache.
  60550. * @return {object} The XML object.
  60551. */
  60552. getXML: function (key) {
  60553. return this.getItem(key, Phaser.Cache.XML, 'getXML', 'data');
  60554. },
  60555. /**
  60556. * Gets a Phaser.Video object from the cache.
  60557. *
  60558. * The object is looked-up based on the key given.
  60559. *
  60560. * Note: If the object cannot be found a `console.warn` message is displayed.
  60561. *
  60562. * @method Phaser.Cache#getVideo
  60563. * @param {string} key - The key of the asset to retrieve from the cache.
  60564. * @return {Phaser.Video} The video object.
  60565. */
  60566. getVideo: function (key) {
  60567. return this.getItem(key, Phaser.Cache.VIDEO, 'getVideo');
  60568. },
  60569. /**
  60570. * Gets a fragment shader object from the cache.
  60571. *
  60572. * The object is looked-up based on the key given.
  60573. *
  60574. * Note: If the object cannot be found a `console.warn` message is displayed.
  60575. *
  60576. * @method Phaser.Cache#getShader
  60577. * @param {string} key - The key of the asset to retrieve from the cache.
  60578. * @return {string} The shader object.
  60579. */
  60580. getShader: function (key) {
  60581. return this.getItem(key, Phaser.Cache.SHADER, 'getShader', 'data');
  60582. },
  60583. /**
  60584. * Gets a RenderTexture object from the cache.
  60585. *
  60586. * The object is looked-up based on the key given.
  60587. *
  60588. * Note: If the object cannot be found a `console.warn` message is displayed.
  60589. *
  60590. * @method Phaser.Cache#getRenderTexture
  60591. * @param {string} key - The key of the asset to retrieve from the cache.
  60592. * @return {Object} The object with Phaser.RenderTexture and Phaser.Frame.
  60593. */
  60594. getRenderTexture: function (key) {
  60595. return this.getItem(key, Phaser.Cache.RENDER_TEXTURE, 'getRenderTexture');
  60596. },
  60597. ////////////////////////////
  60598. // Frame Related Methods //
  60599. ////////////////////////////
  60600. /**
  60601. * Gets a PIXI.BaseTexture by key from the given Cache.
  60602. *
  60603. * @method Phaser.Cache#getBaseTexture
  60604. * @param {string} key - Asset key of the image for which you want the BaseTexture for.
  60605. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search for the item in.
  60606. * @return {PIXI.BaseTexture} The BaseTexture object.
  60607. */
  60608. getBaseTexture: function (key, cache) {
  60609. if (cache === undefined) { cache = Phaser.Cache.IMAGE; }
  60610. return this.getItem(key, cache, 'getBaseTexture', 'base');
  60611. },
  60612. /**
  60613. * Get a single frame by key. You'd only do this to get the default Frame created for a non-atlas/spritesheet image.
  60614. *
  60615. * @method Phaser.Cache#getFrame
  60616. * @param {string} key - Asset key of the frame data to retrieve from the Cache.
  60617. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search for the item in.
  60618. * @return {Phaser.Frame} The frame data.
  60619. */
  60620. getFrame: function (key, cache) {
  60621. if (cache === undefined) { cache = Phaser.Cache.IMAGE; }
  60622. return this.getItem(key, cache, 'getFrame', 'frame');
  60623. },
  60624. /**
  60625. * Get the total number of frames contained in the FrameData object specified by the given key.
  60626. *
  60627. * @method Phaser.Cache#getFrameCount
  60628. * @param {string} key - Asset key of the FrameData you want.
  60629. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search for the item in.
  60630. * @return {number} Then number of frames. 0 if the image is not found.
  60631. */
  60632. getFrameCount: function (key, cache) {
  60633. var data = this.getFrameData(key, cache);
  60634. if (data)
  60635. {
  60636. return data.total;
  60637. }
  60638. else
  60639. {
  60640. return 0;
  60641. }
  60642. },
  60643. /**
  60644. * Gets a Phaser.FrameData object from the Image Cache.
  60645. *
  60646. * The object is looked-up based on the key given.
  60647. *
  60648. * Note: If the object cannot be found a `console.warn` message is displayed.
  60649. *
  60650. * @method Phaser.Cache#getFrameData
  60651. * @param {string} key - Asset key of the frame data to retrieve from the Cache.
  60652. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search for the item in.
  60653. * @return {Phaser.FrameData} The frame data.
  60654. */
  60655. getFrameData: function (key, cache) {
  60656. if (cache === undefined) { cache = Phaser.Cache.IMAGE; }
  60657. return this.getItem(key, cache, 'getFrameData', 'frameData');
  60658. },
  60659. /**
  60660. * Check if the FrameData for the given key exists in the Image Cache.
  60661. *
  60662. * @method Phaser.Cache#hasFrameData
  60663. * @param {string} key - Asset key of the frame data to retrieve from the Cache.
  60664. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search for the item in.
  60665. * @return {boolean} True if the given key has frameData in the cache, otherwise false.
  60666. */
  60667. hasFrameData: function (key, cache) {
  60668. if (cache === undefined) { cache = Phaser.Cache.IMAGE; }
  60669. return (this.getItem(key, cache, '', 'frameData') !== null);
  60670. },
  60671. /**
  60672. * Replaces a set of frameData with a new Phaser.FrameData object.
  60673. *
  60674. * @method Phaser.Cache#updateFrameData
  60675. * @param {string} key - The unique key by which you will reference this object.
  60676. * @param {number} frameData - The new FrameData.
  60677. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search. One of the Cache consts such as `Phaser.Cache.IMAGE` or `Phaser.Cache.SOUND`.
  60678. */
  60679. updateFrameData: function (key, frameData, cache) {
  60680. if (cache === undefined) { cache = Phaser.Cache.IMAGE; }
  60681. if (this._cacheMap[cache][key])
  60682. {
  60683. this._cacheMap[cache][key].frameData = frameData;
  60684. }
  60685. },
  60686. /**
  60687. * Get a single frame out of a frameData set by key.
  60688. *
  60689. * @method Phaser.Cache#getFrameByIndex
  60690. * @param {string} key - Asset key of the frame data to retrieve from the Cache.
  60691. * @param {number} index - The index of the frame you want to get.
  60692. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search. One of the Cache consts such as `Phaser.Cache.IMAGE` or `Phaser.Cache.SOUND`.
  60693. * @return {Phaser.Frame} The frame object.
  60694. */
  60695. getFrameByIndex: function (key, index, cache) {
  60696. var data = this.getFrameData(key, cache);
  60697. if (data)
  60698. {
  60699. return data.getFrame(index);
  60700. }
  60701. else
  60702. {
  60703. return null;
  60704. }
  60705. },
  60706. /**
  60707. * Get a single frame out of a frameData set by key.
  60708. *
  60709. * @method Phaser.Cache#getFrameByName
  60710. * @param {string} key - Asset key of the frame data to retrieve from the Cache.
  60711. * @param {string} name - The name of the frame you want to get.
  60712. * @param {integer} [cache=Phaser.Cache.IMAGE] - The cache to search. One of the Cache consts such as `Phaser.Cache.IMAGE` or `Phaser.Cache.SOUND`.
  60713. * @return {Phaser.Frame} The frame object.
  60714. */
  60715. getFrameByName: function (key, name, cache) {
  60716. var data = this.getFrameData(key, cache);
  60717. if (data)
  60718. {
  60719. return data.getFrameByName(name);
  60720. }
  60721. else
  60722. {
  60723. return null;
  60724. }
  60725. },
  60726. /**
  60727. * Get a cached object by the URL.
  60728. * This only returns a value if you set Cache.autoResolveURL to `true` *before* starting the preload of any assets.
  60729. * Be aware that every call to this function makes a DOM src query, so use carefully and double-check for implications in your target browsers/devices.
  60730. *
  60731. * @method Phaser.Cache#getURL
  60732. * @param {string} url - The url for the object loaded to get from the cache.
  60733. * @return {object} The cached object.
  60734. */
  60735. getURL: function (url) {
  60736. var url = this._resolveURL(url);
  60737. if (url)
  60738. {
  60739. return this._urlMap[url];
  60740. }
  60741. else
  60742. {
  60743. console.warn('Phaser.Cache.getUrl: Invalid url: "' + url + '" or Cache.autoResolveURL was false');
  60744. return null;
  60745. }
  60746. },
  60747. /**
  60748. * Gets all keys used in the requested Cache.
  60749. *
  60750. * @method Phaser.Cache#getKeys
  60751. * @param {integer} [cache=Phaser.Cache.IMAGE] - The Cache you wish to get the keys from. Can be any of the Cache consts such as `Phaser.Cache.IMAGE`, `Phaser.Cache.SOUND` etc.
  60752. * @return {Array} The array of keys in the requested cache.
  60753. */
  60754. getKeys: function (cache) {
  60755. if (cache === undefined) { cache = Phaser.Cache.IMAGE; }
  60756. var out = [];
  60757. if (this._cacheMap[cache])
  60758. {
  60759. for (var key in this._cacheMap[cache])
  60760. {
  60761. if (key !== '__default' && key !== '__missing')
  60762. {
  60763. out.push(key);
  60764. }
  60765. }
  60766. }
  60767. return out;
  60768. },
  60769. /////////////////////
  60770. // Remove Methods //
  60771. /////////////////////
  60772. /**
  60773. * Removes a canvas from the cache.
  60774. *
  60775. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60776. * then it will persist in memory.
  60777. *
  60778. * @method Phaser.Cache#removeCanvas
  60779. * @param {string} key - Key of the asset you want to remove.
  60780. */
  60781. removeCanvas: function (key) {
  60782. delete this._cache.canvas[key];
  60783. },
  60784. /**
  60785. * Removes an image from the cache.
  60786. *
  60787. * You can optionally elect to destroy it as well. This calls BaseTexture.destroy on it.
  60788. *
  60789. * Note that this only removes it from the Phaser Cache. If you still have references to the data elsewhere
  60790. * then it will persist in memory.
  60791. *
  60792. * @method Phaser.Cache#removeImage
  60793. * @param {string} key - Key of the asset you want to remove.
  60794. * @param {boolean} [destroyBaseTexture=true] - Should the BaseTexture behind this image also be destroyed?
  60795. */
  60796. removeImage: function (key, destroyBaseTexture) {
  60797. if (destroyBaseTexture === undefined) { destroyBaseTexture = true; }
  60798. var img = this.getImage(key, true);
  60799. if (destroyBaseTexture && img.base)
  60800. {
  60801. img.base.destroy();
  60802. }
  60803. delete this._cache.image[key];
  60804. },
  60805. /**
  60806. * Removes a sound from the cache.
  60807. *
  60808. * If any `Phaser.Sound` objects use the audio file in the cache that you remove with this method, they will
  60809. * _automatically_ destroy themselves. If you wish to have full control over when Sounds are destroyed then
  60810. * you must finish your house-keeping and destroy them all yourself first, before calling this method.
  60811. *
  60812. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60813. * then it will persist in memory.
  60814. *
  60815. * @method Phaser.Cache#removeSound
  60816. * @param {string} key - Key of the asset you want to remove.
  60817. */
  60818. removeSound: function (key) {
  60819. delete this._cache.sound[key];
  60820. },
  60821. /**
  60822. * Removes a text file from the cache.
  60823. *
  60824. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60825. * then it will persist in memory.
  60826. *
  60827. * @method Phaser.Cache#removeText
  60828. * @param {string} key - Key of the asset you want to remove.
  60829. */
  60830. removeText: function (key) {
  60831. delete this._cache.text[key];
  60832. },
  60833. /**
  60834. * Removes a physics data file from the cache.
  60835. *
  60836. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60837. * then it will persist in memory.
  60838. *
  60839. * @method Phaser.Cache#removePhysics
  60840. * @param {string} key - Key of the asset you want to remove.
  60841. */
  60842. removePhysics: function (key) {
  60843. delete this._cache.physics[key];
  60844. },
  60845. /**
  60846. * Removes a tilemap from the cache.
  60847. *
  60848. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60849. * then it will persist in memory.
  60850. *
  60851. * @method Phaser.Cache#removeTilemap
  60852. * @param {string} key - Key of the asset you want to remove.
  60853. */
  60854. removeTilemap: function (key) {
  60855. delete this._cache.tilemap[key];
  60856. },
  60857. /**
  60858. * Removes a binary file from the cache.
  60859. *
  60860. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60861. * then it will persist in memory.
  60862. *
  60863. * @method Phaser.Cache#removeBinary
  60864. * @param {string} key - Key of the asset you want to remove.
  60865. */
  60866. removeBinary: function (key) {
  60867. delete this._cache.binary[key];
  60868. },
  60869. /**
  60870. * Removes a bitmap data from the cache.
  60871. *
  60872. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60873. * then it will persist in memory.
  60874. *
  60875. * @method Phaser.Cache#removeBitmapData
  60876. * @param {string} key - Key of the asset you want to remove.
  60877. */
  60878. removeBitmapData: function (key) {
  60879. delete this._cache.bitmapData[key];
  60880. },
  60881. /**
  60882. * Removes a bitmap font from the cache.
  60883. *
  60884. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60885. * then it will persist in memory.
  60886. *
  60887. * @method Phaser.Cache#removeBitmapFont
  60888. * @param {string} key - Key of the asset you want to remove.
  60889. */
  60890. removeBitmapFont: function (key) {
  60891. delete this._cache.bitmapFont[key];
  60892. },
  60893. /**
  60894. * Removes a json object from the cache.
  60895. *
  60896. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60897. * then it will persist in memory.
  60898. *
  60899. * @method Phaser.Cache#removeJSON
  60900. * @param {string} key - Key of the asset you want to remove.
  60901. */
  60902. removeJSON: function (key) {
  60903. delete this._cache.json[key];
  60904. },
  60905. /**
  60906. * Removes a xml object from the cache.
  60907. *
  60908. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60909. * then it will persist in memory.
  60910. *
  60911. * @method Phaser.Cache#removeXML
  60912. * @param {string} key - Key of the asset you want to remove.
  60913. */
  60914. removeXML: function (key) {
  60915. delete this._cache.xml[key];
  60916. },
  60917. /**
  60918. * Removes a video from the cache.
  60919. *
  60920. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60921. * then it will persist in memory.
  60922. *
  60923. * @method Phaser.Cache#removeVideo
  60924. * @param {string} key - Key of the asset you want to remove.
  60925. */
  60926. removeVideo: function (key) {
  60927. delete this._cache.video[key];
  60928. },
  60929. /**
  60930. * Removes a shader from the cache.
  60931. *
  60932. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60933. * then it will persist in memory.
  60934. *
  60935. * @method Phaser.Cache#removeShader
  60936. * @param {string} key - Key of the asset you want to remove.
  60937. */
  60938. removeShader: function (key) {
  60939. delete this._cache.shader[key];
  60940. },
  60941. /**
  60942. * Removes a Render Texture from the cache.
  60943. *
  60944. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60945. * then it will persist in memory.
  60946. *
  60947. * @method Phaser.Cache#removeRenderTexture
  60948. * @param {string} key - Key of the asset you want to remove.
  60949. */
  60950. removeRenderTexture: function (key) {
  60951. delete this._cache.renderTexture[key];
  60952. },
  60953. /**
  60954. * Removes a Sprite Sheet from the cache.
  60955. *
  60956. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60957. * then it will persist in memory.
  60958. *
  60959. * @method Phaser.Cache#removeSpriteSheet
  60960. * @param {string} key - Key of the asset you want to remove.
  60961. */
  60962. removeSpriteSheet: function (key) {
  60963. delete this._cache.spriteSheet[key];
  60964. },
  60965. /**
  60966. * Removes a Texture Atlas from the cache.
  60967. *
  60968. * Note that this only removes it from the Phaser.Cache. If you still have references to the data elsewhere
  60969. * then it will persist in memory.
  60970. *
  60971. * @method Phaser.Cache#removeTextureAtlas
  60972. * @param {string} key - Key of the asset you want to remove.
  60973. */
  60974. removeTextureAtlas: function (key) {
  60975. delete this._cache.image[key];
  60976. },
  60977. /**
  60978. * Empties out all of the GL Textures from Images stored in the cache.
  60979. * This is called automatically when the WebGL context is lost and then restored.
  60980. *
  60981. * @method Phaser.Cache#clearGLTextures
  60982. * @protected
  60983. */
  60984. clearGLTextures: function () {
  60985. for (var key in this._cache.image)
  60986. {
  60987. this._cache.image[key].base._glTextures = [];
  60988. }
  60989. },
  60990. /**
  60991. * Resolves a URL to its absolute form and stores it in Cache._urlMap as long as Cache.autoResolveURL is set to `true`.
  60992. * This is then looked-up by the Cache.getURL and Cache.checkURL calls.
  60993. *
  60994. * @method Phaser.Cache#_resolveURL
  60995. * @private
  60996. * @param {string} url - The URL to resolve. This is appended to Loader.baseURL.
  60997. * @param {object} [data] - The data associated with the URL to be stored to the URL Map.
  60998. * @return {string} The resolved URL.
  60999. */
  61000. _resolveURL: function (url, data) {
  61001. if (!this.autoResolveURL)
  61002. {
  61003. return null;
  61004. }
  61005. this._urlResolver.src = this.game.load.baseURL + url;
  61006. this._urlTemp = this._urlResolver.src;
  61007. // Ensure no request is actually made
  61008. this._urlResolver.src = '';
  61009. // Record the URL to the map
  61010. if (data)
  61011. {
  61012. this._urlMap[this._urlTemp] = data;
  61013. }
  61014. return this._urlTemp;
  61015. },
  61016. /**
  61017. * Clears the cache. Removes every local cache object reference.
  61018. * If an object in the cache has a `destroy` method it will be called;
  61019. * otherwise, `destroy` will be called on any of the object's `base`, `data`,
  61020. * `frameData`, or `texture` properties.
  61021. *
  61022. * @method Phaser.Cache#destroy
  61023. */
  61024. destroy: function () {
  61025. for (var i = 0; i < this._cacheMap.length; i++)
  61026. {
  61027. var cache = this._cacheMap[i];
  61028. for (var key in cache)
  61029. {
  61030. if (key !== '__default' && key !== '__missing')
  61031. {
  61032. this.destroyItem(cache[key]);
  61033. delete cache[key];
  61034. }
  61035. }
  61036. }
  61037. this._urlMap = null;
  61038. this._urlResolver = null;
  61039. this._urlTemp = null;
  61040. },
  61041. /**
  61042. * @method Phaser.Cache#destroyItem
  61043. * @protected
  61044. * @param {object} item
  61045. */
  61046. destroyItem: function (item) {
  61047. if (item.destroy)
  61048. {
  61049. item.destroy();
  61050. }
  61051. else
  61052. {
  61053. if (item.base && item.base.destroy)
  61054. {
  61055. item.base.destroy();
  61056. }
  61057. if (item.data && item.data.destroy)
  61058. {
  61059. item.data.destroy();
  61060. }
  61061. if (item.frameData && item.frameData.destroy)
  61062. {
  61063. item.frameData.destroy();
  61064. }
  61065. if (item.texture && item.texture.destroy)
  61066. {
  61067. item.texture.destroy(true);
  61068. }
  61069. }
  61070. },
  61071. /**
  61072. * Starts loading the DEFAULT and MISSING images.
  61073. *
  61074. * @private
  61075. */
  61076. _addImages: function () {
  61077. this._pendingCount = 0;
  61078. this.addDefaultImage();
  61079. this.addMissingImage();
  61080. var self = this;
  61081. var readyTimeout = Phaser.Cache.READY_TIMEOUT;
  61082. if (Phaser.Cache.READY_TIMEOUT > 0)
  61083. {
  61084. setTimeout(function () {
  61085. if (!self.isReady)
  61086. {
  61087. console.warn('Phaser.Cache: Still waiting for images after %s ms.', readyTimeout);
  61088. self._ready();
  61089. }
  61090. }, Phaser.Cache.READY_TIMEOUT);
  61091. }
  61092. else
  61093. {
  61094. this._ready();
  61095. }
  61096. },
  61097. /**
  61098. * Increments the pending count.
  61099. *
  61100. * @private
  61101. */
  61102. _addPending: function () {
  61103. this._pendingCount += 1;
  61104. },
  61105. /**
  61106. * Decrements the pending count and checks if complete.
  61107. *
  61108. * @private
  61109. */
  61110. _removePending: function () {
  61111. this._pendingCount -= 1;
  61112. this._checkReady();
  61113. },
  61114. /**
  61115. * Calls {@link #_ready} if no pending items remain.
  61116. *
  61117. * @private
  61118. */
  61119. _checkReady: function () {
  61120. if (this.isReady)
  61121. {
  61122. this._ready();
  61123. }
  61124. },
  61125. /**
  61126. * Resets pending count and triggers {@link #onReady}.
  61127. *
  61128. * @private
  61129. */
  61130. _ready: function () {
  61131. this._pendingCount = 0;
  61132. this.onReady.dispatch(this);
  61133. }
  61134. };
  61135. Phaser.Cache.prototype.constructor = Phaser.Cache;
  61136. /**
  61137. * The DEFAULT and MISSING textures have loaded (or the {@link #READY_TIMEOUT load timeout} was exceeded).
  61138. *
  61139. * @property {boolean} Phaser.Cache#isReady
  61140. */
  61141. Object.defineProperty(Phaser.Cache.prototype, 'isReady', {
  61142. get: function () {
  61143. return this._pendingCount <= 0;
  61144. }
  61145. });
  61146. /* jshint wsh:true */
  61147. /**
  61148. * @author Richard Davey <rich@photonstorm.com>
  61149. * @copyright 2016 Photon Storm Ltd.
  61150. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  61151. */
  61152. /**
  61153. * The Loader handles loading all external content such as Images, Sounds, Texture Atlases and data files.
  61154. *
  61155. * The loader uses a combination of tag loading (eg. Image elements) and XHR and provides progress and completion callbacks.
  61156. *
  61157. * Parallel loading (see {@link #enableParallel}) is supported and enabled by default.
  61158. * Load-before behavior of parallel resources is controlled by synchronization points as discussed in {@link #withSyncPoint}.
  61159. *
  61160. * Texture Atlases can be created with tools such as [Texture Packer](https://www.codeandweb.com/texturepacker/phaser) and
  61161. * [Shoebox](http://renderhjs.net/shoebox/)
  61162. *
  61163. * @class Phaser.Loader
  61164. * @param {Phaser.Game} game - A reference to the currently running game.
  61165. */
  61166. Phaser.Loader = function (game) {
  61167. /**
  61168. * Local reference to game.
  61169. * @property {Phaser.Game} game
  61170. * @protected
  61171. */
  61172. this.game = game;
  61173. /**
  61174. * Local reference to the Phaser.Cache.
  61175. * @property {Phaser.Cache} cache
  61176. * @protected
  61177. */
  61178. this.cache = game.cache;
  61179. /**
  61180. * If true all calls to Loader.reset will be ignored. Useful if you need to create a load queue before swapping to a preloader state.
  61181. * @property {boolean} resetLocked
  61182. * @default
  61183. */
  61184. this.resetLocked = false;
  61185. /**
  61186. * True if the Loader is in the process of loading the queue.
  61187. * @property {boolean} isLoading
  61188. * @default
  61189. */
  61190. this.isLoading = false;
  61191. /**
  61192. * True if all assets in the queue have finished loading.
  61193. * @property {boolean} hasLoaded
  61194. * @default
  61195. */
  61196. this.hasLoaded = false;
  61197. /**
  61198. * You can optionally link a progress sprite with {@link Phaser.Loader#setPreloadSprite setPreloadSprite}.
  61199. *
  61200. * This property is an object containing: sprite, rect, direction, width and height
  61201. *
  61202. * @property {?object} preloadSprite
  61203. * @protected
  61204. */
  61205. this.preloadSprite = null;
  61206. /**
  61207. * The crossOrigin value applied to loaded images. Very often this needs to be set to 'anonymous'.
  61208. * @property {boolean|string} crossOrigin
  61209. * @default
  61210. */
  61211. this.crossOrigin = false;
  61212. /**
  61213. * If you want to append a URL before the path of any asset you can set this here.
  61214. * Useful if allowing the asset base url to be configured outside of the game code.
  61215. * The string _must_ end with a "/".
  61216. *
  61217. * @property {string} baseURL
  61218. */
  61219. this.baseURL = '';
  61220. /**
  61221. * The value of `path`, if set, is placed before any _relative_ file path given. For example:
  61222. *
  61223. * `load.path = "images/sprites/";
  61224. * load.image("ball", "ball.png");
  61225. * load.image("tree", "level1/oaktree.png");
  61226. * load.image("boom", "http://server.com/explode.png");`
  61227. *
  61228. * Would load the `ball` file from `images/sprites/ball.png` and the tree from
  61229. * `images/sprites/level1/oaktree.png` but the file `boom` would load from the URL
  61230. * given as it's an absolute URL.
  61231. *
  61232. * Please note that the path is added before the filename but *after* the baseURL (if set.)
  61233. *
  61234. * The string _must_ end with a "/".
  61235. *
  61236. * @property {string} path
  61237. */
  61238. this.path = '';
  61239. /**
  61240. * Used to map the application mime-types to to the Accept header in XHR requests.
  61241. * If you don't require these mappings, or they cause problems on your server, then
  61242. * remove them from the headers object and the XHR request will not try to use them.
  61243. *
  61244. * This object can also be used to set the `X-Requested-With` header to
  61245. * `XMLHttpRequest` (or any other value you need). To enable this do:
  61246. *
  61247. * `this.load.headers.requestedWith = 'XMLHttpRequest'`
  61248. *
  61249. * before adding anything to the Loader. The XHR loader will then call:
  61250. *
  61251. * `setRequestHeader('X-Requested-With', this.headers['requestedWith'])`
  61252. *
  61253. * @property {object} headers
  61254. * @default
  61255. */
  61256. this.headers = {
  61257. "requestedWith": false,
  61258. "json": "application/json",
  61259. "xml": "application/xml"
  61260. };
  61261. /**
  61262. * This event is dispatched when the loading process starts: before the first file has been requested,
  61263. * but after all the initial packs have been loaded.
  61264. *
  61265. * @property {Phaser.Signal} onLoadStart
  61266. */
  61267. this.onLoadStart = new Phaser.Signal();
  61268. /**
  61269. * This event is dispatched when the final file in the load queue has either loaded or failed.
  61270. *
  61271. * @property {Phaser.Signal} onLoadComplete
  61272. */
  61273. this.onLoadComplete = new Phaser.Signal();
  61274. /**
  61275. * This event is dispatched when an asset pack has either loaded or failed to load.
  61276. *
  61277. * This is called when the asset pack manifest file has loaded and successfully added its contents to the loader queue.
  61278. *
  61279. * Params: `(pack key, success?, total packs loaded, total packs)`
  61280. *
  61281. * @property {Phaser.Signal} onPackComplete
  61282. */
  61283. this.onPackComplete = new Phaser.Signal();
  61284. /**
  61285. * This event is dispatched immediately before a file starts loading.
  61286. * It's possible the file may fail (eg. download error, invalid format) after this event is sent.
  61287. *
  61288. * Params: `(progress, file key, file url)`
  61289. *
  61290. * @property {Phaser.Signal} onFileStart
  61291. */
  61292. this.onFileStart = new Phaser.Signal();
  61293. /**
  61294. * This event is dispatched when a file has either loaded or failed to load.
  61295. *
  61296. * Any function bound to this will receive the following parameters:
  61297. *
  61298. * progress, file key, success?, total loaded files, total files
  61299. *
  61300. * Where progress is a number between 1 and 100 (inclusive) representing the percentage of the load.
  61301. *
  61302. * @property {Phaser.Signal} onFileComplete
  61303. */
  61304. this.onFileComplete = new Phaser.Signal();
  61305. /**
  61306. * This event is dispatched when a file (or pack) errors as a result of the load request.
  61307. *
  61308. * For files it will be triggered before `onFileComplete`. For packs it will be triggered before `onPackComplete`.
  61309. *
  61310. * Params: `(file key, file)`
  61311. *
  61312. * @property {Phaser.Signal} onFileError
  61313. */
  61314. this.onFileError = new Phaser.Signal();
  61315. /**
  61316. * If true and if the browser supports XDomainRequest, it will be used in preference for XHR.
  61317. *
  61318. * This is only relevant for IE 9 and should _only_ be enabled for IE 9 clients when required by the server/CDN.
  61319. *
  61320. * @property {boolean} useXDomainRequest
  61321. * @deprecated This is only relevant for IE 9.
  61322. */
  61323. this.useXDomainRequest = false;
  61324. /**
  61325. * @private
  61326. * @property {boolean} _warnedAboutXDomainRequest - Control number of warnings for using XDR outside of IE 9.
  61327. */
  61328. this._warnedAboutXDomainRequest = false;
  61329. /**
  61330. * If true (the default) then parallel downloading will be enabled.
  61331. *
  61332. * To disable all parallel downloads this must be set to false prior to any resource being loaded.
  61333. *
  61334. * @property {boolean} enableParallel
  61335. */
  61336. this.enableParallel = true;
  61337. /**
  61338. * The number of concurrent / parallel resources to try and fetch at once.
  61339. *
  61340. * Many current browsers limit 6 requests per domain; this is slightly conservative.
  61341. *
  61342. * This should generally be left at the default, but can be set to a higher limit for specific use-cases. Just be careful when setting large values as different browsers could behave differently.
  61343. *
  61344. * @property {integer} maxParallelDownloads
  61345. */
  61346. this.maxParallelDownloads = 4;
  61347. /**
  61348. * A counter: if more than zero, files will be automatically added as a synchronization point.
  61349. * @property {integer} _withSyncPointDepth;
  61350. */
  61351. this._withSyncPointDepth = 0;
  61352. /**
  61353. * Contains all the information for asset files (including packs) to load.
  61354. *
  61355. * File/assets are only removed from the list after all loading completes.
  61356. *
  61357. * @property {file[]} _fileList
  61358. * @private
  61359. */
  61360. this._fileList = [];
  61361. /**
  61362. * Inflight files (or packs) that are being fetched/processed.
  61363. *
  61364. * This means that if there are any files in the flight queue there should still be processing
  61365. * going on; it should only be empty before or after loading.
  61366. *
  61367. * The files in the queue may have additional properties added to them,
  61368. * including `requestObject` which is normally the associated XHR.
  61369. *
  61370. * @property {file[]} _flightQueue
  61371. * @private
  61372. */
  61373. this._flightQueue = [];
  61374. /**
  61375. * The offset into the fileList past all the complete (loaded or error) entries.
  61376. *
  61377. * @property {integer} _processingHead
  61378. * @private
  61379. */
  61380. this._processingHead = 0;
  61381. /**
  61382. * True when the first file (not pack) has loading started.
  61383. * This used to to control dispatching `onLoadStart` which happens after any initial packs are loaded.
  61384. *
  61385. * @property {boolean} _initialPacksLoaded
  61386. * @private
  61387. */
  61388. this._fileLoadStarted = false;
  61389. /**
  61390. * Total packs seen - adjusted when a pack is added.
  61391. * @property {integer} _totalPackCount
  61392. * @private
  61393. */
  61394. this._totalPackCount = 0;
  61395. /**
  61396. * Total files seen - adjusted when a file is added.
  61397. * @property {integer} _totalFileCount
  61398. * @private
  61399. */
  61400. this._totalFileCount = 0;
  61401. /**
  61402. * Total packs loaded - adjusted just prior to `onPackComplete`.
  61403. * @property {integer} _loadedPackCount
  61404. * @private
  61405. */
  61406. this._loadedPackCount = 0;
  61407. /**
  61408. * Total files loaded - adjusted just prior to `onFileComplete`.
  61409. * @property {integer} _loadedFileCount
  61410. * @private
  61411. */
  61412. this._loadedFileCount = 0;
  61413. };
  61414. /**
  61415. * @constant
  61416. * @type {number}
  61417. */
  61418. Phaser.Loader.TEXTURE_ATLAS_JSON_ARRAY = 0;
  61419. /**
  61420. * @constant
  61421. * @type {number}
  61422. */
  61423. Phaser.Loader.TEXTURE_ATLAS_JSON_HASH = 1;
  61424. /**
  61425. * @constant
  61426. * @type {number}
  61427. */
  61428. Phaser.Loader.TEXTURE_ATLAS_XML_STARLING = 2;
  61429. /**
  61430. * @constant
  61431. * @type {number}
  61432. */
  61433. Phaser.Loader.PHYSICS_LIME_CORONA_JSON = 3;
  61434. /**
  61435. * @constant
  61436. * @type {number}
  61437. */
  61438. Phaser.Loader.PHYSICS_PHASER_JSON = 4;
  61439. /**
  61440. * @constant
  61441. * @type {number}
  61442. */
  61443. Phaser.Loader.TEXTURE_ATLAS_JSON_PYXEL = 5;
  61444. Phaser.Loader.prototype = {
  61445. /**
  61446. * Set a Sprite to be a "preload" sprite by passing it to this method.
  61447. *
  61448. * A "preload" sprite will have its width or height crop adjusted based on the percentage of the loader in real-time.
  61449. * This allows you to easily make loading bars for games.
  61450. *
  61451. * The sprite will automatically be made visible when calling this.
  61452. *
  61453. * @method Phaser.Loader#setPreloadSprite
  61454. * @param {Phaser.Sprite|Phaser.Image} sprite - The sprite or image that will be cropped during the load.
  61455. * @param {number} [direction=0] - A value of zero means the sprite will be cropped horizontally, a value of 1 means its will be cropped vertically.
  61456. */
  61457. setPreloadSprite: function (sprite, direction) {
  61458. direction = direction || 0;
  61459. this.preloadSprite = { sprite: sprite, direction: direction, width: sprite.width, height: sprite.height, rect: null };
  61460. if (direction === 0)
  61461. {
  61462. // Horizontal rect
  61463. this.preloadSprite.rect = new Phaser.Rectangle(0, 0, 1, sprite.height);
  61464. }
  61465. else
  61466. {
  61467. // Vertical rect
  61468. this.preloadSprite.rect = new Phaser.Rectangle(0, 0, sprite.width, 1);
  61469. }
  61470. sprite.crop(this.preloadSprite.rect);
  61471. sprite.visible = true;
  61472. },
  61473. /**
  61474. * Called automatically by ScaleManager when the game resizes in RESIZE scalemode.
  61475. *
  61476. * This can be used to adjust the preloading sprite size, eg.
  61477. *
  61478. * @method Phaser.Loader#resize
  61479. * @protected
  61480. */
  61481. resize: function () {
  61482. if (this.preloadSprite && this.preloadSprite.height !== this.preloadSprite.sprite.height)
  61483. {
  61484. this.preloadSprite.rect.height = this.preloadSprite.sprite.height;
  61485. }
  61486. },
  61487. /**
  61488. * Check whether a file/asset with a specific key is queued to be loaded.
  61489. *
  61490. * To access a loaded asset use Phaser.Cache, eg. {@link Phaser.Cache#checkImageKey}
  61491. *
  61492. * @method Phaser.Loader#checkKeyExists
  61493. * @param {string} type - The type asset you want to check.
  61494. * @param {string} key - Key of the asset you want to check.
  61495. * @return {boolean} Return true if exists, otherwise return false.
  61496. */
  61497. checkKeyExists: function (type, key) {
  61498. return this.getAssetIndex(type, key) > -1;
  61499. },
  61500. /**
  61501. * Get the queue-index of the file/asset with a specific key.
  61502. *
  61503. * Only assets in the download file queue will be found.
  61504. *
  61505. * @method Phaser.Loader#getAssetIndex
  61506. * @param {string} type - The type asset you want to check.
  61507. * @param {string} key - Key of the asset you want to check.
  61508. * @return {number} The index of this key in the filelist, or -1 if not found.
  61509. * The index may change and should only be used immediately following this call
  61510. */
  61511. getAssetIndex: function (type, key) {
  61512. var bestFound = -1;
  61513. for (var i = 0; i < this._fileList.length; i++)
  61514. {
  61515. var file = this._fileList[i];
  61516. if (file.type === type && file.key === key)
  61517. {
  61518. bestFound = i;
  61519. // An already loaded/loading file may be superceded.
  61520. if (!file.loaded && !file.loading)
  61521. {
  61522. break;
  61523. }
  61524. }
  61525. }
  61526. return bestFound;
  61527. },
  61528. /**
  61529. * Find a file/asset with a specific key.
  61530. *
  61531. * Only assets in the download file queue will be found.
  61532. *
  61533. * @method Phaser.Loader#getAsset
  61534. * @param {string} type - The type asset you want to check.
  61535. * @param {string} key - Key of the asset you want to check.
  61536. * @return {any} Returns an object if found that has 2 properties: `index` and `file`; otherwise a non-true value is returned.
  61537. * The index may change and should only be used immediately following this call.
  61538. */
  61539. getAsset: function (type, key) {
  61540. var fileIndex = this.getAssetIndex(type, key);
  61541. if (fileIndex > -1)
  61542. {
  61543. return { index: fileIndex, file: this._fileList[fileIndex] };
  61544. }
  61545. return false;
  61546. },
  61547. /**
  61548. * Reset the loader and clear any queued assets. If `Loader.resetLocked` is true this operation will abort.
  61549. *
  61550. * This will abort any loading and clear any queued assets.
  61551. *
  61552. * Optionally you can clear any associated events.
  61553. *
  61554. * @method Phaser.Loader#reset
  61555. * @protected
  61556. * @param {boolean} [hard=false] - If true then the preload sprite and other artifacts may also be cleared.
  61557. * @param {boolean} [clearEvents=false] - If true then the all Loader signals will have removeAll called on them.
  61558. */
  61559. reset: function (hard, clearEvents) {
  61560. if (clearEvents === undefined) { clearEvents = false; }
  61561. if (this.resetLocked)
  61562. {
  61563. return;
  61564. }
  61565. if (hard)
  61566. {
  61567. this.preloadSprite = null;
  61568. }
  61569. this.isLoading = false;
  61570. this._processingHead = 0;
  61571. this._fileList.length = 0;
  61572. this._flightQueue.length = 0;
  61573. this._fileLoadStarted = false;
  61574. this._totalFileCount = 0;
  61575. this._totalPackCount = 0;
  61576. this._loadedPackCount = 0;
  61577. this._loadedFileCount = 0;
  61578. if (clearEvents)
  61579. {
  61580. this.onLoadStart.removeAll();
  61581. this.onLoadComplete.removeAll();
  61582. this.onPackComplete.removeAll();
  61583. this.onFileStart.removeAll();
  61584. this.onFileComplete.removeAll();
  61585. this.onFileError.removeAll();
  61586. }
  61587. },
  61588. /**
  61589. * Internal function that adds a new entry to the file list. Do not call directly.
  61590. *
  61591. * @method Phaser.Loader#addToFileList
  61592. * @protected
  61593. * @param {string} type - The type of resource to add to the list (image, audio, xml, etc).
  61594. * @param {string} key - The unique Cache ID key of this resource.
  61595. * @param {string} [url] - The URL the asset will be loaded from.
  61596. * @param {object} [properties=(none)] - Any additional properties needed to load the file. These are added directly to the added file object and overwrite any defaults.
  61597. * @param {boolean} [overwrite=false] - If true then this will overwrite a file asset of the same type/key. Otherwise it will only add a new asset. If overwrite is true, and the asset is already being loaded (or has been loaded), then it is appended instead.
  61598. * @param {string} [extension] - If no URL is given the Loader will sometimes auto-generate the URL based on the key, using this as the extension.
  61599. * @return {Phaser.Loader} This instance of the Phaser Loader.
  61600. */
  61601. addToFileList: function (type, key, url, properties, overwrite, extension) {
  61602. if (overwrite === undefined) { overwrite = false; }
  61603. if (key === undefined || key === '')
  61604. {
  61605. console.warn("Phaser.Loader: Invalid or no key given of type " + type);
  61606. return this;
  61607. }
  61608. if (url === undefined || url === null)
  61609. {
  61610. if (extension)
  61611. {
  61612. url = key + extension;
  61613. }
  61614. else
  61615. {
  61616. console.warn("Phaser.Loader: No URL given for file type: " + type + " key: " + key);
  61617. return this;
  61618. }
  61619. }
  61620. var file = {
  61621. type: type,
  61622. key: key,
  61623. path: this.path,
  61624. url: url,
  61625. syncPoint: this._withSyncPointDepth > 0,
  61626. data: null,
  61627. loading: false,
  61628. loaded: false,
  61629. error: false
  61630. };
  61631. if (properties)
  61632. {
  61633. for (var prop in properties)
  61634. {
  61635. file[prop] = properties[prop];
  61636. }
  61637. }
  61638. var fileIndex = this.getAssetIndex(type, key);
  61639. if (overwrite && fileIndex > -1)
  61640. {
  61641. var currentFile = this._fileList[fileIndex];
  61642. if (!currentFile.loading && !currentFile.loaded)
  61643. {
  61644. this._fileList[fileIndex] = file;
  61645. }
  61646. else
  61647. {
  61648. this._fileList.push(file);
  61649. this._totalFileCount++;
  61650. }
  61651. }
  61652. else if (fileIndex === -1)
  61653. {
  61654. this._fileList.push(file);
  61655. this._totalFileCount++;
  61656. }
  61657. return this;
  61658. },
  61659. /**
  61660. * Internal function that replaces an existing entry in the file list with a new one. Do not call directly.
  61661. *
  61662. * @method Phaser.Loader#replaceInFileList
  61663. * @protected
  61664. * @param {string} type - The type of resource to add to the list (image, audio, xml, etc).
  61665. * @param {string} key - The unique Cache ID key of this resource.
  61666. * @param {string} url - The URL the asset will be loaded from.
  61667. * @param {object} properties - Any additional properties needed to load the file.
  61668. */
  61669. replaceInFileList: function (type, key, url, properties) {
  61670. return this.addToFileList(type, key, url, properties, true);
  61671. },
  61672. /**
  61673. * Add a JSON resource pack ('packfile') to the Loader.
  61674. *
  61675. * A packfile is a JSON file that contains a list of assets to the be loaded.
  61676. * Please see the example 'loader/asset pack' in the Phaser Examples repository.
  61677. *
  61678. * Packs are always put before the first non-pack file that is not loaded / loading.
  61679. *
  61680. * This means that all packs added before any loading has started are added to the front
  61681. * of the file queue, in the order added.
  61682. *
  61683. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  61684. *
  61685. * The URL of the packfile can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  61686. *
  61687. * @method Phaser.Loader#pack
  61688. * @param {string} key - Unique asset key of this resource pack.
  61689. * @param {string} [url] - URL of the Asset Pack JSON file. If you wish to pass a json object instead set this to null and pass the object as the data parameter.
  61690. * @param {object} [data] - The Asset Pack JSON data. Use this to pass in a json data object rather than loading it from a URL. TODO
  61691. * @param {object} [callbackContext=(loader)] - Some Loader operations, like Binary and Script require a context for their callbacks. Pass the context here.
  61692. * @return {Phaser.Loader} This Loader instance.
  61693. */
  61694. pack: function (key, url, data, callbackContext) {
  61695. if (url === undefined) { url = null; }
  61696. if (data === undefined) { data = null; }
  61697. if (callbackContext === undefined) { callbackContext = null; }
  61698. if (!url && !data)
  61699. {
  61700. console.warn('Phaser.Loader.pack - Both url and data are null. One must be set.');
  61701. return this;
  61702. }
  61703. var pack = {
  61704. type: 'packfile',
  61705. key: key,
  61706. url: url,
  61707. path: this.path,
  61708. syncPoint: true,
  61709. data: null,
  61710. loading: false,
  61711. loaded: false,
  61712. error: false,
  61713. callbackContext: callbackContext
  61714. };
  61715. // A data object has been given
  61716. if (data)
  61717. {
  61718. if (typeof data === 'string')
  61719. {
  61720. data = JSON.parse(data);
  61721. }
  61722. pack.data = data || {};
  61723. // Already consider 'loaded'
  61724. pack.loaded = true;
  61725. }
  61726. // Add before first non-pack/no-loaded ~ last pack from start prior to loading
  61727. // (Read one past for splice-to-end)
  61728. for (var i = 0; i < this._fileList.length + 1; i++)
  61729. {
  61730. var file = this._fileList[i];
  61731. if (!file || (!file.loaded && !file.loading && file.type !== 'packfile'))
  61732. {
  61733. this._fileList.splice(i, 0, pack);
  61734. this._totalPackCount++;
  61735. break;
  61736. }
  61737. }
  61738. return this;
  61739. },
  61740. /**
  61741. * Adds an Image to the current load queue.
  61742. *
  61743. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  61744. *
  61745. * Phaser can load all common image types: png, jpg, gif and any other format the browser can natively handle.
  61746. *
  61747. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  61748. *
  61749. * Retrieve the image via `Cache.getImage(key)`
  61750. *
  61751. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  61752. *
  61753. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  61754. * and no URL is given then the Loader will set the URL to be "alien.png". It will always add `.png` as the extension.
  61755. * If you do not desire this action then provide a URL.
  61756. *
  61757. * This method also supports passing in a texture object as the `url` argument. This allows you to load
  61758. * compressed textures into Phaser. You can also use `Loader.texture` to do this.
  61759. *
  61760. * Compressed Textures are a WebGL only feature, and require 3rd party tools to create.
  61761. * Available tools include Texture Packer, PVRTexTool, DirectX Texture Tool and Mali Texture Compression Tool.
  61762. *
  61763. * Supported texture compression formats are: PVRTC, S3TC and ETC1.
  61764. * Supported file formats are: PVR, DDS, KTX and PKM.
  61765. *
  61766. * The formats that support all 3 compression algorithms are PVR and KTX.
  61767. * PKM only supports ETC1, and DDS only S3TC for now.
  61768. *
  61769. * The texture path object looks like this:
  61770. *
  61771. * ```javascript
  61772. * load.image('factory', {
  61773. * etc1: 'assets/factory_etc1.pkm',
  61774. * s3tc: 'assets/factory_dxt1.pvr',
  61775. * pvrtc: 'assets/factory_pvrtc.pvr',
  61776. * truecolor: 'assets/factory.png'
  61777. * });
  61778. * ```
  61779. *
  61780. * The `truecolor` property points to a standard PNG file, that will be used if none of the
  61781. * compressed formats are supported by the browser / GPU.
  61782. *
  61783. * @method Phaser.Loader#image
  61784. * @param {string} key - Unique asset key of this image file.
  61785. * @param {string|object} [url] - URL of an image file. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png". Can also be a texture data object.
  61786. * @param {boolean} [overwrite=false] - If an unloaded file with a matching key already exists in the queue, this entry will overwrite it.
  61787. * @return {Phaser.Loader} This Loader instance.
  61788. */
  61789. image: function (key, url, overwrite) {
  61790. if (typeof url === 'object')
  61791. {
  61792. return this.texture(key, url, overwrite);
  61793. }
  61794. else
  61795. {
  61796. return this.addToFileList('image', key, url, undefined, overwrite, '.png');
  61797. }
  61798. },
  61799. /**
  61800. * Generate an image from a BitmapData object and add it to the current load queue.
  61801. *
  61802. * @method Phaser.Loader#imageFromBitmapData
  61803. * @param {string} key - Unique asset key for the generated image.
  61804. * @param {Phaser.BitmapData} bitmapData
  61805. * @param {boolean} [overwrite=false] - If an unloaded file with a matching key already exists in the queue, this entry will overwrite it.
  61806. * @return {Phaser.Loader} This Loader instance.
  61807. */
  61808. imageFromBitmapData: function (key, bitmapData, overwrite) {
  61809. return this.image(key, bitmapData.canvas.toDataURL('image/png'), overwrite);
  61810. },
  61811. /**
  61812. * Adds a Compressed Texture Image to the current load queue.
  61813. *
  61814. * Compressed Textures are a WebGL only feature, and require 3rd party tools to create.
  61815. * Available tools include Texture Packer, PVRTexTool, DirectX Texture Tool and Mali Texture Compression Tool.
  61816. *
  61817. * Supported texture compression formats are: PVRTC, S3TC and ETC1.
  61818. * Supported file formats are: PVR, DDS, KTX and PKM.
  61819. *
  61820. * The formats that support all 3 compression algorithms are PVR and KTX.
  61821. * PKM only supports ETC1, and DDS only S3TC for now.
  61822. *
  61823. * The texture path object looks like this:
  61824. *
  61825. * ```javascript
  61826. * load.texture('factory', {
  61827. * etc1: 'assets/factory_etc1.pkm',
  61828. * s3tc: 'assets/factory_dxt1.pvr',
  61829. * pvrtc: 'assets/factory_pvrtc.pvr',
  61830. * truecolor: 'assets/factory.png'
  61831. * });
  61832. * ```
  61833. *
  61834. * The `truecolor` property points to a standard PNG file, that will be used if none of the
  61835. * compressed formats are supported by the browser / GPU.
  61836. *
  61837. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  61838. *
  61839. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  61840. *
  61841. * Retrieve the image via `Cache.getImage(key)`
  61842. *
  61843. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  61844. *
  61845. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  61846. * and no URL is given then the Loader will set the URL to be "alien.pvr". It will always add `.pvr` as the extension.
  61847. * If you do not desire this action then provide a URL.
  61848. *
  61849. * @method Phaser.Loader#texture
  61850. * @param {string} key - Unique asset key of this image file.
  61851. * @param {object} object - The texture path data object.
  61852. * @param {boolean} [overwrite=false] - If an unloaded file with a matching key already exists in the queue, this entry will overwrite it.
  61853. * @return {Phaser.Loader} This Loader instance.
  61854. */
  61855. texture: function (key, object, overwrite) {
  61856. if (this.game.renderType === Phaser.WEBGL)
  61857. {
  61858. var compression = this.game.renderer.extensions.compression;
  61859. var exkey;
  61860. for (exkey in object)
  61861. {
  61862. if (exkey.toUpperCase() in compression)
  61863. {
  61864. return this.addToFileList('texture', key, object[exkey], undefined, overwrite, '.pvr');
  61865. }
  61866. }
  61867. }
  61868. // Check if we have a truecolor texture to fallback.
  61869. // Also catches calls to this function that are from a Canvas renderer
  61870. if (object['truecolor'])
  61871. {
  61872. this.addToFileList('image', key, object['truecolor'], undefined, overwrite, '.png');
  61873. }
  61874. return this;
  61875. },
  61876. /**
  61877. * Adds an array of images to the current load queue.
  61878. *
  61879. * It works by passing each element of the array to the Loader.image method.
  61880. *
  61881. * The files are **not** loaded immediately after calling this method. The files are added to the queue ready to be loaded when the loader starts.
  61882. *
  61883. * Phaser can load all common image types: png, jpg, gif and any other format the browser can natively handle.
  61884. *
  61885. * The keys must be unique Strings. They are used to add the files to the Phaser.Cache upon successful load.
  61886. *
  61887. * Retrieve the images via `Cache.getImage(key)`
  61888. *
  61889. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  61890. *
  61891. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  61892. * and no URL is given then the Loader will set the URL to be "alien.png". It will always add `.png` as the extension.
  61893. * If you do not desire this action then provide a URL.
  61894. *
  61895. * @method Phaser.Loader#images
  61896. * @param {array} keys - An array of unique asset keys of the image files.
  61897. * @param {array} [urls] - Optional array of URLs. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png". If provided the URLs array length must match the keys array length.
  61898. * @return {Phaser.Loader} This Loader instance.
  61899. */
  61900. images: function (keys, urls) {
  61901. if (Array.isArray(urls))
  61902. {
  61903. for (var i = 0; i < keys.length; i++)
  61904. {
  61905. this.image(keys[i], urls[i]);
  61906. }
  61907. }
  61908. else
  61909. {
  61910. for (var i = 0; i < keys.length; i++)
  61911. {
  61912. this.image(keys[i]);
  61913. }
  61914. }
  61915. return this;
  61916. },
  61917. /**
  61918. * Adds a Text file to the current load queue.
  61919. *
  61920. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  61921. *
  61922. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  61923. *
  61924. * Retrieve the file via `Cache.getText(key)`
  61925. *
  61926. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  61927. *
  61928. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  61929. * and no URL is given then the Loader will set the URL to be "alien.txt". It will always add `.txt` as the extension.
  61930. * If you do not desire this action then provide a URL.
  61931. *
  61932. * @method Phaser.Loader#text
  61933. * @param {string} key - Unique asset key of the text file.
  61934. * @param {string} [url] - URL of the text file. If undefined or `null` the url will be set to `<key>.txt`, i.e. if `key` was "alien" then the URL will be "alien.txt".
  61935. * @param {boolean} [overwrite=false] - If an unloaded file with a matching key already exists in the queue, this entry will overwrite it.
  61936. * @return {Phaser.Loader} This Loader instance.
  61937. */
  61938. text: function (key, url, overwrite) {
  61939. return this.addToFileList('text', key, url, undefined, overwrite, '.txt');
  61940. },
  61941. /**
  61942. * Adds a JSON file to the current load queue.
  61943. *
  61944. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  61945. *
  61946. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  61947. *
  61948. * Retrieve the file via `Cache.getJSON(key)`. JSON files are automatically parsed upon load.
  61949. * If you need to control when the JSON is parsed then use `Loader.text` instead and parse the text file as needed.
  61950. *
  61951. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  61952. *
  61953. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  61954. * and no URL is given then the Loader will set the URL to be "alien.json". It will always add `.json` as the extension.
  61955. * If you do not desire this action then provide a URL.
  61956. *
  61957. * @method Phaser.Loader#json
  61958. * @param {string} key - Unique asset key of the json file.
  61959. * @param {string} [url] - URL of the JSON file. If undefined or `null` the url will be set to `<key>.json`, i.e. if `key` was "alien" then the URL will be "alien.json".
  61960. * @param {boolean} [overwrite=false] - If an unloaded file with a matching key already exists in the queue, this entry will overwrite it.
  61961. * @return {Phaser.Loader} This Loader instance.
  61962. */
  61963. json: function (key, url, overwrite) {
  61964. return this.addToFileList('json', key, url, undefined, overwrite, '.json');
  61965. },
  61966. /**
  61967. * Adds a fragment shader file to the current load queue.
  61968. *
  61969. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  61970. *
  61971. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  61972. *
  61973. * Retrieve the file via `Cache.getShader(key)`.
  61974. *
  61975. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  61976. *
  61977. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "blur"
  61978. * and no URL is given then the Loader will set the URL to be "blur.frag". It will always add `.frag` as the extension.
  61979. * If you do not desire this action then provide a URL.
  61980. *
  61981. * @method Phaser.Loader#shader
  61982. * @param {string} key - Unique asset key of the fragment file.
  61983. * @param {string} [url] - URL of the fragment file. If undefined or `null` the url will be set to `<key>.frag`, i.e. if `key` was "blur" then the URL will be "blur.frag".
  61984. * @param {boolean} [overwrite=false] - If an unloaded file with a matching key already exists in the queue, this entry will overwrite it.
  61985. * @return {Phaser.Loader} This Loader instance.
  61986. */
  61987. shader: function (key, url, overwrite) {
  61988. return this.addToFileList('shader', key, url, undefined, overwrite, '.frag');
  61989. },
  61990. /**
  61991. * Adds an XML file to the current load queue.
  61992. *
  61993. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  61994. *
  61995. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  61996. *
  61997. * Retrieve the file via `Cache.getXML(key)`.
  61998. *
  61999. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62000. *
  62001. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  62002. * and no URL is given then the Loader will set the URL to be "alien.xml". It will always add `.xml` as the extension.
  62003. * If you do not desire this action then provide a URL.
  62004. *
  62005. * @method Phaser.Loader#xml
  62006. * @param {string} key - Unique asset key of the xml file.
  62007. * @param {string} [url] - URL of the XML file. If undefined or `null` the url will be set to `<key>.xml`, i.e. if `key` was "alien" then the URL will be "alien.xml".
  62008. * @param {boolean} [overwrite=false] - If an unloaded file with a matching key already exists in the queue, this entry will overwrite it.
  62009. * @return {Phaser.Loader} This Loader instance.
  62010. */
  62011. xml: function (key, url, overwrite) {
  62012. return this.addToFileList('xml', key, url, undefined, overwrite, '.xml');
  62013. },
  62014. /**
  62015. * Adds a JavaScript file to the current load queue.
  62016. *
  62017. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  62018. *
  62019. * The key must be a unique String.
  62020. *
  62021. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62022. *
  62023. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  62024. * and no URL is given then the Loader will set the URL to be "alien.js". It will always add `.js` as the extension.
  62025. * If you do not desire this action then provide a URL.
  62026. *
  62027. * Upon successful load the JavaScript is automatically turned into a script tag and executed, so be careful what you load!
  62028. *
  62029. * A callback, which will be invoked as the script tag has been created, can also be specified.
  62030. * The callback must return relevant `data`.
  62031. *
  62032. * @method Phaser.Loader#script
  62033. * @param {string} key - Unique asset key of the script file.
  62034. * @param {string} [url] - URL of the JavaScript file. If undefined or `null` the url will be set to `<key>.js`, i.e. if `key` was "alien" then the URL will be "alien.js".
  62035. * @param {function} [callback=(none)] - Optional callback that will be called after the script tag has loaded, so you can perform additional processing.
  62036. * @param {object} [callbackContext=(loader)] - The context under which the callback will be applied. If not specified it will use the Phaser Loader as the context.
  62037. * @return {Phaser.Loader} This Loader instance.
  62038. */
  62039. script: function (key, url, callback, callbackContext) {
  62040. if (callback === undefined) { callback = false; }
  62041. if (callback !== false && callbackContext === undefined) { callbackContext = this; }
  62042. return this.addToFileList('script', key, url, { syncPoint: true, callback: callback, callbackContext: callbackContext }, false, '.js');
  62043. },
  62044. /**
  62045. * Adds a binary file to the current load queue.
  62046. *
  62047. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  62048. *
  62049. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62050. *
  62051. * Retrieve the file via `Cache.getBinary(key)`.
  62052. *
  62053. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62054. *
  62055. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  62056. * and no URL is given then the Loader will set the URL to be "alien.bin". It will always add `.bin` as the extension.
  62057. * If you do not desire this action then provide a URL.
  62058. *
  62059. * It will be loaded via xhr with a responseType of "arraybuffer". You can specify an optional callback to process the file after load.
  62060. * When the callback is called it will be passed 2 parameters: the key of the file and the file data.
  62061. *
  62062. * WARNING: If a callback is specified the data will be set to whatever it returns. Always return the data object, even if you didn't modify it.
  62063. *
  62064. * @method Phaser.Loader#binary
  62065. * @param {string} key - Unique asset key of the binary file.
  62066. * @param {string} [url] - URL of the binary file. If undefined or `null` the url will be set to `<key>.bin`, i.e. if `key` was "alien" then the URL will be "alien.bin".
  62067. * @param {function} [callback=(none)] - Optional callback that will be passed the file after loading, so you can perform additional processing on it.
  62068. * @param {object} [callbackContext] - The context under which the callback will be applied. If not specified it will use the callback itself as the context.
  62069. * @return {Phaser.Loader} This Loader instance.
  62070. */
  62071. binary: function (key, url, callback, callbackContext) {
  62072. if (callback === undefined) { callback = false; }
  62073. // Why is the default callback context the ..callback?
  62074. if (callback !== false && callbackContext === undefined) { callbackContext = callback; }
  62075. return this.addToFileList('binary', key, url, { callback: callback, callbackContext: callbackContext }, false, '.bin');
  62076. },
  62077. /**
  62078. * Adds a Sprite Sheet to the current load queue.
  62079. *
  62080. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  62081. *
  62082. * To clarify the terminology that Phaser uses: A Sprite Sheet is an image containing frames, usually of an animation, that are all equal
  62083. * dimensions and often in sequence. For example if the frame size is 32x32 then every frame in the sprite sheet will be that size.
  62084. * Sometimes (outside of Phaser) the term "sprite sheet" is used to refer to a texture atlas.
  62085. * A Texture Atlas works by packing together images as best it can, using whatever frame sizes it likes, often with cropping and trimming
  62086. * the frames in the process. Software such as Texture Packer, Flash CC or Shoebox all generate texture atlases, not sprite sheets.
  62087. * If you've got an atlas then use `Loader.atlas` instead.
  62088. *
  62089. * The key must be a unique String. It is used to add the image to the Phaser.Cache upon successful load.
  62090. *
  62091. * Retrieve the file via `Cache.getImage(key)`. Sprite sheets, being image based, live in the same Cache as all other Images.
  62092. *
  62093. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62094. *
  62095. * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
  62096. * and no URL is given then the Loader will set the URL to be "alien.png". It will always add `.png` as the extension.
  62097. * If you do not desire this action then provide a URL.
  62098. *
  62099. * @method Phaser.Loader#spritesheet
  62100. * @param {string} key - Unique asset key of the sheet file.
  62101. * @param {string} url - URL of the sprite sheet file. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png".
  62102. * @param {number} frameWidth - Width in pixels of a single frame in the sprite sheet.
  62103. * @param {number} frameHeight - Height in pixels of a single frame in the sprite sheet.
  62104. * @param {number} [frameMax=-1] - How many frames in this sprite sheet. If not specified it will divide the whole image into frames.
  62105. * @param {number} [margin=0] - If the frames have been drawn with a margin, specify the amount here.
  62106. * @param {number} [spacing=0] - If the frames have been drawn with spacing between them, specify the amount here.
  62107. * @param {number} [skipFrames=0] - Skip a number of frames. Useful when there are multiple sprite sheets in one image.
  62108. * @return {Phaser.Loader} This Loader instance.
  62109. */
  62110. spritesheet: function (key, url, frameWidth, frameHeight, frameMax, margin, spacing, skipFrames) {
  62111. if (frameMax === undefined) { frameMax = -1; }
  62112. if (margin === undefined) { margin = 0; }
  62113. if (spacing === undefined) { spacing = 0; }
  62114. if (skipFrames === undefined) { skipFrames = 0; }
  62115. return this.addToFileList('spritesheet', key, url, { frameWidth: frameWidth, frameHeight: frameHeight, frameMax: frameMax, margin: margin, spacing: spacing, skipFrames: skipFrames }, false, '.png');
  62116. },
  62117. /**
  62118. * Adds an audio file to the current load queue.
  62119. *
  62120. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  62121. *
  62122. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62123. *
  62124. * Retrieve the file via `Cache.getSound(key)`.
  62125. *
  62126. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62127. *
  62128. * Mobile warning: There are some mobile devices (certain iPad 2 and iPad Mini revisions) that cannot play 48000 Hz audio.
  62129. * When they try to play the audio becomes extremely distorted and buzzes, eventually crashing the sound system.
  62130. * The solution is to use a lower encoding rate such as 44100 Hz.
  62131. *
  62132. * @method Phaser.Loader#audio
  62133. * @param {string} key - Unique asset key of the audio file.
  62134. * @param {string|string[]|object[]} urls - Either a single string or an array of URIs or pairs of `{uri: .., type: ..}`.
  62135. * If an array is specified then the first URI (or URI + mime pair) that is device-compatible will be selected.
  62136. * For example: `"jump.mp3"`, `['jump.mp3', 'jump.ogg', 'jump.m4a']`, or `[{uri: "data:<opus_resource>", type: 'opus'}, 'fallback.mp3']`.
  62137. * BLOB and DATA URIs can be used but only support automatic detection when used in the pair form; otherwise the format must be manually checked before adding the resource.
  62138. * @param {boolean} [autoDecode=true] - When using Web Audio the audio files can either be decoded at load time or run-time.
  62139. * Audio files can't be played until they are decoded and, if specified, this enables immediate decoding. Decoding is a non-blocking async process, however it consumes huge amounts of CPU time on mobiles especially.
  62140. * @return {Phaser.Loader} This Loader instance.
  62141. */
  62142. audio: function (key, urls, autoDecode) {
  62143. if (this.game.sound.noAudio)
  62144. {
  62145. return this;
  62146. }
  62147. if (autoDecode === undefined) { autoDecode = true; }
  62148. if (typeof urls === 'string')
  62149. {
  62150. urls = [urls];
  62151. }
  62152. return this.addToFileList('audio', key, urls, { buffer: null, autoDecode: autoDecode });
  62153. },
  62154. /**
  62155. * Adds an audio sprite file to the current load queue.
  62156. *
  62157. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  62158. *
  62159. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62160. *
  62161. * Audio Sprites are a combination of audio files and a JSON configuration.
  62162. *
  62163. * The JSON follows the format of that created by https://github.com/tonistiigi/audiosprite
  62164. *
  62165. * Retrieve the file via `Cache.getSoundData(key)`.
  62166. *
  62167. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62168. *
  62169. * @method Phaser.Loader#audioSprite
  62170. * @param {string} key - Unique asset key of the audio file.
  62171. * @param {Array|string} urls - An array containing the URLs of the audio files, i.e.: [ 'audiosprite.mp3', 'audiosprite.ogg', 'audiosprite.m4a' ] or a single string containing just one URL.
  62172. * @param {string} [jsonURL=null] - The URL of the audiosprite configuration JSON object. If you wish to pass the data directly set this parameter to null.
  62173. * @param {string|object} [jsonData=null] - A JSON object or string containing the audiosprite configuration data. This is ignored if jsonURL is not null.
  62174. * @param {boolean} [autoDecode=true] - When using Web Audio the audio files can either be decoded at load time or run-time.
  62175. * Audio files can't be played until they are decoded and, if specified, this enables immediate decoding. Decoding is a non-blocking async process, however it consumes huge amounts of CPU time on mobiles especially.
  62176. * @return {Phaser.Loader} This Loader instance.
  62177. */
  62178. audioSprite: function (key, urls, jsonURL, jsonData, autoDecode) {
  62179. if (this.game.sound.noAudio)
  62180. {
  62181. return this;
  62182. }
  62183. if (jsonURL === undefined) { jsonURL = null; }
  62184. if (jsonData === undefined) { jsonData = null; }
  62185. if (autoDecode === undefined) { autoDecode = true; }
  62186. this.audio(key, urls, autoDecode);
  62187. if (jsonURL)
  62188. {
  62189. this.json(key + '-audioatlas', jsonURL);
  62190. }
  62191. else if (jsonData)
  62192. {
  62193. if (typeof jsonData === 'string')
  62194. {
  62195. jsonData = JSON.parse(jsonData);
  62196. }
  62197. this.cache.addJSON(key + '-audioatlas', '', jsonData);
  62198. }
  62199. else
  62200. {
  62201. console.warn('Phaser.Loader.audiosprite - You must specify either a jsonURL or provide a jsonData object');
  62202. }
  62203. return this;
  62204. },
  62205. /**
  62206. * A legacy alias for Loader.audioSprite. Please see that method for documentation.
  62207. *
  62208. * @method Phaser.Loader#audiosprite
  62209. * @param {string} key - Unique asset key of the audio file.
  62210. * @param {Array|string} urls - An array containing the URLs of the audio files, i.e.: [ 'audiosprite.mp3', 'audiosprite.ogg', 'audiosprite.m4a' ] or a single string containing just one URL.
  62211. * @param {string} [jsonURL=null] - The URL of the audiosprite configuration JSON object. If you wish to pass the data directly set this parameter to null.
  62212. * @param {string|object} [jsonData=null] - A JSON object or string containing the audiosprite configuration data. This is ignored if jsonURL is not null.
  62213. * @param {boolean} [autoDecode=true] - When using Web Audio the audio files can either be decoded at load time or run-time.
  62214. * Audio files can't be played until they are decoded and, if specified, this enables immediate decoding. Decoding is a non-blocking async process, however it consumes huge amounts of CPU time on mobiles especially.
  62215. * @return {Phaser.Loader} This Loader instance.
  62216. */
  62217. audiosprite: function (key, urls, jsonURL, jsonData, autoDecode) {
  62218. return this.audioSprite(key, urls, jsonURL, jsonData, autoDecode);
  62219. },
  62220. /**
  62221. * Adds a video file to the current load queue.
  62222. *
  62223. * The file is **not** loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
  62224. *
  62225. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62226. *
  62227. * Retrieve the file via `Cache.getVideo(key)`.
  62228. *
  62229. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62230. *
  62231. * You don't need to preload a video in order to play it in your game. See `Video.createVideoFromURL` for details.
  62232. *
  62233. * @method Phaser.Loader#video
  62234. * @param {string} key - Unique asset key of the video file.
  62235. * @param {string|string[]|object[]} urls - Either a single string or an array of URIs or pairs of `{uri: .., type: ..}`.
  62236. * If an array is specified then the first URI (or URI + mime pair) that is device-compatible will be selected.
  62237. * For example: `"boom.mp4"`, `['boom.mp4', 'boom.ogg', 'boom.webm']`, or `[{uri: "data:<opus_resource>", type: 'opus'}, 'fallback.mp4']`.
  62238. * BLOB and DATA URIs can be used but only support automatic detection when used in the pair form; otherwise the format must be manually checked before adding the resource.
  62239. * @param {string} [loadEvent='canplaythrough'] - This sets the Video source event to listen for before the load is considered complete.
  62240. * 'canplaythrough' implies the video has downloaded enough, and bandwidth is high enough that it can be played to completion.
  62241. * 'canplay' implies the video has downloaded enough to start playing, but not necessarily to finish.
  62242. * 'loadeddata' just makes sure that the video meta data and first frame have downloaded. Phaser uses this value automatically if the
  62243. * browser is detected as being Firefox and no `loadEvent` is given, otherwise it defaults to `canplaythrough`.
  62244. * @param {boolean} [asBlob=false] - Video files can either be loaded via the creation of a video element which has its src property set.
  62245. * Or they can be loaded via xhr, stored as binary data in memory and then converted to a Blob. This isn't supported in IE9 or Android 2.
  62246. * If you need to have the same video playing at different times across multiple Sprites then you need to load it as a Blob.
  62247. * @return {Phaser.Loader} This Loader instance.
  62248. */
  62249. video: function (key, urls, loadEvent, asBlob) {
  62250. if (loadEvent === undefined)
  62251. {
  62252. if (this.game.device.firefox)
  62253. {
  62254. loadEvent = 'loadeddata';
  62255. }
  62256. else
  62257. {
  62258. loadEvent = 'canplaythrough';
  62259. }
  62260. }
  62261. if (asBlob === undefined) { asBlob = false; }
  62262. if (typeof urls === 'string')
  62263. {
  62264. urls = [urls];
  62265. }
  62266. return this.addToFileList('video', key, urls, { buffer: null, asBlob: asBlob, loadEvent: loadEvent });
  62267. },
  62268. /**
  62269. * Adds a Tile Map data file to the current load queue.
  62270. *
  62271. * Phaser can load data in two different formats: CSV and Tiled JSON.
  62272. *
  62273. * Tiled is a free software package, specifically for creating tilemaps, and is available from http://www.mapeditor.org
  62274. *
  62275. * You can choose to either load the data externally, by providing a URL to a json file.
  62276. * Or you can pass in a JSON object or String via the `data` parameter.
  62277. * If you pass a String the data is automatically run through `JSON.parse` and then immediately added to the Phaser.Cache.
  62278. *
  62279. * If a URL is provided the file is **not** loaded immediately after calling this method, but is added to the load queue.
  62280. *
  62281. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62282. *
  62283. * Retrieve the file via `Cache.getTilemapData(key)`. JSON files are automatically parsed upon load.
  62284. * If you need to control when the JSON is parsed then use `Loader.text` instead and parse the text file as needed.
  62285. *
  62286. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62287. *
  62288. * If the URL isn't specified and no data is given then the Loader will take the key and create a filename from that.
  62289. * For example if the key is "level1" and no URL or data is given then the Loader will set the URL to be "level1.json".
  62290. * If you set the format to be Tilemap.CSV it will set the URL to be "level1.csv" instead.
  62291. *
  62292. * If you do not desire this action then provide a URL or data object.
  62293. *
  62294. * @method Phaser.Loader#tilemap
  62295. * @param {string} key - Unique asset key of the tilemap data.
  62296. * @param {string} [url] - URL of the tile map file. If undefined or `null` and no data is given the url will be set to `<key>.json`, i.e. if `key` was "level1" then the URL will be "level1.json".
  62297. * @param {object|string} [data] - An optional JSON data object. If given then the url is ignored and this JSON object is used for map data instead.
  62298. * @param {number} [format=Phaser.Tilemap.CSV] - The format of the map data. Either Phaser.Tilemap.CSV or Phaser.Tilemap.TILED_JSON.
  62299. * @return {Phaser.Loader} This Loader instance.
  62300. */
  62301. tilemap: function (key, url, data, format) {
  62302. if (url === undefined) { url = null; }
  62303. if (data === undefined) { data = null; }
  62304. if (format === undefined) { format = Phaser.Tilemap.CSV; }
  62305. if (!url && !data)
  62306. {
  62307. if (format === Phaser.Tilemap.CSV)
  62308. {
  62309. url = key + '.csv';
  62310. }
  62311. else
  62312. {
  62313. url = key + '.json';
  62314. }
  62315. }
  62316. // A map data object has been given
  62317. if (data)
  62318. {
  62319. switch (format)
  62320. {
  62321. // A csv string or object has been given
  62322. case Phaser.Tilemap.CSV:
  62323. break;
  62324. // A json string or object has been given
  62325. case Phaser.Tilemap.TILED_JSON:
  62326. if (typeof data === 'string')
  62327. {
  62328. data = JSON.parse(data);
  62329. }
  62330. break;
  62331. }
  62332. this.cache.addTilemap(key, null, data, format);
  62333. }
  62334. else
  62335. {
  62336. this.addToFileList('tilemap', key, url, { format: format });
  62337. }
  62338. return this;
  62339. },
  62340. /**
  62341. * Adds a physics data file to the current load queue.
  62342. *
  62343. * The data must be in `Lime + Corona` JSON format. [Physics Editor](https://www.codeandweb.com) by code'n'web exports in this format natively.
  62344. *
  62345. * You can choose to either load the data externally, by providing a URL to a json file.
  62346. * Or you can pass in a JSON object or String via the `data` parameter.
  62347. * If you pass a String the data is automatically run through `JSON.parse` and then immediately added to the Phaser.Cache.
  62348. *
  62349. * If a URL is provided the file is **not** loaded immediately after calling this method, but is added to the load queue.
  62350. *
  62351. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62352. *
  62353. * Retrieve the file via `Cache.getJSON(key)`. JSON files are automatically parsed upon load.
  62354. * If you need to control when the JSON is parsed then use `Loader.text` instead and parse the text file as needed.
  62355. *
  62356. * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62357. *
  62358. * If the URL isn't specified and no data is given then the Loader will take the key and create a filename from that.
  62359. * For example if the key is "alien" and no URL or data is given then the Loader will set the URL to be "alien.json".
  62360. * It will always use `.json` as the extension.
  62361. *
  62362. * If you do not desire this action then provide a URL or data object.
  62363. *
  62364. * @method Phaser.Loader#physics
  62365. * @param {string} key - Unique asset key of the physics json data.
  62366. * @param {string} [url] - URL of the physics data file. If undefined or `null` and no data is given the url will be set to `<key>.json`, i.e. if `key` was "alien" then the URL will be "alien.json".
  62367. * @param {object|string} [data] - An optional JSON data object. If given then the url is ignored and this JSON object is used for physics data instead.
  62368. * @param {string} [format=Phaser.Physics.LIME_CORONA_JSON] - The format of the physics data.
  62369. * @return {Phaser.Loader} This Loader instance.
  62370. */
  62371. physics: function (key, url, data, format) {
  62372. if (url === undefined) { url = null; }
  62373. if (data === undefined) { data = null; }
  62374. if (format === undefined) { format = Phaser.Physics.LIME_CORONA_JSON; }
  62375. if (!url && !data)
  62376. {
  62377. url = key + '.json';
  62378. }
  62379. // A map data object has been given
  62380. if (data)
  62381. {
  62382. if (typeof data === 'string')
  62383. {
  62384. data = JSON.parse(data);
  62385. }
  62386. this.cache.addPhysicsData(key, null, data, format);
  62387. }
  62388. else
  62389. {
  62390. this.addToFileList('physics', key, url, { format: format });
  62391. }
  62392. return this;
  62393. },
  62394. /**
  62395. * Adds Bitmap Font files to the current load queue.
  62396. *
  62397. * To create the Bitmap Font files you can use:
  62398. *
  62399. * BMFont (Windows, free): http://www.angelcode.com/products/bmfont/
  62400. * Glyph Designer (OS X, commercial): http://www.71squared.com/en/glyphdesigner
  62401. * Littera (Web-based, free): http://kvazars.com/littera/
  62402. *
  62403. * You can choose to either load the data externally, by providing a URL to an xml file.
  62404. * Or you can pass in an XML object or String via the `xmlData` parameter.
  62405. * If you pass a String the data is automatically run through `Loader.parseXML` and then immediately added to the Phaser.Cache.
  62406. *
  62407. * If URLs are provided the files are **not** loaded immediately after calling this method, but are added to the load queue.
  62408. *
  62409. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62410. *
  62411. * Retrieve the file via `Cache.getBitmapFont(key)`. XML files are automatically parsed upon load.
  62412. * If you need to control when the XML is parsed then use `Loader.text` instead and parse the XML file as needed.
  62413. *
  62414. * The URLs can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62415. *
  62416. * If the textureURL isn't specified then the Loader will take the key and create a filename from that.
  62417. * For example if the key is "megaFont" and textureURL is null then the Loader will set the URL to be "megaFont.png".
  62418. * The same is true for the atlasURL. If atlasURL isn't specified and no atlasData has been provided then the Loader will
  62419. * set the atlasURL to be the key. For example if the key is "megaFont" the atlasURL will be set to "megaFont.xml".
  62420. *
  62421. * If you do not desire this action then provide URLs and / or a data object.
  62422. *
  62423. * @method Phaser.Loader#bitmapFont
  62424. * @param {string} key - Unique asset key of the bitmap font.
  62425. * @param {string} textureURL - URL of the Bitmap Font texture file. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "megaFont" then the URL will be "megaFont.png".
  62426. * @param {string} atlasURL - URL of the Bitmap Font atlas file (xml/json). If undefined or `null` AND `atlasData` is null, the url will be set to `<key>.xml`, i.e. if `key` was "megaFont" then the URL will be "megaFont.xml".
  62427. * @param {object} atlasData - An optional Bitmap Font atlas in string form (stringified xml/json).
  62428. * @param {number} [xSpacing=0] - If you'd like to add additional horizontal spacing between the characters then set the pixel value here.
  62429. * @param {number} [ySpacing=0] - If you'd like to add additional vertical spacing between the lines then set the pixel value here.
  62430. * @return {Phaser.Loader} This Loader instance.
  62431. */
  62432. bitmapFont: function (key, textureURL, atlasURL, atlasData, xSpacing, ySpacing) {
  62433. if (textureURL === undefined || textureURL === null)
  62434. {
  62435. textureURL = key + '.png';
  62436. }
  62437. if (atlasURL === undefined) { atlasURL = null; }
  62438. if (atlasData === undefined) { atlasData = null; }
  62439. if (atlasURL === null && atlasData === null)
  62440. {
  62441. atlasURL = key + '.xml';
  62442. }
  62443. if (xSpacing === undefined) { xSpacing = 0; }
  62444. if (ySpacing === undefined) { ySpacing = 0; }
  62445. // A URL to a json/xml atlas has been given
  62446. if (atlasURL)
  62447. {
  62448. this.addToFileList('bitmapfont', key, textureURL, { atlasURL: atlasURL, xSpacing: xSpacing, ySpacing: ySpacing });
  62449. }
  62450. else
  62451. {
  62452. // A stringified xml/json atlas has been given
  62453. if (typeof atlasData === 'string')
  62454. {
  62455. var json, xml;
  62456. try
  62457. {
  62458. json = JSON.parse(atlasData);
  62459. }
  62460. catch ( e )
  62461. {
  62462. xml = this.parseXml(atlasData);
  62463. }
  62464. if (!xml && !json)
  62465. {
  62466. throw new Error("Phaser.Loader. Invalid Bitmap Font atlas given");
  62467. }
  62468. this.addToFileList('bitmapfont', key, textureURL, { atlasURL: null, atlasData: json || xml,
  62469. atlasType: (!!json ? 'json' : 'xml'), xSpacing: xSpacing, ySpacing: ySpacing });
  62470. }
  62471. }
  62472. return this;
  62473. },
  62474. /**
  62475. * Adds a Texture Atlas file to the current load queue.
  62476. *
  62477. * Unlike `Loader.atlasJSONHash` this call expects the atlas data to be in a JSON Array format.
  62478. *
  62479. * To create the Texture Atlas you can use tools such as:
  62480. *
  62481. * [Texture Packer](https://www.codeandweb.com/texturepacker/phaser)
  62482. * [Shoebox](http://renderhjs.net/shoebox/)
  62483. *
  62484. * If using Texture Packer we recommend you enable "Trim sprite names".
  62485. * If your atlas software has an option to "rotate" the resulting frames, you must disable it.
  62486. *
  62487. * You can choose to either load the data externally, by providing a URL to a json file.
  62488. * Or you can pass in a JSON object or String via the `atlasData` parameter.
  62489. * If you pass a String the data is automatically run through `JSON.parse` and then immediately added to the Phaser.Cache.
  62490. *
  62491. * If URLs are provided the files are **not** loaded immediately after calling this method, but are added to the load queue.
  62492. *
  62493. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62494. *
  62495. * Retrieve the file via `Cache.getImage(key)`. JSON files are automatically parsed upon load.
  62496. * If you need to control when the JSON is parsed then use `Loader.text` instead and parse the JSON file as needed.
  62497. *
  62498. * The URLs can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62499. *
  62500. * If the textureURL isn't specified then the Loader will take the key and create a filename from that.
  62501. * For example if the key is "player" and textureURL is null then the Loader will set the URL to be "player.png".
  62502. * The same is true for the atlasURL. If atlasURL isn't specified and no atlasData has been provided then the Loader will
  62503. * set the atlasURL to be the key. For example if the key is "player" the atlasURL will be set to "player.json".
  62504. *
  62505. * If you do not desire this action then provide URLs and / or a data object.
  62506. *
  62507. * @method Phaser.Loader#atlasJSONArray
  62508. * @param {string} key - Unique asset key of the texture atlas file.
  62509. * @param {string} [textureURL] - URL of the texture atlas image file. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png".
  62510. * @param {string} [atlasURL] - URL of the texture atlas data file. If undefined or `null` and no atlasData is given, the url will be set to `<key>.json`, i.e. if `key` was "alien" then the URL will be "alien.json".
  62511. * @param {object} [atlasData] - A JSON data object. You don't need this if the data is being loaded from a URL.
  62512. * @return {Phaser.Loader} This Loader instance.
  62513. */
  62514. atlasJSONArray: function (key, textureURL, atlasURL, atlasData) {
  62515. return this.atlas(key, textureURL, atlasURL, atlasData, Phaser.Loader.TEXTURE_ATLAS_JSON_ARRAY);
  62516. },
  62517. /**
  62518. * Adds a Texture Atlas file to the current load queue.
  62519. *
  62520. * Unlike `Loader.atlas` this call expects the atlas data to be in a JSON Hash format.
  62521. *
  62522. * To create the Texture Atlas you can use tools such as:
  62523. *
  62524. * [Texture Packer](https://www.codeandweb.com/texturepacker/phaser)
  62525. * [Shoebox](http://renderhjs.net/shoebox/)
  62526. *
  62527. * If using Texture Packer we recommend you enable "Trim sprite names".
  62528. * If your atlas software has an option to "rotate" the resulting frames, you must disable it.
  62529. *
  62530. * You can choose to either load the data externally, by providing a URL to a json file.
  62531. * Or you can pass in a JSON object or String via the `atlasData` parameter.
  62532. * If you pass a String the data is automatically run through `JSON.parse` and then immediately added to the Phaser.Cache.
  62533. *
  62534. * If URLs are provided the files are **not** loaded immediately after calling this method, but are added to the load queue.
  62535. *
  62536. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62537. *
  62538. * Retrieve the file via `Cache.getImage(key)`. JSON files are automatically parsed upon load.
  62539. * If you need to control when the JSON is parsed then use `Loader.text` instead and parse the JSON file as needed.
  62540. *
  62541. * The URLs can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62542. *
  62543. * If the textureURL isn't specified then the Loader will take the key and create a filename from that.
  62544. * For example if the key is "player" and textureURL is null then the Loader will set the URL to be "player.png".
  62545. * The same is true for the atlasURL. If atlasURL isn't specified and no atlasData has been provided then the Loader will
  62546. * set the atlasURL to be the key. For example if the key is "player" the atlasURL will be set to "player.json".
  62547. *
  62548. * If you do not desire this action then provide URLs and / or a data object.
  62549. *
  62550. * @method Phaser.Loader#atlasJSONHash
  62551. * @param {string} key - Unique asset key of the texture atlas file.
  62552. * @param {string} [textureURL] - URL of the texture atlas image file. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png".
  62553. * @param {string} [atlasURL] - URL of the texture atlas data file. If undefined or `null` and no atlasData is given, the url will be set to `<key>.json`, i.e. if `key` was "alien" then the URL will be "alien.json".
  62554. * @param {object} [atlasData] - A JSON data object. You don't need this if the data is being loaded from a URL.
  62555. * @return {Phaser.Loader} This Loader instance.
  62556. */
  62557. atlasJSONHash: function (key, textureURL, atlasURL, atlasData) {
  62558. return this.atlas(key, textureURL, atlasURL, atlasData, Phaser.Loader.TEXTURE_ATLAS_JSON_HASH);
  62559. },
  62560. /**
  62561. * Adds a Texture Atlas file to the current load queue.
  62562. *
  62563. * This call expects the atlas data to be in the Starling XML data format.
  62564. *
  62565. * To create the Texture Atlas you can use tools such as:
  62566. *
  62567. * [Texture Packer](https://www.codeandweb.com/texturepacker/phaser)
  62568. * [Shoebox](http://renderhjs.net/shoebox/)
  62569. *
  62570. * If using Texture Packer we recommend you enable "Trim sprite names".
  62571. * If your atlas software has an option to "rotate" the resulting frames, you must disable it.
  62572. *
  62573. * You can choose to either load the data externally, by providing a URL to an xml file.
  62574. * Or you can pass in an XML object or String via the `atlasData` parameter.
  62575. * If you pass a String the data is automatically run through `Loader.parseXML` and then immediately added to the Phaser.Cache.
  62576. *
  62577. * If URLs are provided the files are **not** loaded immediately after calling this method, but are added to the load queue.
  62578. *
  62579. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62580. *
  62581. * Retrieve the file via `Cache.getImage(key)`. XML files are automatically parsed upon load.
  62582. * If you need to control when the XML is parsed then use `Loader.text` instead and parse the XML file as needed.
  62583. *
  62584. * The URLs can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62585. *
  62586. * If the textureURL isn't specified then the Loader will take the key and create a filename from that.
  62587. * For example if the key is "player" and textureURL is null then the Loader will set the URL to be "player.png".
  62588. * The same is true for the atlasURL. If atlasURL isn't specified and no atlasData has been provided then the Loader will
  62589. * set the atlasURL to be the key. For example if the key is "player" the atlasURL will be set to "player.xml".
  62590. *
  62591. * If you do not desire this action then provide URLs and / or a data object.
  62592. *
  62593. * @method Phaser.Loader#atlasXML
  62594. * @param {string} key - Unique asset key of the texture atlas file.
  62595. * @param {string} [textureURL] - URL of the texture atlas image file. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png".
  62596. * @param {string} [atlasURL] - URL of the texture atlas data file. If undefined or `null` and no atlasData is given, the url will be set to `<key>.json`, i.e. if `key` was "alien" then the URL will be "alien.xml".
  62597. * @param {object} [atlasData] - An XML data object. You don't need this if the data is being loaded from a URL.
  62598. * @return {Phaser.Loader} This Loader instance.
  62599. */
  62600. atlasXML: function (key, textureURL, atlasURL, atlasData) {
  62601. if (atlasURL === undefined) { atlasURL = null; }
  62602. if (atlasData === undefined) { atlasData = null; }
  62603. if (!atlasURL && !atlasData)
  62604. {
  62605. atlasURL = key + '.xml';
  62606. }
  62607. return this.atlas(key, textureURL, atlasURL, atlasData, Phaser.Loader.TEXTURE_ATLAS_XML_STARLING);
  62608. },
  62609. /**
  62610. * Adds a Texture Atlas file to the current load queue.
  62611. *
  62612. * To create the Texture Atlas you can use tools such as:
  62613. *
  62614. * [Texture Packer](https://www.codeandweb.com/texturepacker/phaser)
  62615. * [Shoebox](http://renderhjs.net/shoebox/)
  62616. *
  62617. * If using Texture Packer we recommend you enable "Trim sprite names".
  62618. * If your atlas software has an option to "rotate" the resulting frames, you must disable it.
  62619. *
  62620. * You can choose to either load the data externally, by providing a URL to a json file.
  62621. * Or you can pass in a JSON object or String via the `atlasData` parameter.
  62622. * If you pass a String the data is automatically run through `JSON.parse` and then immediately added to the Phaser.Cache.
  62623. *
  62624. * If URLs are provided the files are **not** loaded immediately after calling this method, but are added to the load queue.
  62625. *
  62626. * The key must be a unique String. It is used to add the file to the Phaser.Cache upon successful load.
  62627. *
  62628. * Retrieve the file via `Cache.getImage(key)`. JSON files are automatically parsed upon load.
  62629. * If you need to control when the JSON is parsed then use `Loader.text` instead and parse the JSON file as needed.
  62630. *
  62631. * The URLs can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
  62632. *
  62633. * If the textureURL isn't specified then the Loader will take the key and create a filename from that.
  62634. * For example if the key is "player" and textureURL is null then the Loader will set the URL to be "player.png".
  62635. * The same is true for the atlasURL. If atlasURL isn't specified and no atlasData has been provided then the Loader will
  62636. * set the atlasURL to be the key. For example if the key is "player" the atlasURL will be set to "player.json".
  62637. *
  62638. * If you do not desire this action then provide URLs and / or a data object.
  62639. *
  62640. * @method Phaser.Loader#atlas
  62641. * @param {string} key - Unique asset key of the texture atlas file.
  62642. * @param {string} [textureURL] - URL of the texture atlas image file. If undefined or `null` the url will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png".
  62643. * @param {string} [atlasURL] - URL of the texture atlas data file. If undefined or `null` and no atlasData is given, the url will be set to `<key>.json`, i.e. if `key` was "alien" then the URL will be "alien.json".
  62644. * @param {object} [atlasData] - A JSON or XML data object. You don't need this if the data is being loaded from a URL.
  62645. * @param {number} [format] - The format of the data. Can be Phaser.Loader.TEXTURE_ATLAS_JSON_ARRAY (the default), Phaser.Loader.TEXTURE_ATLAS_JSON_HASH or Phaser.Loader.TEXTURE_ATLAS_XML_STARLING.
  62646. * @return {Phaser.Loader} This Loader instance.
  62647. */
  62648. atlas: function (key, textureURL, atlasURL, atlasData, format) {
  62649. if (textureURL === undefined || textureURL === null)
  62650. {
  62651. textureURL = key + '.png';
  62652. }
  62653. if (atlasURL === undefined) { atlasURL = null; }
  62654. if (atlasData === undefined) { atlasData = null; }
  62655. if (format === undefined) { format = Phaser.Loader.TEXTURE_ATLAS_JSON_ARRAY; }
  62656. if (!atlasURL && !atlasData)
  62657. {
  62658. if (format === Phaser.Loader.TEXTURE_ATLAS_XML_STARLING)
  62659. {
  62660. atlasURL = key + '.xml';
  62661. }
  62662. else
  62663. {
  62664. atlasURL = key + '.json';
  62665. }
  62666. }
  62667. // A URL to a json/xml file has been given
  62668. if (atlasURL)
  62669. {
  62670. this.addToFileList('textureatlas', key, textureURL, { atlasURL: atlasURL, format: format });
  62671. }
  62672. else
  62673. {
  62674. switch (format)
  62675. {
  62676. // A json string or object has been given
  62677. case Phaser.Loader.TEXTURE_ATLAS_JSON_ARRAY:
  62678. if (typeof atlasData === 'string')
  62679. {
  62680. atlasData = JSON.parse(atlasData);
  62681. }
  62682. break;
  62683. // An xml string or object has been given
  62684. case Phaser.Loader.TEXTURE_ATLAS_XML_STARLING:
  62685. if (typeof atlasData === 'string')
  62686. {
  62687. var xml = this.parseXml(atlasData);
  62688. if (!xml)
  62689. {
  62690. throw new Error("Phaser.Loader. Invalid Texture Atlas XML given");
  62691. }
  62692. atlasData = xml;
  62693. }
  62694. break;
  62695. }
  62696. this.addToFileList('textureatlas', key, textureURL, { atlasURL: null, atlasData: atlasData, format: format });
  62697. }
  62698. return this;
  62699. },
  62700. /**
  62701. * Add a synchronization point to the assets / files added within the supplied callback.
  62702. *
  62703. * A synchronization point denotes that an asset _must_ be completely loaded before
  62704. * subsequent assets can be loaded. An asset marked as a sync-point does not need to wait
  62705. * for previous assets to load (unless they are sync-points). Resources, such as packs, may still
  62706. * be downloaded around sync-points, as long as they do not finalize loading.
  62707. *
  62708. * @method Phaser.Loader#withSyncPoint
  62709. * @param {function} callback - The callback is invoked and is supplied with a single argument: the loader.
  62710. * @param {object} [callbackContext=(loader)] - Context for the callback.
  62711. * @return {Phaser.Loader} This Loader instance.
  62712. */
  62713. withSyncPoint: function (callback, callbackContext) {
  62714. this._withSyncPointDepth++;
  62715. try {
  62716. callback.call(callbackContext || this, this);
  62717. } finally {
  62718. this._withSyncPointDepth--;
  62719. }
  62720. return this;
  62721. },
  62722. /**
  62723. * Add a synchronization point to a specific file/asset in the load queue.
  62724. *
  62725. * This has no effect on already loaded assets.
  62726. *
  62727. * @method Phaser.Loader#addSyncPoint
  62728. * @param {string} type - The type of resource to turn into a sync point (image, audio, xml, etc).
  62729. * @param {string} key - Key of the file you want to turn into a sync point.
  62730. * @return {Phaser.Loader} This Loader instance.
  62731. * @see {@link Phaser.Loader#withSyncPoint withSyncPoint}
  62732. */
  62733. addSyncPoint: function (type, key) {
  62734. var asset = this.getAsset(type, key);
  62735. if (asset)
  62736. {
  62737. asset.file.syncPoint = true;
  62738. }
  62739. return this;
  62740. },
  62741. /**
  62742. * Remove a file/asset from the loading queue.
  62743. *
  62744. * A file that is loaded or has started loading cannot be removed.
  62745. *
  62746. * @method Phaser.Loader#removeFile
  62747. * @protected
  62748. * @param {string} type - The type of resource to add to the list (image, audio, xml, etc).
  62749. * @param {string} key - Key of the file you want to remove.
  62750. */
  62751. removeFile: function (type, key) {
  62752. var asset = this.getAsset(type, key);
  62753. if (asset)
  62754. {
  62755. if (!asset.loaded && !asset.loading)
  62756. {
  62757. this._fileList.splice(asset.index, 1);
  62758. }
  62759. }
  62760. },
  62761. /**
  62762. * Remove all file loading requests - this is _insufficient_ to stop current loading. Use `reset` instead.
  62763. *
  62764. * @method Phaser.Loader#removeAll
  62765. * @protected
  62766. */
  62767. removeAll: function () {
  62768. this._fileList.length = 0;
  62769. this._flightQueue.length = 0;
  62770. },
  62771. /**
  62772. * Start loading the assets. Normally you don't need to call this yourself as the StateManager will do so.
  62773. *
  62774. * @method Phaser.Loader#start
  62775. */
  62776. start: function () {
  62777. if (this.isLoading)
  62778. {
  62779. return;
  62780. }
  62781. this.hasLoaded = false;
  62782. this.isLoading = true;
  62783. this.updateProgress();
  62784. this.processLoadQueue();
  62785. },
  62786. /**
  62787. * Process the next item(s) in the file/asset queue.
  62788. *
  62789. * Process the queue and start loading enough items to fill up the inflight queue.
  62790. *
  62791. * If a sync-file is encountered then subsequent asset processing is delayed until it completes.
  62792. * The exception to this rule is that packfiles can be downloaded (but not processed) even if
  62793. * there appear other sync files (ie. packs) - this enables multiple packfiles to be fetched in parallel.
  62794. * such as during the start phaser.
  62795. *
  62796. * @method Phaser.Loader#processLoadQueue
  62797. * @private
  62798. */
  62799. processLoadQueue: function () {
  62800. if (!this.isLoading)
  62801. {
  62802. console.warn('Phaser.Loader - active loading canceled / reset');
  62803. this.finishedLoading(true);
  62804. return;
  62805. }
  62806. // Empty the flight queue as applicable
  62807. for (var i = 0; i < this._flightQueue.length; i++)
  62808. {
  62809. var file = this._flightQueue[i];
  62810. if (file.loaded || file.error)
  62811. {
  62812. this._flightQueue.splice(i, 1);
  62813. i--;
  62814. file.loading = false;
  62815. file.requestUrl = null;
  62816. file.requestObject = null;
  62817. if (file.error)
  62818. {
  62819. this.onFileError.dispatch(file.key, file);
  62820. }
  62821. if (file.type !== 'packfile')
  62822. {
  62823. this._loadedFileCount++;
  62824. this.onFileComplete.dispatch(this.progress, file.key, !file.error, this._loadedFileCount, this._totalFileCount);
  62825. }
  62826. else if (file.type === 'packfile' && file.error)
  62827. {
  62828. // Non-error pack files are handled when processing the file queue
  62829. this._loadedPackCount++;
  62830. this.onPackComplete.dispatch(file.key, !file.error, this._loadedPackCount, this._totalPackCount);
  62831. }
  62832. }
  62833. }
  62834. // When true further non-pack file downloads are suppressed
  62835. var syncblock = false;
  62836. var inflightLimit = this.enableParallel ? Math.max(1, this.maxParallelDownloads) : 1;
  62837. for (var i = this._processingHead; i < this._fileList.length; i++)
  62838. {
  62839. var file = this._fileList[i];
  62840. // Pack is fetched (ie. has data) and is currently at the start of the process queue.
  62841. if (file.type === 'packfile' && !file.error && file.loaded && i === this._processingHead)
  62842. {
  62843. // Processing the pack / adds more files
  62844. this.processPack(file);
  62845. this._loadedPackCount++;
  62846. this.onPackComplete.dispatch(file.key, !file.error, this._loadedPackCount, this._totalPackCount);
  62847. }
  62848. if (file.loaded || file.error)
  62849. {
  62850. // Item at the start of file list finished, can skip it in future
  62851. if (i === this._processingHead)
  62852. {
  62853. this._processingHead = i + 1;
  62854. }
  62855. }
  62856. else if (!file.loading && this._flightQueue.length < inflightLimit)
  62857. {
  62858. // -> not loaded/failed, not loading
  62859. if (file.type === 'packfile' && !file.data)
  62860. {
  62861. // Fetches the pack data: the pack is processed above as it reaches queue-start.
  62862. // (Packs do not trigger onLoadStart or onFileStart.)
  62863. this._flightQueue.push(file);
  62864. file.loading = true;
  62865. this.loadFile(file);
  62866. }
  62867. else if (!syncblock)
  62868. {
  62869. if (!this._fileLoadStarted)
  62870. {
  62871. this._fileLoadStarted = true;
  62872. this.onLoadStart.dispatch();
  62873. }
  62874. this._flightQueue.push(file);
  62875. file.loading = true;
  62876. this.onFileStart.dispatch(this.progress, file.key, file.url);
  62877. this.loadFile(file);
  62878. }
  62879. }
  62880. if (!file.loaded && file.syncPoint)
  62881. {
  62882. syncblock = true;
  62883. }
  62884. // Stop looking if queue full - or if syncblocked and there are no more packs.
  62885. // (As only packs can be loaded around a syncblock)
  62886. if (this._flightQueue.length >= inflightLimit ||
  62887. (syncblock && this._loadedPackCount === this._totalPackCount))
  62888. {
  62889. break;
  62890. }
  62891. }
  62892. this.updateProgress();
  62893. // True when all items in the queue have been advanced over
  62894. // (There should be no inflight items as they are complete - loaded/error.)
  62895. if (this._processingHead >= this._fileList.length)
  62896. {
  62897. this.finishedLoading();
  62898. }
  62899. else if (!this._flightQueue.length)
  62900. {
  62901. // Flight queue is empty but file list is not done being processed.
  62902. // This indicates a critical internal error with no known recovery.
  62903. console.warn("Phaser.Loader - aborting: processing queue empty, loading may have stalled");
  62904. var _this = this;
  62905. setTimeout(function () {
  62906. _this.finishedLoading(true);
  62907. }, 2000);
  62908. }
  62909. },
  62910. /**
  62911. * The loading is all finished.
  62912. *
  62913. * @method Phaser.Loader#finishedLoading
  62914. * @private
  62915. * @param {boolean} [abnormal=true] - True if the loading finished abnormally.
  62916. */
  62917. finishedLoading: function (abnormal) {
  62918. if (this.hasLoaded)
  62919. {
  62920. return;
  62921. }
  62922. this.hasLoaded = true;
  62923. this.isLoading = false;
  62924. // If there were no files make sure to trigger the event anyway, for consistency
  62925. if (!abnormal && !this._fileLoadStarted)
  62926. {
  62927. this._fileLoadStarted = true;
  62928. this.onLoadStart.dispatch();
  62929. }
  62930. this.reset();
  62931. this.onLoadComplete.dispatch();
  62932. this.game.state.loadComplete();
  62933. },
  62934. /**
  62935. * Informs the loader that the given file resource has been fetched and processed;
  62936. * or such a request has failed.
  62937. *
  62938. * @method Phaser.Loader#asyncComplete
  62939. * @private
  62940. * @param {object} file
  62941. * @param {string} [error=''] - The error message, if any. No message implies no error.
  62942. */
  62943. asyncComplete: function (file, errorMessage) {
  62944. if (errorMessage === undefined) { errorMessage = ''; }
  62945. file.loaded = true;
  62946. file.error = !!errorMessage;
  62947. if (errorMessage)
  62948. {
  62949. file.errorMessage = errorMessage;
  62950. console.warn('Phaser.Loader - ' + file.type + '[' + file.key + ']' + ': ' + errorMessage);
  62951. }
  62952. this.processLoadQueue();
  62953. },
  62954. /**
  62955. * Process pack data. This will usually modify the file list.
  62956. *
  62957. * @method Phaser.Loader#processPack
  62958. * @private
  62959. * @param {object} pack
  62960. */
  62961. processPack: function (pack) {
  62962. var packData = pack.data[pack.key];
  62963. if (!packData)
  62964. {
  62965. console.warn('Phaser.Loader - ' + pack.key + ': pack has data, but not for pack key');
  62966. return;
  62967. }
  62968. for (var i = 0; i < packData.length; i++)
  62969. {
  62970. var file = packData[i];
  62971. switch (file.type)
  62972. {
  62973. case "image":
  62974. this.image(file.key, file.url, file.overwrite);
  62975. break;
  62976. case "text":
  62977. this.text(file.key, file.url, file.overwrite);
  62978. break;
  62979. case "json":
  62980. this.json(file.key, file.url, file.overwrite);
  62981. break;
  62982. case "xml":
  62983. this.xml(file.key, file.url, file.overwrite);
  62984. break;
  62985. case "script":
  62986. this.script(file.key, file.url, file.callback, pack.callbackContext || this);
  62987. break;
  62988. case "binary":
  62989. this.binary(file.key, file.url, file.callback, pack.callbackContext || this);
  62990. break;
  62991. case "spritesheet":
  62992. this.spritesheet(file.key, file.url, file.frameWidth, file.frameHeight, file.frameMax, file.margin, file.spacing, file.skipFrames);
  62993. break;
  62994. case "video":
  62995. this.video(file.key, file.urls);
  62996. break;
  62997. case "audio":
  62998. this.audio(file.key, file.urls, file.autoDecode);
  62999. break;
  63000. case "audiosprite":
  63001. this.audiosprite(file.key, file.urls, file.jsonURL, file.jsonData, file.autoDecode);
  63002. break;
  63003. case "tilemap":
  63004. this.tilemap(file.key, file.url, file.data, Phaser.Tilemap[file.format]);
  63005. break;
  63006. case "physics":
  63007. this.physics(file.key, file.url, file.data, Phaser.Loader[file.format]);
  63008. break;
  63009. case "bitmapFont":
  63010. this.bitmapFont(file.key, file.textureURL, file.atlasURL, file.atlasData, file.xSpacing, file.ySpacing);
  63011. break;
  63012. case "atlasJSONArray":
  63013. this.atlasJSONArray(file.key, file.textureURL, file.atlasURL, file.atlasData);
  63014. break;
  63015. case "atlasJSONHash":
  63016. this.atlasJSONHash(file.key, file.textureURL, file.atlasURL, file.atlasData);
  63017. break;
  63018. case "atlasXML":
  63019. this.atlasXML(file.key, file.textureURL, file.atlasURL, file.atlasData);
  63020. break;
  63021. case "atlas":
  63022. this.atlas(file.key, file.textureURL, file.atlasURL, file.atlasData, Phaser.Loader[file.format]);
  63023. break;
  63024. case "shader":
  63025. this.shader(file.key, file.url, file.overwrite);
  63026. break;
  63027. }
  63028. }
  63029. },
  63030. /**
  63031. * Transforms the asset URL.
  63032. *
  63033. * The default implementation prepends the baseURL if the url doesn't begin with http or //
  63034. *
  63035. * @method Phaser.Loader#transformUrl
  63036. * @protected
  63037. * @param {string} url - The url to transform.
  63038. * @param {object} file - The file object being transformed.
  63039. * @return {string} The transformed url. In rare cases where the url isn't specified it will return false instead.
  63040. */
  63041. transformUrl: function (url, file) {
  63042. if (!url)
  63043. {
  63044. return false;
  63045. }
  63046. if (url.match(/^(?:blob:|data:|http:\/\/|https:\/\/|\/\/)/))
  63047. {
  63048. return url;
  63049. }
  63050. else
  63051. {
  63052. return this.baseURL + file.path + url;
  63053. }
  63054. },
  63055. /**
  63056. * Start fetching a resource.
  63057. *
  63058. * All code paths, async or otherwise, from this function must return to `asyncComplete`.
  63059. *
  63060. * @method Phaser.Loader#loadFile
  63061. * @private
  63062. * @param {object} file
  63063. */
  63064. loadFile: function (file) {
  63065. // Image or Data?
  63066. switch (file.type)
  63067. {
  63068. case 'packfile':
  63069. this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.fileComplete);
  63070. break;
  63071. case 'image':
  63072. case 'spritesheet':
  63073. case 'textureatlas':
  63074. case 'bitmapfont':
  63075. this.loadImageTag(file);
  63076. break;
  63077. case 'audio':
  63078. file.url = this.getAudioURL(file.url);
  63079. if (file.url)
  63080. {
  63081. // WebAudio or Audio Tag?
  63082. if (this.game.sound.usingWebAudio)
  63083. {
  63084. this.xhrLoad(file, this.transformUrl(file.url, file), 'arraybuffer', this.fileComplete);
  63085. }
  63086. else if (this.game.sound.usingAudioTag)
  63087. {
  63088. this.loadAudioTag(file);
  63089. }
  63090. }
  63091. else
  63092. {
  63093. this.fileError(file, null, 'No supported audio URL specified or device does not have audio playback support');
  63094. }
  63095. break;
  63096. case 'video':
  63097. file.url = this.getVideoURL(file.url);
  63098. if (file.url)
  63099. {
  63100. if (file.asBlob)
  63101. {
  63102. this.xhrLoad(file, this.transformUrl(file.url, file), 'blob', this.fileComplete);
  63103. }
  63104. else
  63105. {
  63106. this.loadVideoTag(file);
  63107. }
  63108. }
  63109. else
  63110. {
  63111. this.fileError(file, null, 'No supported video URL specified or device does not have video playback support');
  63112. }
  63113. break;
  63114. case 'json':
  63115. this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.jsonLoadComplete);
  63116. break;
  63117. case 'xml':
  63118. this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.xmlLoadComplete);
  63119. break;
  63120. case 'tilemap':
  63121. if (file.format === Phaser.Tilemap.TILED_JSON)
  63122. {
  63123. this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.jsonLoadComplete);
  63124. }
  63125. else if (file.format === Phaser.Tilemap.CSV)
  63126. {
  63127. this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.csvLoadComplete);
  63128. }
  63129. else
  63130. {
  63131. this.asyncComplete(file, "invalid Tilemap format: " + file.format);
  63132. }
  63133. break;
  63134. case 'text':
  63135. case 'script':
  63136. case 'shader':
  63137. case 'physics':
  63138. this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.fileComplete);
  63139. break;
  63140. case 'texture':
  63141. if (file.key.split('_').pop() === 'truecolor')
  63142. {
  63143. this.loadImageTag(file);
  63144. }
  63145. else
  63146. {
  63147. this.xhrLoad(file, this.transformUrl(file.url, file), 'arraybuffer', this.fileComplete);
  63148. }
  63149. break;
  63150. case 'binary':
  63151. this.xhrLoad(file, this.transformUrl(file.url, file), 'arraybuffer', this.fileComplete);
  63152. break;
  63153. }
  63154. },
  63155. /**
  63156. * Continue async loading through an Image tag.
  63157. * @private
  63158. */
  63159. loadImageTag: function (file) {
  63160. var _this = this;
  63161. file.data = new Image();
  63162. file.data.name = file.key;
  63163. if (this.crossOrigin)
  63164. {
  63165. file.data.crossOrigin = this.crossOrigin;
  63166. }
  63167. file.data.onload = function () {
  63168. if (file.data.onload)
  63169. {
  63170. file.data.onload = null;
  63171. file.data.onerror = null;
  63172. _this.fileComplete(file);
  63173. }
  63174. };
  63175. file.data.onerror = function () {
  63176. if (file.data.onload)
  63177. {
  63178. file.data.onload = null;
  63179. file.data.onerror = null;
  63180. _this.fileError(file);
  63181. }
  63182. };
  63183. file.data.src = this.transformUrl(file.url, file);
  63184. // Image is immediately-available/cached
  63185. // Special Firefox magic, exclude from cached reload
  63186. // More info here: https://github.com/photonstorm/phaser/issues/2534
  63187. if (!this.game.device.firefox && file.data.complete && file.data.width && file.data.height)
  63188. {
  63189. file.data.onload = null;
  63190. file.data.onerror = null;
  63191. this.fileComplete(file);
  63192. }
  63193. },
  63194. /**
  63195. * Continue async loading through a Video tag.
  63196. * @private
  63197. */
  63198. loadVideoTag: function (file) {
  63199. var _this = this;
  63200. file.data = document.createElement("video");
  63201. file.data.name = file.key;
  63202. file.data.controls = false;
  63203. file.data.autoplay = false;
  63204. var videoLoadEvent = function () {
  63205. file.data.removeEventListener(file.loadEvent, videoLoadEvent, false);
  63206. file.data.onerror = null;
  63207. file.data.canplay = true;
  63208. Phaser.GAMES[_this.game.id].load.fileComplete(file);
  63209. };
  63210. file.data.onerror = function () {
  63211. file.data.removeEventListener(file.loadEvent, videoLoadEvent, false);
  63212. file.data.onerror = null;
  63213. file.data.canplay = false;
  63214. _this.fileError(file);
  63215. };
  63216. file.data.addEventListener(file.loadEvent, videoLoadEvent, false);
  63217. file.data.src = this.transformUrl(file.url, file);
  63218. file.data.load();
  63219. },
  63220. /**
  63221. * Continue async loading through an Audio tag.
  63222. * @private
  63223. */
  63224. loadAudioTag: function (file) {
  63225. var _this = this;
  63226. if (this.game.sound.touchLocked)
  63227. {
  63228. // If audio is locked we can't do this yet, so need to queue this load request. Bum.
  63229. file.data = new Audio();
  63230. file.data.name = file.key;
  63231. file.data.preload = 'auto';
  63232. file.data.src = this.transformUrl(file.url, file);
  63233. this.fileComplete(file);
  63234. }
  63235. else
  63236. {
  63237. file.data = new Audio();
  63238. file.data.name = file.key;
  63239. var playThroughEvent = function () {
  63240. file.data.removeEventListener('canplaythrough', playThroughEvent, false);
  63241. file.data.onerror = null;
  63242. _this.fileComplete(file);
  63243. };
  63244. file.data.onerror = function () {
  63245. file.data.removeEventListener('canplaythrough', playThroughEvent, false);
  63246. file.data.onerror = null;
  63247. _this.fileError(file);
  63248. };
  63249. file.data.preload = 'auto';
  63250. file.data.src = this.transformUrl(file.url, file);
  63251. file.data.addEventListener('canplaythrough', playThroughEvent, false);
  63252. file.data.load();
  63253. }
  63254. },
  63255. /**
  63256. * Starts the xhr loader.
  63257. *
  63258. * This is designed specifically to use with asset file processing.
  63259. *
  63260. * @method Phaser.Loader#xhrLoad
  63261. * @private
  63262. * @param {object} file - The file/pack to load.
  63263. * @param {string} url - The URL of the file.
  63264. * @param {string} type - The xhr responseType.
  63265. * @param {function} onload - The function to call on success. Invoked in `this` context and supplied with `(file, xhr)` arguments.
  63266. * @param {function} [onerror=fileError] The function to call on error. Invoked in `this` context and supplied with `(file, xhr)` arguments.
  63267. */
  63268. xhrLoad: function (file, url, type, onload, onerror) {
  63269. if (this.useXDomainRequest && window.XDomainRequest)
  63270. {
  63271. this.xhrLoadWithXDR(file, url, type, onload, onerror);
  63272. return;
  63273. }
  63274. var xhr = new XMLHttpRequest();
  63275. xhr.open("GET", url, true);
  63276. xhr.responseType = type;
  63277. if (this.headers['requestedWith'] !== false)
  63278. {
  63279. xhr.setRequestHeader('X-Requested-With', this.headers['requestedWith']);
  63280. }
  63281. if (this.headers[file.type])
  63282. {
  63283. xhr.setRequestHeader('Accept', this.headers[file.type]);
  63284. }
  63285. onerror = onerror || this.fileError;
  63286. var _this = this;
  63287. xhr.onload = function () {
  63288. try {
  63289. if (xhr.readyState === 4 && xhr.status >= 400 && xhr.status <= 599) { // Handle HTTP status codes of 4xx and 5xx as errors, even if xhr.onerror was not called.
  63290. return onerror.call(_this, file, xhr);
  63291. }
  63292. else {
  63293. return onload.call(_this, file, xhr);
  63294. }
  63295. } catch (e) {
  63296. // If this was the last file in the queue and an error is thrown in the create method
  63297. // then it's caught here, so be sure we don't carry on processing it
  63298. if (!_this.hasLoaded)
  63299. {
  63300. _this.asyncComplete(file, e.message || 'Exception');
  63301. }
  63302. else
  63303. {
  63304. if (window['console'])
  63305. {
  63306. console.error(e);
  63307. }
  63308. }
  63309. }
  63310. };
  63311. xhr.onerror = function () {
  63312. try {
  63313. return onerror.call(_this, file, xhr);
  63314. } catch (e) {
  63315. if (!_this.hasLoaded)
  63316. {
  63317. _this.asyncComplete(file, e.message || 'Exception');
  63318. }
  63319. else
  63320. {
  63321. if (window['console'])
  63322. {
  63323. console.error(e);
  63324. }
  63325. }
  63326. }
  63327. };
  63328. file.requestObject = xhr;
  63329. file.requestUrl = url;
  63330. xhr.send();
  63331. },
  63332. /**
  63333. * Starts the xhr loader - using XDomainRequest.
  63334. * This should _only_ be used with IE 9. Phaser does not support IE 8 and XDR is deprecated in IE 10.
  63335. *
  63336. * This is designed specifically to use with asset file processing.
  63337. *
  63338. * @method Phaser.Loader#xhrLoad
  63339. * @private
  63340. * @param {object} file - The file/pack to load.
  63341. * @param {string} url - The URL of the file.
  63342. * @param {string} type - The xhr responseType.
  63343. * @param {function} onload - The function to call on success. Invoked in `this` context and supplied with `(file, xhr)` arguments.
  63344. * @param {function} [onerror=fileError] The function to call on error. Invoked in `this` context and supplied with `(file, xhr)` arguments.
  63345. * @deprecated This is only relevant for IE 9.
  63346. */
  63347. xhrLoadWithXDR: function (file, url, type, onload, onerror) {
  63348. // Special IE9 magic .. only
  63349. if (!this._warnedAboutXDomainRequest &&
  63350. (!this.game.device.ie || this.game.device.ieVersion >= 10))
  63351. {
  63352. this._warnedAboutXDomainRequest = true;
  63353. console.warn("Phaser.Loader - using XDomainRequest outside of IE 9");
  63354. }
  63355. // Ref: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
  63356. var xhr = new window.XDomainRequest();
  63357. xhr.open('GET', url, true);
  63358. xhr.responseType = type;
  63359. // XDomainRequest has a few quirks. Occasionally it will abort requests
  63360. // A way to avoid this is to make sure ALL callbacks are set even if not used
  63361. // More info here: http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9
  63362. xhr.timeout = 3000;
  63363. onerror = onerror || this.fileError;
  63364. var _this = this;
  63365. xhr.onerror = function () {
  63366. try {
  63367. return onerror.call(_this, file, xhr);
  63368. } catch (e) {
  63369. _this.asyncComplete(file, e.message || 'Exception');
  63370. }
  63371. };
  63372. xhr.ontimeout = function () {
  63373. try {
  63374. return onerror.call(_this, file, xhr);
  63375. } catch (e) {
  63376. _this.asyncComplete(file, e.message || 'Exception');
  63377. }
  63378. };
  63379. xhr.onprogress = function() {};
  63380. xhr.onload = function () {
  63381. try {
  63382. if (xhr.readyState === 4 && xhr.status >= 400 && xhr.status <= 599) { // Handle HTTP status codes of 4xx and 5xx as errors, even if xhr.onerror was not called.
  63383. return onerror.call(_this, file, xhr);
  63384. }
  63385. else {
  63386. return onload.call(_this, file, xhr);
  63387. }
  63388. return onload.call(_this, file, xhr);
  63389. } catch (e) {
  63390. _this.asyncComplete(file, e.message || 'Exception');
  63391. }
  63392. };
  63393. file.requestObject = xhr;
  63394. file.requestUrl = url;
  63395. // Note: The xdr.send() call is wrapped in a timeout to prevent an issue with the interface where some requests are lost
  63396. // if multiple XDomainRequests are being sent at the same time.
  63397. setTimeout(function () {
  63398. xhr.send();
  63399. }, 0);
  63400. },
  63401. /**
  63402. * Give a bunch of URLs, return the first URL that has an extension this device thinks it can play.
  63403. *
  63404. * It is assumed that the device can play "blob:" or "data:" URIs - There is no mime-type checking on data URIs.
  63405. *
  63406. * @method Phaser.Loader#getVideoURL
  63407. * @private
  63408. * @param {object[]|string[]} urls - See {@link #video} for format.
  63409. * @return {string} The URL to try and fetch; or null.
  63410. */
  63411. getVideoURL: function (urls) {
  63412. for (var i = 0; i < urls.length; i++)
  63413. {
  63414. var url = urls[i];
  63415. var videoType;
  63416. if (url.uri) // {uri: .., type: ..} pair
  63417. {
  63418. videoType = url.type;
  63419. url = url.uri;
  63420. if (this.game.device.canPlayVideo(videoType))
  63421. {
  63422. return url;
  63423. }
  63424. }
  63425. else
  63426. {
  63427. // Assume direct-data URI can be played if not in a paired form; select immediately
  63428. if (url.indexOf("blob:") === 0 || url.indexOf("data:") === 0)
  63429. {
  63430. return url;
  63431. }
  63432. if (url.indexOf("?") >= 0) // Remove query from URL
  63433. {
  63434. url = url.substr(0, url.indexOf("?"));
  63435. }
  63436. var extension = url.substr((Math.max(0, url.lastIndexOf(".")) || Infinity) + 1);
  63437. videoType = extension.toLowerCase();
  63438. if (this.game.device.canPlayVideo(videoType))
  63439. {
  63440. return urls[i];
  63441. }
  63442. }
  63443. }
  63444. return null;
  63445. },
  63446. /**
  63447. * Give a bunch of URLs, return the first URL that has an extension this device thinks it can play.
  63448. *
  63449. * It is assumed that the device can play "blob:" or "data:" URIs - There is no mime-type checking on data URIs.
  63450. *
  63451. * @method Phaser.Loader#getAudioURL
  63452. * @private
  63453. * @param {object[]|string[]} urls - See {@link #audio} for format.
  63454. * @return {string} The URL to try and fetch; or null.
  63455. */
  63456. getAudioURL: function (urls) {
  63457. if (this.game.sound.noAudio)
  63458. {
  63459. return null;
  63460. }
  63461. for (var i = 0; i < urls.length; i++)
  63462. {
  63463. var url = urls[i];
  63464. var audioType;
  63465. if (url.uri) // {uri: .., type: ..} pair
  63466. {
  63467. audioType = url.type;
  63468. url = url.uri;
  63469. if (this.game.device.canPlayAudio(audioType))
  63470. {
  63471. return url;
  63472. }
  63473. }
  63474. else
  63475. {
  63476. // Assume direct-data URI can be played if not in a paired form; select immediately
  63477. if (url.indexOf("blob:") === 0 || url.indexOf("data:") === 0)
  63478. {
  63479. return url;
  63480. }
  63481. if (url.indexOf("?") >= 0) // Remove query from URL
  63482. {
  63483. url = url.substr(0, url.indexOf("?"));
  63484. }
  63485. var extension = url.substr((Math.max(0, url.lastIndexOf(".")) || Infinity) + 1);
  63486. audioType = extension.toLowerCase();
  63487. if (this.game.device.canPlayAudio(audioType))
  63488. {
  63489. return urls[i];
  63490. }
  63491. }
  63492. }
  63493. return null;
  63494. },
  63495. /**
  63496. * Error occurred when loading a file.
  63497. *
  63498. * @method Phaser.Loader#fileError
  63499. * @private
  63500. * @param {object} file
  63501. * @param {?XMLHttpRequest} xhr - XHR request, unspecified if loaded via other means (eg. tags)
  63502. * @param {string} reason
  63503. */
  63504. fileError: function (file, xhr, reason) {
  63505. var url = file.requestUrl || this.transformUrl(file.url, file);
  63506. var message = 'error loading asset from URL ' + url;
  63507. if (!reason && xhr)
  63508. {
  63509. reason = xhr.status;
  63510. }
  63511. if (reason)
  63512. {
  63513. message = message + ' (' + reason + ')';
  63514. }
  63515. this.asyncComplete(file, message);
  63516. },
  63517. /**
  63518. * Called when a file has been downloaded and needs to be processed further.
  63519. *
  63520. * @method Phaser.Loader#fileComplete
  63521. * @private
  63522. * @param {object} file - File loaded
  63523. * @param {?XMLHttpRequest} xhr - XHR request, unspecified if loaded via other means (eg. tags)
  63524. */
  63525. fileComplete: function (file, xhr) {
  63526. var loadNext = true;
  63527. switch (file.type)
  63528. {
  63529. case 'packfile':
  63530. // Pack data must never be false-ish after it is fetched without error
  63531. var data = JSON.parse(xhr.responseText);
  63532. file.data = data || {};
  63533. break;
  63534. case 'texture':
  63535. var extension = /\.([^.]+)$/.exec(file.url.split('?', 1)[0])[1].toLowerCase();
  63536. if (file.data !== null)
  63537. {
  63538. this.cache.addCompressedTextureMetaData(file.key, file.url, extension, file.data);
  63539. }
  63540. else
  63541. {
  63542. this.cache.addCompressedTextureMetaData(file.key, file.url, extension, xhr.response);
  63543. }
  63544. break;
  63545. case 'image':
  63546. this.cache.addImage(file.key, file.url, file.data);
  63547. break;
  63548. case 'spritesheet':
  63549. this.cache.addSpriteSheet(file.key, file.url, file.data, file.frameWidth, file.frameHeight, file.frameMax, file.margin, file.spacing, file.skipFrames);
  63550. break;
  63551. case 'textureatlas':
  63552. if (file.atlasURL == null)
  63553. {
  63554. this.cache.addTextureAtlas(file.key, file.url, file.data, file.atlasData, file.format);
  63555. }
  63556. else
  63557. {
  63558. // Load the JSON or XML before carrying on with the next file
  63559. loadNext = false;
  63560. if (file.format === Phaser.Loader.TEXTURE_ATLAS_JSON_ARRAY || file.format === Phaser.Loader.TEXTURE_ATLAS_JSON_HASH || file.format === Phaser.Loader.TEXTURE_ATLAS_JSON_PYXEL)
  63561. {
  63562. this.xhrLoad(file, this.transformUrl(file.atlasURL, file), 'text', this.jsonLoadComplete);
  63563. }
  63564. else if (file.format === Phaser.Loader.TEXTURE_ATLAS_XML_STARLING)
  63565. {
  63566. this.xhrLoad(file, this.transformUrl(file.atlasURL, file), 'text', this.xmlLoadComplete);
  63567. }
  63568. else
  63569. {
  63570. throw new Error("Phaser.Loader. Invalid Texture Atlas format: " + file.format);
  63571. }
  63572. }
  63573. break;
  63574. case 'bitmapfont':
  63575. if (!file.atlasURL)
  63576. {
  63577. this.cache.addBitmapFont(file.key, file.url, file.data, file.atlasData, file.atlasType, file.xSpacing, file.ySpacing);
  63578. }
  63579. else
  63580. {
  63581. // Load the XML before carrying on with the next file
  63582. loadNext = false;
  63583. this.xhrLoad(file, this.transformUrl(file.atlasURL, file), 'text', function (file, xhr) {
  63584. var json;
  63585. try
  63586. {
  63587. // Try to parse as JSON, if it fails, then it's hopefully XML
  63588. json = JSON.parse(xhr.responseText);
  63589. }
  63590. catch (e) {}
  63591. if (!!json)
  63592. {
  63593. file.atlasType = 'json';
  63594. this.jsonLoadComplete(file, xhr);
  63595. }
  63596. else
  63597. {
  63598. file.atlasType = 'xml';
  63599. this.xmlLoadComplete(file, xhr);
  63600. }
  63601. });
  63602. }
  63603. break;
  63604. case 'video':
  63605. if (file.asBlob)
  63606. {
  63607. try
  63608. {
  63609. file.data = xhr.response;
  63610. }
  63611. catch (e)
  63612. {
  63613. throw new Error("Phaser.Loader. Unable to parse video file as Blob: " + file.key);
  63614. }
  63615. }
  63616. this.cache.addVideo(file.key, file.url, file.data, file.asBlob);
  63617. break;
  63618. case 'audio':
  63619. if (this.game.sound.usingWebAudio)
  63620. {
  63621. file.data = xhr.response;
  63622. this.cache.addSound(file.key, file.url, file.data, true, false);
  63623. if (file.autoDecode)
  63624. {
  63625. this.game.sound.decode(file.key);
  63626. }
  63627. }
  63628. else
  63629. {
  63630. this.cache.addSound(file.key, file.url, file.data, false, true);
  63631. }
  63632. break;
  63633. case 'text':
  63634. file.data = xhr.responseText;
  63635. this.cache.addText(file.key, file.url, file.data);
  63636. break;
  63637. case 'shader':
  63638. file.data = xhr.responseText;
  63639. this.cache.addShader(file.key, file.url, file.data);
  63640. break;
  63641. case 'physics':
  63642. var data = JSON.parse(xhr.responseText);
  63643. this.cache.addPhysicsData(file.key, file.url, data, file.format);
  63644. break;
  63645. case 'script':
  63646. file.data = document.createElement('script');
  63647. file.data.language = 'javascript';
  63648. file.data.type = 'text/javascript';
  63649. file.data.defer = false;
  63650. file.data.text = xhr.responseText;
  63651. document.head.appendChild(file.data);
  63652. if (file.callback)
  63653. {
  63654. file.data = file.callback.call(file.callbackContext, file.key, xhr.responseText);
  63655. }
  63656. break;
  63657. case 'binary':
  63658. if (file.callback)
  63659. {
  63660. file.data = file.callback.call(file.callbackContext, file.key, xhr.response);
  63661. }
  63662. else
  63663. {
  63664. file.data = xhr.response;
  63665. }
  63666. this.cache.addBinary(file.key, file.data);
  63667. break;
  63668. }
  63669. if (loadNext)
  63670. {
  63671. this.asyncComplete(file);
  63672. }
  63673. },
  63674. /**
  63675. * Successfully loaded a JSON file - only used for certain types.
  63676. *
  63677. * @method Phaser.Loader#jsonLoadComplete
  63678. * @private
  63679. * @param {object} file - File associated with this request
  63680. * @param {XMLHttpRequest} xhr
  63681. */
  63682. jsonLoadComplete: function (file, xhr) {
  63683. var data = JSON.parse(xhr.responseText);
  63684. if (file.type === 'tilemap')
  63685. {
  63686. this.cache.addTilemap(file.key, file.url, data, file.format);
  63687. }
  63688. else if (file.type === 'bitmapfont')
  63689. {
  63690. this.cache.addBitmapFont(file.key, file.url, file.data, data, file.atlasType, file.xSpacing, file.ySpacing);
  63691. }
  63692. else if (file.type === 'json')
  63693. {
  63694. this.cache.addJSON(file.key, file.url, data);
  63695. }
  63696. else
  63697. {
  63698. this.cache.addTextureAtlas(file.key, file.url, file.data, data, file.format);
  63699. }
  63700. this.asyncComplete(file);
  63701. },
  63702. /**
  63703. * Successfully loaded a CSV file - only used for certain types.
  63704. *
  63705. * @method Phaser.Loader#csvLoadComplete
  63706. * @private
  63707. * @param {object} file - File associated with this request
  63708. * @param {XMLHttpRequest} xhr
  63709. */
  63710. csvLoadComplete: function (file, xhr) {
  63711. var data = xhr.responseText;
  63712. this.cache.addTilemap(file.key, file.url, data, file.format);
  63713. this.asyncComplete(file);
  63714. },
  63715. /**
  63716. * Successfully loaded an XML file - only used for certain types.
  63717. *
  63718. * @method Phaser.Loader#xmlLoadComplete
  63719. * @private
  63720. * @param {object} file - File associated with this request
  63721. * @param {XMLHttpRequest} xhr
  63722. */
  63723. xmlLoadComplete: function (file, xhr) {
  63724. // Always try parsing the content as XML, regardless of actually response type
  63725. var data = xhr.responseText;
  63726. var xml = this.parseXml(data);
  63727. if (!xml)
  63728. {
  63729. var responseType = xhr.responseType || xhr.contentType; // contentType for MS-XDomainRequest
  63730. console.warn('Phaser.Loader - ' + file.key + ': invalid XML (' + responseType + ')');
  63731. this.asyncComplete(file, "invalid XML");
  63732. return;
  63733. }
  63734. if (file.type === 'bitmapfont')
  63735. {
  63736. this.cache.addBitmapFont(file.key, file.url, file.data, xml, file.atlasType, file.xSpacing, file.ySpacing);
  63737. }
  63738. else if (file.type === 'textureatlas')
  63739. {
  63740. this.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format);
  63741. }
  63742. else if (file.type === 'xml')
  63743. {
  63744. this.cache.addXML(file.key, file.url, xml);
  63745. }
  63746. this.asyncComplete(file);
  63747. },
  63748. /**
  63749. * Parses string data as XML.
  63750. *
  63751. * @method Phaser.Loader#parseXml
  63752. * @private
  63753. * @param {string} data - The XML text to parse
  63754. * @return {?XMLDocument} Returns the xml document, or null if such could not parsed to a valid document.
  63755. */
  63756. parseXml: function (data) {
  63757. var xml;
  63758. try
  63759. {
  63760. if (window['DOMParser'])
  63761. {
  63762. var domparser = new DOMParser();
  63763. xml = domparser.parseFromString(data, "text/xml");
  63764. }
  63765. else
  63766. {
  63767. xml = new ActiveXObject("Microsoft.XMLDOM");
  63768. // Why is this 'false'?
  63769. xml.async = 'false';
  63770. xml.loadXML(data);
  63771. }
  63772. }
  63773. catch (e)
  63774. {
  63775. xml = null;
  63776. }
  63777. if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length)
  63778. {
  63779. return null;
  63780. }
  63781. else
  63782. {
  63783. return xml;
  63784. }
  63785. },
  63786. /**
  63787. * Update the loading sprite progress.
  63788. *
  63789. * @method Phaser.Loader#nextFile
  63790. * @private
  63791. * @param {object} previousFile
  63792. * @param {boolean} success - Whether the previous asset loaded successfully or not.
  63793. */
  63794. updateProgress: function () {
  63795. if (this.preloadSprite)
  63796. {
  63797. if (this.preloadSprite.direction === 0)
  63798. {
  63799. this.preloadSprite.rect.width = Math.floor((this.preloadSprite.width / 100) * this.progress);
  63800. }
  63801. else
  63802. {
  63803. this.preloadSprite.rect.height = Math.floor((this.preloadSprite.height / 100) * this.progress);
  63804. }
  63805. if (this.preloadSprite.sprite)
  63806. {
  63807. this.preloadSprite.sprite.updateCrop();
  63808. }
  63809. else
  63810. {
  63811. // We seem to have lost our sprite - maybe it was destroyed?
  63812. this.preloadSprite = null;
  63813. }
  63814. }
  63815. },
  63816. /**
  63817. * Returns the number of files that have already been loaded, even if they errored.
  63818. *
  63819. * @method Phaser.Loader#totalLoadedFiles
  63820. * @protected
  63821. * @return {number} The number of files that have already been loaded (even if they errored)
  63822. */
  63823. totalLoadedFiles: function () {
  63824. return this._loadedFileCount;
  63825. },
  63826. /**
  63827. * Returns the number of files still waiting to be processed in the load queue. This value decreases as each file in the queue is loaded.
  63828. *
  63829. * @method Phaser.Loader#totalQueuedFiles
  63830. * @protected
  63831. * @return {number} The number of files that still remain in the load queue.
  63832. */
  63833. totalQueuedFiles: function () {
  63834. return this._totalFileCount - this._loadedFileCount;
  63835. },
  63836. /**
  63837. * Returns the number of asset packs that have already been loaded, even if they errored.
  63838. *
  63839. * @method Phaser.Loader#totalLoadedPacks
  63840. * @protected
  63841. * @return {number} The number of asset packs that have already been loaded (even if they errored)
  63842. */
  63843. totalLoadedPacks: function () {
  63844. return this._totalPackCount;
  63845. },
  63846. /**
  63847. * Returns the number of asset packs still waiting to be processed in the load queue. This value decreases as each pack in the queue is loaded.
  63848. *
  63849. * @method Phaser.Loader#totalQueuedPacks
  63850. * @protected
  63851. * @return {number} The number of asset packs that still remain in the load queue.
  63852. */
  63853. totalQueuedPacks: function () {
  63854. return this._totalPackCount - this._loadedPackCount;
  63855. }
  63856. };
  63857. /**
  63858. * The non-rounded load progress value (from 0.0 to 100.0).
  63859. *
  63860. * A general indicator of the progress.
  63861. * It is possible for the progress to decrease, after `onLoadStart`, if more files are dynamically added.
  63862. *
  63863. * @name Phaser.Loader#progressFloat
  63864. * @property {number}
  63865. */
  63866. Object.defineProperty(Phaser.Loader.prototype, "progressFloat", {
  63867. get: function () {
  63868. var progress = (this._loadedFileCount / this._totalFileCount) * 100;
  63869. return Phaser.Math.clamp(progress || 0, 0, 100);
  63870. }
  63871. });
  63872. /**
  63873. * The rounded load progress percentage value (from 0 to 100). See {@link Phaser.Loader#progressFloat}.
  63874. *
  63875. * @name Phaser.Loader#progress
  63876. * @property {integer}
  63877. */
  63878. Object.defineProperty(Phaser.Loader.prototype, "progress", {
  63879. get: function () {
  63880. return Math.round(this.progressFloat);
  63881. }
  63882. });
  63883. Phaser.Loader.prototype.constructor = Phaser.Loader;
  63884. /**
  63885. * @author Richard Davey <rich@photonstorm.com>
  63886. * @copyright 2016 Photon Storm Ltd.
  63887. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  63888. */
  63889. /**
  63890. * Phaser.LoaderParser parses data objects from Phaser.Loader that need more preparation before they can be inserted into the Cache.
  63891. *
  63892. * @class Phaser.LoaderParser
  63893. */
  63894. Phaser.LoaderParser = {
  63895. /**
  63896. * Alias for xmlBitmapFont, for backwards compatibility.
  63897. *
  63898. * @method Phaser.LoaderParser.bitmapFont
  63899. * @param {object} xml - XML data you want to parse.
  63900. * @param {PIXI.BaseTexture} baseTexture - The BaseTexture this font uses.
  63901. * @param {number} [xSpacing=0] - Additional horizontal spacing between the characters.
  63902. * @param {number} [ySpacing=0] - Additional vertical spacing between the characters.
  63903. * @param {Phaser.Frame} [frame] - Optional Frame, if this font is embedded in a texture atlas.
  63904. * @param {number} [resolution=1] - Optional game resolution to apply to the kerning data.
  63905. * @return {object} The parsed Bitmap Font data.
  63906. */
  63907. bitmapFont: function (xml, baseTexture, xSpacing, ySpacing, frame, resolution) {
  63908. return this.xmlBitmapFont(xml, baseTexture, xSpacing, ySpacing, frame, resolution);
  63909. },
  63910. /**
  63911. * Parse a Bitmap Font from an XML file.
  63912. *
  63913. * @method Phaser.LoaderParser.xmlBitmapFont
  63914. * @param {object} xml - XML data you want to parse.
  63915. * @param {PIXI.BaseTexture} baseTexture - The BaseTexture this font uses.
  63916. * @param {number} [xSpacing=0] - Additional horizontal spacing between the characters.
  63917. * @param {number} [ySpacing=0] - Additional vertical spacing between the characters.
  63918. * @param {Phaser.Frame} [frame] - Optional Frame, if this font is embedded in a texture atlas.
  63919. * @param {number} [resolution=1] - Optional game resolution to apply to the kerning data.
  63920. * @return {object} The parsed Bitmap Font data.
  63921. */
  63922. xmlBitmapFont: function (xml, baseTexture, xSpacing, ySpacing, frame, resolution) {
  63923. if (resolution == null)
  63924. {
  63925. resolution = 1;
  63926. }
  63927. var data = {};
  63928. var info = xml.getElementsByTagName('info')[0];
  63929. var common = xml.getElementsByTagName('common')[0];
  63930. data.font = info.getAttribute('face');
  63931. data.size = parseInt(info.getAttribute('size'), 10);
  63932. data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10) + ySpacing;
  63933. data.chars = {};
  63934. var letters = xml.getElementsByTagName('char');
  63935. var x = (frame) ? frame.x : 0;
  63936. var y = (frame) ? frame.y : 0;
  63937. for (var i = 0; i < letters.length; i++)
  63938. {
  63939. var charCode = parseInt(letters[i].getAttribute('id'), 10);
  63940. data.chars[charCode] = {
  63941. x: x + parseInt(letters[i].getAttribute('x'), 10),
  63942. y: y + parseInt(letters[i].getAttribute('y'), 10),
  63943. width: parseInt(letters[i].getAttribute('width'), 10),
  63944. height: parseInt(letters[i].getAttribute('height'), 10),
  63945. xOffset: parseInt(letters[i].getAttribute('xoffset'), 10) / resolution,
  63946. yOffset: parseInt(letters[i].getAttribute('yoffset'), 10) / resolution,
  63947. xAdvance: (parseInt(letters[i].getAttribute('xadvance'), 10) + xSpacing) / resolution,
  63948. kerning: {}
  63949. };
  63950. }
  63951. var kernings = xml.getElementsByTagName('kerning');
  63952. for (i = 0; i < kernings.length; i++)
  63953. {
  63954. var first = parseInt(kernings[i].getAttribute('first'), 10);
  63955. var second = parseInt(kernings[i].getAttribute('second'), 10);
  63956. var amount = parseInt(kernings[i].getAttribute('amount'), 10) / resolution;
  63957. data.chars[second].kerning[first] = amount;
  63958. }
  63959. return this.finalizeBitmapFont(baseTexture, data);
  63960. },
  63961. /**
  63962. * Parse a Bitmap Font from a JSON file.
  63963. *
  63964. * @method Phaser.LoaderParser.jsonBitmapFont
  63965. * @param {object} json - JSON data you want to parse.
  63966. * @param {PIXI.BaseTexture} baseTexture - The BaseTexture this font uses.
  63967. * @param {number} [xSpacing=0] - Additional horizontal spacing between the characters.
  63968. * @param {number} [ySpacing=0] - Additional vertical spacing between the characters.
  63969. * @param {Phaser.Frame} [frame] - Optional Frame, if this font is embedded in a texture atlas.
  63970. * @param {number} [resolution=1] - Optional game resolution to apply to the kerning data.
  63971. * @return {object} The parsed Bitmap Font data.
  63972. */
  63973. jsonBitmapFont: function (json, baseTexture, xSpacing, ySpacing, frame, resolution) {
  63974. if (resolution == null)
  63975. {
  63976. resolution = 1;
  63977. }
  63978. var data = {
  63979. font: json.font.info._face,
  63980. size: parseInt(json.font.info._size, 10),
  63981. lineHeight: parseInt(json.font.common._lineHeight, 10) + ySpacing,
  63982. chars: {}
  63983. };
  63984. var x = (frame) ? frame.x : 0;
  63985. var y = (frame) ? frame.y : 0;
  63986. json.font.chars["char"].forEach(
  63987. function parseChar(letter) {
  63988. var charCode = parseInt(letter._id, 10);
  63989. data.chars[charCode] = {
  63990. x: x + parseInt(letter._x, 10),
  63991. y: y + parseInt(letter._y, 10),
  63992. width: parseInt(letter._width, 10),
  63993. height: parseInt(letter._height, 10),
  63994. xOffset: parseInt(letter._xoffset, 10) / resolution,
  63995. yOffset: parseInt(letter._yoffset, 10) / resolution,
  63996. xAdvance: (parseInt(letter._xadvance, 10) + xSpacing) / resolution,
  63997. kerning: {}
  63998. };
  63999. }
  64000. );
  64001. if (json.font.kernings && json.font.kernings.kerning)
  64002. {
  64003. json.font.kernings.kerning.forEach(
  64004. function parseKerning(kerning) {
  64005. data.chars[kerning._second].kerning[kerning._first] = parseInt(kerning._amount, 10) / resolution;
  64006. }
  64007. );
  64008. }
  64009. return this.finalizeBitmapFont(baseTexture, data);
  64010. },
  64011. /**
  64012. * Finalize Bitmap Font parsing.
  64013. *
  64014. * @method Phaser.LoaderParser.finalizeBitmapFont
  64015. * @private
  64016. * @param {PIXI.BaseTexture} baseTexture - The BaseTexture this font uses.
  64017. * @param {object} bitmapFontData - Pre-parsed bitmap font data.
  64018. * @return {object} The parsed Bitmap Font data.
  64019. */
  64020. finalizeBitmapFont: function (baseTexture, bitmapFontData) {
  64021. Object.keys(bitmapFontData.chars).forEach(
  64022. function addTexture(charCode) {
  64023. var letter = bitmapFontData.chars[charCode];
  64024. letter.texture = new PIXI.Texture(baseTexture, new Phaser.Rectangle(letter.x, letter.y, letter.width, letter.height));
  64025. }
  64026. );
  64027. return bitmapFontData;
  64028. },
  64029. /**
  64030. * Extract PVR header from loaded binary
  64031. *
  64032. * @method Phaser.LoaderParser.pvr
  64033. * @param {ArrayBuffer} arrayBuffer
  64034. * @return {object} The parsed PVR file including texture data.
  64035. */
  64036. pvr: function (arrayBuffer) {
  64037. // Reference: http://cdn.imgtec.com/sdk-documentation/PVR+File+Format.Specification.pdf
  64038. // PVR 3 header structure
  64039. // ---------------------------------------
  64040. // address: 0, size: 4 bytes version
  64041. // address: 4, size: 4 bytes flags
  64042. // address: 8, size: 8 bytes pixel format
  64043. // address: 16, size: 4 bytes color space
  64044. // address: 20, size: 4 bytes channel type
  64045. // address: 24, size: 4 bytes height
  64046. // address: 28, size: 4 bytes width
  64047. // address: 32, size: 4 bytes depth
  64048. // address: 36, size: 4 bytes number of surfaces
  64049. // address: 40, size: 4 bytes number of faces
  64050. // address: 44, size: 4 bytes number of mipmaps
  64051. // address: 48, size: 4 bytes meta data size
  64052. // ---------------------------------------
  64053. var uintArray = new Uint32Array(arrayBuffer.slice(0, 52)),
  64054. byteArray = new Uint8Array(arrayBuffer),
  64055. pvrHeader = null,
  64056. pixelFormat = (uintArray[3] << 32 | uintArray[2]),
  64057. compressionAlgorithm,
  64058. glExtensionFormat = 0;
  64059. if (uintArray[0] === 0x03525650 &&
  64060. [ // Validate WebGL Pixel Format
  64061. 0, 1, 2, 3,
  64062. 6, 7, 9, 11
  64063. ].indexOf(pixelFormat) >= 0
  64064. ) {
  64065. if (pixelFormat >= 0 && pixelFormat <= 3) {
  64066. compressionAlgorithm = 'PVRTC';
  64067. } else if (pixelFormat >= 7 && pixelFormat <= 11) {
  64068. compressionAlgorithm = 'S3TC';
  64069. } else if (pixelFormat === 6) {
  64070. compressionAlgorithm = 'ETC1';
  64071. }
  64072. switch (pixelFormat) {
  64073. case 0:
  64074. glExtensionFormat = 0x8C01;
  64075. break;
  64076. case 1:
  64077. glExtensionFormat = 0x8C03;
  64078. break;
  64079. case 2:
  64080. glExtensionFormat = 0x8C00;
  64081. break;
  64082. case 3:
  64083. glExtensionFormat = 0x8C02;
  64084. break;
  64085. case 6:
  64086. glExtensionFormat = 0x8D64;
  64087. break;
  64088. case 7:
  64089. glExtensionFormat = 0x83F1;
  64090. break;
  64091. case 9:
  64092. glExtensionFormat = 0x83F2;
  64093. break;
  64094. case 11:
  64095. glExtensionFormat = 0x83F3;
  64096. break;
  64097. default:
  64098. glExtensionFormat = -1;
  64099. }
  64100. pvrHeader = {
  64101. complete: true,
  64102. fileFormat: 'PVR',
  64103. compressionAlgorithm: compressionAlgorithm,
  64104. flags: uintArray[1],
  64105. pixelFormat: pixelFormat,
  64106. colorSpace: uintArray[4],
  64107. channelType: uintArray[5],
  64108. height: uintArray[6],
  64109. width: uintArray[7],
  64110. depth: uintArray[8],
  64111. numberOfSurfaces: uintArray[9],
  64112. numberOfFaces: uintArray[10],
  64113. numberOfMipmaps: uintArray[11],
  64114. metaDataSize: uintArray[12],
  64115. textureData: byteArray.subarray(52 + uintArray[12], byteArray.byteLength),
  64116. glExtensionFormat: glExtensionFormat
  64117. };
  64118. }
  64119. return pvrHeader;
  64120. },
  64121. /**
  64122. * Extract DDS header from loaded binary
  64123. *
  64124. * @method Phaser.LoaderParser.dds
  64125. * @param {ArrayBuffer} arrayBuffer
  64126. * @return {object} The parsed DDS file including texture data.
  64127. */
  64128. dds: function (arrayBuffer) {
  64129. // Reference at: https://msdn.microsoft.com/en-us/library/windows/desktop/bb943982(v=vs.85).aspx
  64130. // DDS header structure
  64131. // ---------------------------------------
  64132. // address: 0, size: 4 bytes Identifier 'DDS '
  64133. // address: 4, size: 4 bytes size
  64134. // address: 8, size: 4 bytes flags
  64135. // address: 12, size: 4 bytes height
  64136. // address: 16, size: 4 bytes width
  64137. // address: 20, size: 4 bytes pitch or linear size
  64138. // address: 24, size: 4 bytes depth
  64139. // address: 28, size: 4 bytes mipmap count
  64140. // address: 32, size: 44 bytes reserved space 1
  64141. // address: 76, size: 4 pixel format size
  64142. // address: 80, size: 4 pixel format flag
  64143. // address: 84, size: 4 pixel format four CC
  64144. // address: 88, size: 4 pixel format bit count
  64145. // address: 92, size: 4 pixel format R bit mask
  64146. // address: 96, size: 4 pixel format G bit mask
  64147. // address: 100, size: 4 pixel format B bit mask
  64148. // address: 104, size: 4 pixel format A bit mask
  64149. // address: 108, size: 4 caps 1
  64150. // address: 112, size: 4 caps 2
  64151. // address: 116, size: 4 caps 3
  64152. // address: 120, size: 4 caps 4
  64153. // address: 124, size: 4 reserved 2
  64154. // -- DXT10 extension
  64155. // address: 130, size: 4 DXGI Format
  64156. // address: 134, size: 4 resource dimension
  64157. // address: 138, size: 4 misc flag
  64158. // address: 142, size: 4 array size
  64159. // address: 146, size: 4 misc flag 2
  64160. // ---------------------------------------
  64161. var byteArray = new Uint8Array(arrayBuffer),
  64162. uintArray = new Uint32Array(arrayBuffer),
  64163. ddsHeader = null;
  64164. if (byteArray[0] === 0x44 &&
  64165. byteArray[1] === 0x44 &&
  64166. byteArray[2] === 0x53 &&
  64167. byteArray[3] === 0x20) {
  64168. ddsHeader = {
  64169. complete: true,
  64170. fileFormat: 'DDS',
  64171. compressionAlgorithm: 'S3TC',
  64172. size: uintArray[1],
  64173. flags: uintArray[2],
  64174. height: uintArray[3],
  64175. width: uintArray[4],
  64176. pitch: uintArray[5],
  64177. depth: uintArray[6],
  64178. mipmapCount: uintArray[7],
  64179. formatSize: uintArray[19],
  64180. formatFlag: uintArray[19],
  64181. formatFourCC: [
  64182. String.fromCharCode(byteArray[84]),
  64183. String.fromCharCode(byteArray[85]),
  64184. String.fromCharCode(byteArray[86]),
  64185. String.fromCharCode(byteArray[87])
  64186. ].join(''),
  64187. formatBitCount: uintArray[21],
  64188. formatRBitMask: uintArray[22],
  64189. formatGBitMask: uintArray[23],
  64190. formatBBitMask: uintArray[24],
  64191. formatABitMask: uintArray[25],
  64192. caps1: uintArray[26],
  64193. caps2: uintArray[27],
  64194. caps3: uintArray[28],
  64195. caps4: uintArray[29],
  64196. reserved2: uintArray[30],
  64197. DXGIFormat: null,
  64198. resourceDimension: null,
  64199. miscFlag: null,
  64200. arraySize: null,
  64201. textureData: byteArray.subarray(uintArray[1] + 4, byteArray.byteLength)
  64202. };
  64203. if (ddsHeader.formatFourCC === 'DX10') {
  64204. ddsHeader.DXGIFormat = uintArray[31];
  64205. ddsHeader.resourceDimension = uintArray[32];
  64206. ddsHeader.miscFlag = uintArray[33];
  64207. ddsHeader.arraySize = uintArray[34];
  64208. ddsHeader.miscFlag = uintArray[35];
  64209. }
  64210. }
  64211. return ddsHeader;
  64212. },
  64213. /**
  64214. * Extract KTX header from loaded binary
  64215. *
  64216. * @method Phaser.LoaderParser.ktx
  64217. * @param {ArrayBuffer} arrayBuffer
  64218. * @return {object} The parsed KTX file including texture data.
  64219. */
  64220. ktx: function (arrayBuffer) {
  64221. // Reference: https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
  64222. // KTX header structure
  64223. // ---------------------------------------
  64224. // address: 0, size 12 bytes: Identifier '«KTX 11»\r\n\x1A\n'
  64225. // address: 12, size 4 bytes: endianness
  64226. // address: 16, size 4 bytes: GL type
  64227. // address: 20, size 4 bytes: GL type size
  64228. // address: 24, size 4 bytes: GL format
  64229. // address: 28, size 4 bytes: GL internal format
  64230. // address: 32, size 4 bytes: GL base internal format
  64231. // address: 36, size 4 bytes: pixel width
  64232. // address: 40, size 4 bytes: pixel height
  64233. // address: 44, size 4 bytes: pixel depth
  64234. // address: 48, size 4 bytes: number of array elements
  64235. // address: 52, size 4 bytes: number of faces
  64236. // address: 56, size 4 bytes: number of mipmap levels
  64237. // address: 60, size 4 bytes: bytes of key value data
  64238. // address: 64, size 4 bytes: key and value bytes size
  64239. // address: X, size 1 byte : key and value
  64240. // address: X, size 1 byte : value padding
  64241. // address: X, size 4 byte : image size
  64242. // ---------------------------------------
  64243. var byteArray = new Uint8Array(arrayBuffer),
  64244. uintArray = new Uint32Array(arrayBuffer),
  64245. ktxHeader = null,
  64246. imageSizeOffset = 16 + (uintArray[15] / 4) | 0,
  64247. imageSize = uintArray[imageSizeOffset],
  64248. glInternalFormat = uintArray[7],
  64249. compressionAlgorithm = 0;
  64250. if (byteArray[0] === 0xAB && byteArray[1] === 0x4B &&
  64251. byteArray[2] === 0x54 && byteArray[3] === 0x58 &&
  64252. byteArray[4] === 0x20 && byteArray[5] === 0x31 &&
  64253. byteArray[6] === 0x31 && byteArray[7] === 0xBB &&
  64254. byteArray[8] === 0x0D && byteArray[9] === 0x0A &&
  64255. byteArray[10] === 0x1A && byteArray[11] === 0x0A &&
  64256. //Check if internal GL format is supported by WebGL
  64257. [
  64258. // ETC1
  64259. 0x8D64,
  64260. // PVRTC
  64261. 0x8C00, 0x8C01, 0x8C02, 0x8C03,
  64262. // DXTC | S3TC
  64263. 0x83F0, 0x83F1, 0x83F2, 0x83F3
  64264. ].indexOf(glInternalFormat) >= 0) {
  64265. switch (glInternalFormat) {
  64266. case 0x8D64:
  64267. compressionAlgorithm = 'ETC1';
  64268. break;
  64269. case 0x8C00:
  64270. case 0x8C01:
  64271. case 0x8C02:
  64272. case 0x8C03:
  64273. compressionAlgorithm = 'PVRTC';
  64274. break;
  64275. case 0x83F0:
  64276. case 0x83F1:
  64277. case 0x83F2:
  64278. case 0x83F3:
  64279. compressionAlgorithm = 'S3TC';
  64280. break;
  64281. }
  64282. ktxHeader = {
  64283. complete: true,
  64284. fileFormat: 'KTX',
  64285. compressionAlgorithm: compressionAlgorithm,
  64286. endianness: uintArray[3],
  64287. glType: uintArray[4],
  64288. glTypeSize: uintArray[5],
  64289. glFormat: uintArray[6],
  64290. glInternalFormat: uintArray[7],
  64291. glBaseInternalFormat: uintArray[8],
  64292. width: uintArray[9],
  64293. height: uintArray[10],
  64294. pixelDepth: uintArray[11],
  64295. numberOfArrayElements: uintArray[12],
  64296. numberOfFaces: uintArray[13],
  64297. numberOfMipmapLevels: uintArray[14],
  64298. bytesOfKeyValueData: uintArray[15],
  64299. keyAndValueByteSize: uintArray[16],
  64300. imageSize: imageSize,
  64301. textureData: byteArray.subarray((imageSizeOffset + 1) * 4, imageSize + 100)
  64302. };
  64303. }
  64304. return ktxHeader;
  64305. },
  64306. /**
  64307. * Extract PKM header from loaded binary
  64308. *
  64309. * @method Phaser.LoaderParser.pkm
  64310. * @param {ArrayBuffer} arrayBuffer
  64311. * @return {object} The parsed PKM file including texture data.
  64312. */
  64313. pkm: function (arrayBuffer) {
  64314. // PKM header structure
  64315. // ---------------------------------------
  64316. // address: 0, size 4 bytes: for 'PKM '
  64317. // address: 4, size 2 bytes: for version
  64318. // address: 6, size 2 bytes: for type
  64319. // address: 8, size 2 bytes: for extended width
  64320. // address: 10, size 2 bytes: for extended height
  64321. // address: 12, size 2 bytes: for original width
  64322. // address: 14, size 2 bytes: for original height
  64323. // address: 16, texture data
  64324. // ---------------------------------------
  64325. var byteArray = new Uint8Array(arrayBuffer),
  64326. pkmHeader = null;
  64327. if (byteArray[0] === 0x50 &&
  64328. byteArray[1] === 0x4B &&
  64329. byteArray[2] === 0x4D &&
  64330. byteArray[3] === 0x20) {
  64331. pkmHeader = {
  64332. complete: true,
  64333. fileFormat: 'PKM',
  64334. compressionAlgorithm: 'ETC1',
  64335. format: ((byteArray[6] << 8 | byteArray[7])) & 0xFFFF,
  64336. width: ((byteArray[8] << 8 | byteArray[9])) & 0xFFFF,
  64337. height: ((byteArray[10] << 8 | byteArray[11])) & 0xFFFF,
  64338. originalWidth: ((byteArray[12] << 8 | byteArray[13])) & 0xFFFF,
  64339. originalHeight: ((byteArray[14] << 8 | byteArray[15])) & 0xFFFF,
  64340. textureData: byteArray.subarray(16, byteArray.length)
  64341. };
  64342. }
  64343. return pkmHeader;
  64344. }
  64345. };
  64346. /**
  64347. * @author Jeremy Dowell <jeremy@codevinsky.com>
  64348. * @author Richard Davey <rich@photonstorm.com>
  64349. * @copyright 2016 Photon Storm Ltd.
  64350. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  64351. */
  64352. /**
  64353. * Audio Sprites are a combination of audio files and a JSON configuration.
  64354. * The JSON follows the format of that created by https://github.com/tonistiigi/audiosprite
  64355. *
  64356. * @class Phaser.AudioSprite
  64357. * @constructor
  64358. * @param {Phaser.Game} game - Reference to the current game instance.
  64359. * @param {string} key - Asset key for the sound.
  64360. */
  64361. Phaser.AudioSprite = function (game, key) {
  64362. /**
  64363. * A reference to the currently running Game.
  64364. * @property {Phaser.Game} game
  64365. */
  64366. this.game = game;
  64367. /**
  64368. * Asset key for the Audio Sprite.
  64369. * @property {string} key
  64370. */
  64371. this.key = key;
  64372. /**
  64373. * JSON audio atlas object.
  64374. * @property {object} config
  64375. */
  64376. this.config = this.game.cache.getJSON(key + '-audioatlas');
  64377. /**
  64378. * If a sound is set to auto play, this holds the marker key of it.
  64379. * @property {string} autoplayKey
  64380. */
  64381. this.autoplayKey = null;
  64382. /**
  64383. * Is a sound set to autoplay or not?
  64384. * @property {boolean} autoplay
  64385. * @default
  64386. */
  64387. this.autoplay = false;
  64388. /**
  64389. * An object containing the Phaser.Sound objects for the Audio Sprite.
  64390. * @property {object} sounds
  64391. */
  64392. this.sounds = {};
  64393. for (var k in this.config.spritemap)
  64394. {
  64395. var marker = this.config.spritemap[k];
  64396. var sound = this.game.add.sound(this.key);
  64397. sound.addMarker(k, marker.start, (marker.end - marker.start), null, marker.loop);
  64398. this.sounds[k] = sound;
  64399. }
  64400. if (this.config.autoplay)
  64401. {
  64402. this.autoplayKey = this.config.autoplay;
  64403. this.play(this.autoplayKey);
  64404. this.autoplay = this.sounds[this.autoplayKey];
  64405. }
  64406. };
  64407. Phaser.AudioSprite.prototype = {
  64408. /**
  64409. * Play a sound with the given name.
  64410. *
  64411. * @method Phaser.AudioSprite#play
  64412. * @param {string} [marker] - The name of sound to play
  64413. * @param {number} [volume=1] - Volume of the sound you want to play. If none is given it will use the volume given to the Sound when it was created (which defaults to 1 if none was specified).
  64414. * @return {Phaser.Sound} This sound instance.
  64415. */
  64416. play: function (marker, volume) {
  64417. if (volume === undefined) { volume = 1; }
  64418. return this.sounds[marker].play(marker, null, volume);
  64419. },
  64420. /**
  64421. * Stop a sound with the given name.
  64422. *
  64423. * @method Phaser.AudioSprite#stop
  64424. * @param {string} [marker=''] - The name of sound to stop. If none is given it will stop all sounds in the audio sprite.
  64425. */
  64426. stop: function (marker) {
  64427. if (!marker)
  64428. {
  64429. for (var key in this.sounds)
  64430. {
  64431. this.sounds[key].stop();
  64432. }
  64433. }
  64434. else
  64435. {
  64436. this.sounds[marker].stop();
  64437. }
  64438. },
  64439. /**
  64440. * Get a sound with the given name.
  64441. *
  64442. * @method Phaser.AudioSprite#get
  64443. * @param {string} marker - The name of sound to get.
  64444. * @return {Phaser.Sound} The sound instance.
  64445. */
  64446. get: function(marker) {
  64447. return this.sounds[marker];
  64448. }
  64449. };
  64450. Phaser.AudioSprite.prototype.constructor = Phaser.AudioSprite;
  64451. /**
  64452. * @author Richard Davey <rich@photonstorm.com>
  64453. * @copyright 2016 Photon Storm Ltd.
  64454. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  64455. */
  64456. /**
  64457. * The Sound class constructor.
  64458. *
  64459. * @class Phaser.Sound
  64460. * @constructor
  64461. * @param {Phaser.Game} game - Reference to the current game instance.
  64462. * @param {string} key - Asset key for the sound.
  64463. * @param {number} [volume=1] - Default value for the volume, between 0 and 1.
  64464. * @param {boolean} [loop=false] - Whether or not the sound will loop.
  64465. */
  64466. Phaser.Sound = function (game, key, volume, loop, connect) {
  64467. if (volume === undefined) { volume = 1; }
  64468. if (loop === undefined) { loop = false; }
  64469. if (connect === undefined) { connect = game.sound.connectToMaster; }
  64470. /**
  64471. * A reference to the currently running Game.
  64472. * @property {Phaser.Game} game
  64473. */
  64474. this.game = game;
  64475. /**
  64476. * @property {string} name - Name of the sound.
  64477. */
  64478. this.name = key;
  64479. /**
  64480. * @property {string} key - Asset key for the sound.
  64481. */
  64482. this.key = key;
  64483. /**
  64484. * @property {boolean} loop - Whether or not the sound or current sound marker will loop.
  64485. */
  64486. this.loop = loop;
  64487. /**
  64488. * @property {object} markers - The sound markers.
  64489. */
  64490. this.markers = {};
  64491. /**
  64492. * @property {AudioContext} context - Reference to the AudioContext instance.
  64493. */
  64494. this.context = null;
  64495. /**
  64496. * @property {boolean} autoplay - Boolean indicating whether the sound should start automatically.
  64497. */
  64498. this.autoplay = false;
  64499. /**
  64500. * @property {number} totalDuration - The total duration of the sound in seconds.
  64501. */
  64502. this.totalDuration = 0;
  64503. /**
  64504. * @property {number} startTime - The time the sound starts at in ms (typically 0 unless starting from a marker).
  64505. * @default
  64506. */
  64507. this.startTime = 0;
  64508. /**
  64509. * @property {number} currentTime - The current time of sound playback in ms.
  64510. */
  64511. this.currentTime = 0;
  64512. /**
  64513. * @property {number} duration - The duration of the current sound marker in seconds.
  64514. */
  64515. this.duration = 0;
  64516. /**
  64517. * @property {number} durationMS - The duration of the current sound marker in ms.
  64518. */
  64519. this.durationMS = 0;
  64520. /**
  64521. * @property {number} position - The position of the current sound marker in ms.
  64522. */
  64523. this.position = 0;
  64524. /**
  64525. * @property {number} stopTime - The time the sound stopped in ms.
  64526. */
  64527. this.stopTime = 0;
  64528. /**
  64529. * @property {boolean} paused - true if the sound is paused, otherwise false.
  64530. * @default
  64531. */
  64532. this.paused = false;
  64533. /**
  64534. * @property {number} pausedPosition - The position the sound had reached when it was paused in ms.
  64535. */
  64536. this.pausedPosition = 0;
  64537. /**
  64538. * @property {number} pausedTime - The game time (ms) at which the sound was paused.
  64539. */
  64540. this.pausedTime = 0;
  64541. /**
  64542. * @property {boolean} isPlaying - true if the sound is currently playing, otherwise false.
  64543. * @default
  64544. */
  64545. this.isPlaying = false;
  64546. /**
  64547. * @property {string} currentMarker - The string ID of the currently playing marker, if any.
  64548. * @default
  64549. */
  64550. this.currentMarker = '';
  64551. /**
  64552. * @property {Phaser.Tween} fadeTween - The tween that fades the audio, set via Sound.fadeIn and Sound.fadeOut.
  64553. */
  64554. this.fadeTween = null;
  64555. /**
  64556. * @property {boolean} pendingPlayback - true if the sound file is pending playback
  64557. * @readonly
  64558. */
  64559. this.pendingPlayback = false;
  64560. /**
  64561. * @property {boolean} override - if true when you play this sound it will always start from the beginning.
  64562. * @default
  64563. */
  64564. this.override = false;
  64565. /**
  64566. * @property {boolean} allowMultiple - This will allow you to have multiple instances of this Sound playing at once. This is only useful when running under Web Audio, and we recommend you implement a local pooling system to not flood the sound channels.
  64567. * @default
  64568. */
  64569. this.allowMultiple = false;
  64570. /**
  64571. * @property {boolean} usingWebAudio - true if this sound is being played with Web Audio.
  64572. * @readonly
  64573. */
  64574. this.usingWebAudio = this.game.sound.usingWebAudio;
  64575. /**
  64576. * @property {boolean} usingAudioTag - true if the sound is being played via the Audio tag.
  64577. */
  64578. this.usingAudioTag = this.game.sound.usingAudioTag;
  64579. /**
  64580. * @property {object} externalNode - If defined this Sound won't connect to the SoundManager master gain node, but will instead connect to externalNode.
  64581. */
  64582. this.externalNode = null;
  64583. /**
  64584. * @property {object} masterGainNode - The master gain node in a Web Audio system.
  64585. */
  64586. this.masterGainNode = null;
  64587. /**
  64588. * @property {object} gainNode - The gain node in a Web Audio system.
  64589. */
  64590. this.gainNode = null;
  64591. /**
  64592. * @property {object} _sound - Internal var.
  64593. * @private
  64594. */
  64595. this._sound = null;
  64596. /**
  64597. * @property {object} _globalVolume - Internal var for keeping track of global volume when using AudioTag
  64598. * @private
  64599. */
  64600. this._globalVolume = 1;
  64601. /**
  64602. * @property {boolean} _markedToDelete - When audio stops, disconnect Web Audio nodes.
  64603. * @private
  64604. */
  64605. this._markedToDelete = false;
  64606. /**
  64607. * @property {boolean} _removeFromSoundManager - When audio stops, remove it from the Sound Manager and destroy it.
  64608. * @private
  64609. */
  64610. this._removeFromSoundManager = false;
  64611. if (this.usingWebAudio)
  64612. {
  64613. this.context = this.game.sound.context;
  64614. this.masterGainNode = this.game.sound.masterGain;
  64615. if (this.context.createGain === undefined)
  64616. {
  64617. this.gainNode = this.context.createGainNode();
  64618. }
  64619. else
  64620. {
  64621. this.gainNode = this.context.createGain();
  64622. }
  64623. this.gainNode.gain.value = volume * this.game.sound.volume;
  64624. if (connect)
  64625. {
  64626. this.gainNode.connect(this.masterGainNode);
  64627. }
  64628. }
  64629. else if (this.usingAudioTag)
  64630. {
  64631. if (this.game.cache.getSound(key) && this.game.cache.isSoundReady(key))
  64632. {
  64633. this._sound = this.game.cache.getSoundData(key);
  64634. this.totalDuration = 0;
  64635. if (this._sound.duration)
  64636. {
  64637. this.totalDuration = this._sound.duration;
  64638. }
  64639. }
  64640. else
  64641. {
  64642. this.game.cache.onSoundUnlock.add(this.soundHasUnlocked, this);
  64643. }
  64644. }
  64645. /**
  64646. * @property {Phaser.Signal} onDecoded - The onDecoded event is dispatched when the sound has finished decoding (typically for mp3 files)
  64647. */
  64648. this.onDecoded = new Phaser.Signal();
  64649. /**
  64650. * @property {Phaser.Signal} onPlay - The onPlay event is dispatched each time this sound is played.
  64651. */
  64652. this.onPlay = new Phaser.Signal();
  64653. /**
  64654. * @property {Phaser.Signal} onPause - The onPause event is dispatched when this sound is paused.
  64655. */
  64656. this.onPause = new Phaser.Signal();
  64657. /**
  64658. * @property {Phaser.Signal} onResume - The onResume event is dispatched when this sound is resumed from a paused state.
  64659. */
  64660. this.onResume = new Phaser.Signal();
  64661. /**
  64662. * @property {Phaser.Signal} onLoop - The onLoop event is dispatched when this sound loops during playback.
  64663. */
  64664. this.onLoop = new Phaser.Signal();
  64665. /**
  64666. * @property {Phaser.Signal} onStop - The onStop event is dispatched when this sound stops playback.
  64667. */
  64668. this.onStop = new Phaser.Signal();
  64669. /**
  64670. * @property {Phaser.Signal} onMute - The onMute event is dispatched when this sound is muted.
  64671. */
  64672. this.onMute = new Phaser.Signal();
  64673. /**
  64674. * @property {Phaser.Signal} onMarkerComplete - The onMarkerComplete event is dispatched when a marker within this sound completes playback.
  64675. */
  64676. this.onMarkerComplete = new Phaser.Signal();
  64677. /**
  64678. * @property {Phaser.Signal} onFadeComplete - The onFadeComplete event is dispatched when this sound finishes fading either in or out.
  64679. */
  64680. this.onFadeComplete = new Phaser.Signal();
  64681. /**
  64682. * @property {number} _volume - The global audio volume. A value between 0 (silence) and 1 (full volume).
  64683. * @private
  64684. */
  64685. this._volume = volume;
  64686. /**
  64687. * @property {any} _buffer - Decoded data buffer / Audio tag.
  64688. * @private
  64689. */
  64690. this._buffer = null;
  64691. /**
  64692. * @property {boolean} _muted - Boolean indicating whether the sound is muted or not.
  64693. * @private
  64694. */
  64695. this._muted = false;
  64696. /**
  64697. * @property {number} _tempMarker - Internal marker var.
  64698. * @private
  64699. */
  64700. this._tempMarker = 0;
  64701. /**
  64702. * @property {number} _tempPosition - Internal marker var.
  64703. * @private
  64704. */
  64705. this._tempPosition = 0;
  64706. /**
  64707. * @property {number} _tempVolume - Internal marker var.
  64708. * @private
  64709. */
  64710. this._tempVolume = 0;
  64711. /**
  64712. * @property {number} _tempPause - Internal marker var.
  64713. * @private
  64714. */
  64715. this._tempPause = 0;
  64716. /**
  64717. * @property {number} _muteVolume - Internal cache var.
  64718. * @private
  64719. */
  64720. this._muteVolume = 0;
  64721. /**
  64722. * @property {boolean} _tempLoop - Internal cache var.
  64723. * @private
  64724. */
  64725. this._tempLoop = 0;
  64726. /**
  64727. * @property {boolean} _paused - Was this sound paused via code or a game event?
  64728. * @private
  64729. */
  64730. this._paused = false;
  64731. /**
  64732. * @property {boolean} _onDecodedEventDispatched - Was the onDecoded event dispatched?
  64733. * @private
  64734. */
  64735. this._onDecodedEventDispatched = false;
  64736. };
  64737. Phaser.Sound.prototype = {
  64738. /**
  64739. * Called automatically when this sound is unlocked.
  64740. * @method Phaser.Sound#soundHasUnlocked
  64741. * @param {string} key - The Phaser.Cache key of the sound file to check for decoding.
  64742. * @protected
  64743. */
  64744. soundHasUnlocked: function (key) {
  64745. if (key === this.key)
  64746. {
  64747. this._sound = this.game.cache.getSoundData(this.key);
  64748. this.totalDuration = this._sound.duration;
  64749. }
  64750. },
  64751. /**
  64752. * Adds a marker into the current Sound. A marker is represented by a unique key and a start time and duration.
  64753. * This allows you to bundle multiple sounds together into a single audio file and use markers to jump between them for playback.
  64754. *
  64755. * @method Phaser.Sound#addMarker
  64756. * @param {string} name - A unique name for this marker, i.e. 'explosion', 'gunshot', etc.
  64757. * @param {number} start - The start point of this marker in the audio file, given in seconds. 2.5 = 2500ms, 0.5 = 500ms, etc.
  64758. * @param {number} [duration=1] - The duration of the marker in seconds. 2.5 = 2500ms, 0.5 = 500ms, etc.
  64759. * @param {number} [volume=1] - The volume the sound will play back at, between 0 (silent) and 1 (full volume).
  64760. * @param {boolean} [loop=false] - Sets if the sound will loop or not.
  64761. */
  64762. addMarker: function (name, start, duration, volume, loop) {
  64763. if (duration === undefined || duration === null) { duration = 1; }
  64764. if (volume === undefined || volume === null) { volume = 1; }
  64765. if (loop === undefined) { loop = false; }
  64766. this.markers[name] = {
  64767. name: name,
  64768. start: start,
  64769. stop: start + duration,
  64770. volume: volume,
  64771. duration: duration,
  64772. durationMS: duration * 1000,
  64773. loop: loop
  64774. };
  64775. },
  64776. /**
  64777. * Removes a marker from the sound.
  64778. * @method Phaser.Sound#removeMarker
  64779. * @param {string} name - The key of the marker to remove.
  64780. */
  64781. removeMarker: function (name) {
  64782. delete this.markers[name];
  64783. },
  64784. /**
  64785. * Called automatically by the AudioContext when the sound stops playing.
  64786. * Doesn't get called if the sound is set to loop or is a section of an Audio Sprite.
  64787. *
  64788. * @method Phaser.Sound#onEndedHandler
  64789. * @protected
  64790. */
  64791. onEndedHandler: function () {
  64792. this._sound.onended = null;
  64793. this.isPlaying = false;
  64794. this.currentTime = this.durationMS;
  64795. this.stop();
  64796. if (this._markedToDelete)
  64797. {
  64798. if (this.externalNode)
  64799. {
  64800. this._sound.disconnect(this.externalNode);
  64801. }
  64802. else if (this.gainNode)
  64803. {
  64804. this._sound.disconnect(this.gainNode);
  64805. }
  64806. if (this._removeFromSoundManager)
  64807. {
  64808. this.game.sound.remove(this);
  64809. }
  64810. else
  64811. {
  64812. this.markers = {};
  64813. this.context = null;
  64814. this._buffer = null;
  64815. this.externalNode = null;
  64816. this.onDecoded.dispose();
  64817. this.onPlay.dispose();
  64818. this.onPause.dispose();
  64819. this.onResume.dispose();
  64820. this.onLoop.dispose();
  64821. this.onStop.dispose();
  64822. this.onMute.dispose();
  64823. this.onMarkerComplete.dispose();
  64824. }
  64825. }
  64826. },
  64827. /**
  64828. * Called automatically by Phaser.SoundManager.
  64829. * @method Phaser.Sound#update
  64830. * @protected
  64831. */
  64832. update: function () {
  64833. if (!this.game.cache.checkSoundKey(this.key))
  64834. {
  64835. this.destroy();
  64836. return;
  64837. }
  64838. if (this.isDecoded && !this._onDecodedEventDispatched)
  64839. {
  64840. this.onDecoded.dispatch(this);
  64841. this._onDecodedEventDispatched = true;
  64842. }
  64843. if (this.pendingPlayback && this.game.cache.isSoundReady(this.key))
  64844. {
  64845. this.pendingPlayback = false;
  64846. this.play(this._tempMarker, this._tempPosition, this._tempVolume, this._tempLoop);
  64847. }
  64848. if (this.isPlaying)
  64849. {
  64850. this.currentTime = this.game.time.time - this.startTime;
  64851. if (this.currentTime >= this.durationMS)
  64852. {
  64853. if (this.usingWebAudio)
  64854. {
  64855. if (this.loop)
  64856. {
  64857. // won't work with markers, needs to reset the position
  64858. this.onLoop.dispatch(this);
  64859. // Gets reset by the play function
  64860. this.isPlaying = false;
  64861. if (this.currentMarker === '')
  64862. {
  64863. this.currentTime = 0;
  64864. this.startTime = this.game.time.time;
  64865. this.isPlaying = true; // play not called again in this case
  64866. }
  64867. else
  64868. {
  64869. this.onMarkerComplete.dispatch(this.currentMarker, this);
  64870. this.play(this.currentMarker, 0, this.volume, true, true);
  64871. }
  64872. }
  64873. else
  64874. {
  64875. // Stop if we're using an audio marker, otherwise we let onended handle it
  64876. if (this.currentMarker !== '')
  64877. {
  64878. this.stop();
  64879. }
  64880. }
  64881. }
  64882. else
  64883. {
  64884. if (this.loop)
  64885. {
  64886. this.onLoop.dispatch(this);
  64887. if (this.currentMarker === '')
  64888. {
  64889. this.currentTime = 0;
  64890. this.startTime = this.game.time.time;
  64891. }
  64892. // Gets reset by the play function
  64893. this.isPlaying = false;
  64894. this.play(this.currentMarker, 0, this.volume, true, true);
  64895. }
  64896. else
  64897. {
  64898. this.stop();
  64899. }
  64900. }
  64901. }
  64902. }
  64903. },
  64904. /**
  64905. * Loops this entire sound. If you need to loop a section of it then use Sound.play and the marker and loop parameters.
  64906. *
  64907. * @method Phaser.Sound#loopFull
  64908. * @param {number} [volume=1] - Volume of the sound you want to play. If none is given it will use the volume given to the Sound when it was created (which defaults to 1 if none was specified).
  64909. * @return {Phaser.Sound} This sound instance.
  64910. */
  64911. loopFull: function (volume) {
  64912. return this.play(null, 0, volume, true);
  64913. },
  64914. /**
  64915. * Play this sound, or a marked section of it.
  64916. *
  64917. * @method Phaser.Sound#play
  64918. * @param {string} [marker=''] - If you want to play a marker then give the key here, otherwise leave blank to play the full sound.
  64919. * @param {number} [position=0] - The starting position to play the sound from - this is ignored if you provide a marker.
  64920. * @param {number} [volume=1] - Volume of the sound you want to play. If none is given it will use the volume given to the Sound when it was created (which defaults to 1 if none was specified).
  64921. * @param {boolean} [loop=false] - Loop when finished playing? If not using a marker / audio sprite the looping will be done via the WebAudio loop property, otherwise it's time based.
  64922. * @param {boolean} [forceRestart=true] - If the sound is already playing you can set forceRestart to restart it from the beginning.
  64923. * @return {Phaser.Sound} This sound instance.
  64924. */
  64925. play: function (marker, position, volume, loop, forceRestart) {
  64926. if (marker === undefined || marker === false || marker === null) { marker = ''; }
  64927. if (forceRestart === undefined) { forceRestart = true; }
  64928. if (this.isPlaying && !this.allowMultiple && !forceRestart && !this.override)
  64929. {
  64930. // Use Restart instead
  64931. return this;
  64932. }
  64933. if (this._sound && this.isPlaying && !this.allowMultiple && (this.override || forceRestart))
  64934. {
  64935. if (this.usingWebAudio)
  64936. {
  64937. if (this._sound.stop === undefined)
  64938. {
  64939. this._sound.noteOff(0);
  64940. }
  64941. else
  64942. {
  64943. try {
  64944. this._sound.stop(0);
  64945. }
  64946. catch (e) {
  64947. }
  64948. }
  64949. if (this.externalNode)
  64950. {
  64951. this._sound.disconnect(this.externalNode);
  64952. }
  64953. else if (this.gainNode)
  64954. {
  64955. this._sound.disconnect(this.gainNode);
  64956. }
  64957. }
  64958. else if (this.usingAudioTag)
  64959. {
  64960. this._sound.pause();
  64961. this._sound.currentTime = 0;
  64962. }
  64963. this.isPlaying = false;
  64964. }
  64965. if (marker === '' && Object.keys(this.markers).length > 0)
  64966. {
  64967. // If they didn't specify a marker but this is an audio sprite,
  64968. // we should never play the entire thing
  64969. return this;
  64970. }
  64971. if (marker !== '')
  64972. {
  64973. if (this.markers[marker])
  64974. {
  64975. this.currentMarker = marker;
  64976. // Playing a marker? Then we default to the marker values
  64977. this.position = this.markers[marker].start;
  64978. this.volume = this.markers[marker].volume;
  64979. this.loop = this.markers[marker].loop;
  64980. this.duration = this.markers[marker].duration;
  64981. this.durationMS = this.markers[marker].durationMS;
  64982. if (typeof volume !== 'undefined')
  64983. {
  64984. this.volume = volume;
  64985. }
  64986. if (typeof loop !== 'undefined')
  64987. {
  64988. this.loop = loop;
  64989. }
  64990. this._tempMarker = marker;
  64991. this._tempPosition = this.position;
  64992. this._tempVolume = this.volume;
  64993. this._tempLoop = this.loop;
  64994. }
  64995. else
  64996. {
  64997. console.warn("Phaser.Sound.play: audio marker " + marker + " doesn't exist");
  64998. return this;
  64999. }
  65000. }
  65001. else
  65002. {
  65003. position = position || 0;
  65004. if (volume === undefined) { volume = this._volume; }
  65005. if (loop === undefined) { loop = this.loop; }
  65006. this.position = Math.max(0, position);
  65007. this.volume = volume;
  65008. this.loop = loop;
  65009. this.duration = 0;
  65010. this.durationMS = 0;
  65011. this._tempMarker = marker;
  65012. this._tempPosition = position;
  65013. this._tempVolume = volume;
  65014. this._tempLoop = loop;
  65015. }
  65016. if (this.usingWebAudio)
  65017. {
  65018. // Does the sound need decoding?
  65019. if (this.game.cache.isSoundDecoded(this.key))
  65020. {
  65021. this._sound = this.context.createBufferSource();
  65022. if (this.externalNode)
  65023. {
  65024. this._sound.connect(this.externalNode);
  65025. }
  65026. else
  65027. {
  65028. this._sound.connect(this.gainNode);
  65029. }
  65030. this._buffer = this.game.cache.getSoundData(this.key);
  65031. this._sound.buffer = this._buffer;
  65032. if (this.loop && marker === '')
  65033. {
  65034. this._sound.loop = true;
  65035. }
  65036. if (!this.loop && marker === '')
  65037. {
  65038. this._sound.onended = this.onEndedHandler.bind(this);
  65039. }
  65040. this.totalDuration = this._sound.buffer.duration;
  65041. if (this.duration === 0)
  65042. {
  65043. this.duration = this.totalDuration;
  65044. this.durationMS = Math.ceil(this.totalDuration * 1000);
  65045. }
  65046. // Useful to cache this somewhere perhaps?
  65047. if (this._sound.start === undefined)
  65048. {
  65049. this._sound.noteGrainOn(0, this.position, this.duration);
  65050. }
  65051. else
  65052. {
  65053. if (this.loop && marker === '')
  65054. {
  65055. this._sound.start(0, 0);
  65056. }
  65057. else
  65058. {
  65059. this._sound.start(0, this.position, this.duration);
  65060. }
  65061. }
  65062. this.isPlaying = true;
  65063. this.startTime = this.game.time.time;
  65064. this.currentTime = 0;
  65065. this.stopTime = this.startTime + this.durationMS;
  65066. this.onPlay.dispatch(this);
  65067. }
  65068. else
  65069. {
  65070. this.pendingPlayback = true;
  65071. if (this.game.cache.getSound(this.key) && this.game.cache.getSound(this.key).isDecoding === false)
  65072. {
  65073. this.game.sound.decode(this.key, this);
  65074. }
  65075. }
  65076. }
  65077. else
  65078. {
  65079. if (this.game.cache.getSound(this.key) && this.game.cache.getSound(this.key).locked)
  65080. {
  65081. this.game.cache.reloadSound(this.key);
  65082. this.pendingPlayback = true;
  65083. }
  65084. else
  65085. {
  65086. if (this._sound && (this.game.device.cocoonJS || this._sound.readyState === 4))
  65087. {
  65088. this._sound.play();
  65089. // This doesn't become available until you call play(), wonderful ...
  65090. this.totalDuration = this._sound.duration;
  65091. if (this.duration === 0)
  65092. {
  65093. this.duration = this.totalDuration;
  65094. this.durationMS = this.totalDuration * 1000;
  65095. }
  65096. this._sound.currentTime = this.position;
  65097. this._sound.muted = this._muted;
  65098. if (this._muted || this.game.sound.mute)
  65099. {
  65100. this._sound.volume = 0;
  65101. }
  65102. else
  65103. {
  65104. this._sound.volume = this._volume;
  65105. }
  65106. this.isPlaying = true;
  65107. this.startTime = this.game.time.time;
  65108. this.currentTime = 0;
  65109. this.stopTime = this.startTime + this.durationMS;
  65110. this.onPlay.dispatch(this);
  65111. }
  65112. else
  65113. {
  65114. this.pendingPlayback = true;
  65115. }
  65116. }
  65117. }
  65118. return this;
  65119. },
  65120. /**
  65121. * Restart the sound, or a marked section of it.
  65122. *
  65123. * @method Phaser.Sound#restart
  65124. * @param {string} [marker=''] - If you want to play a marker then give the key here, otherwise leave blank to play the full sound.
  65125. * @param {number} [position=0] - The starting position to play the sound from - this is ignored if you provide a marker.
  65126. * @param {number} [volume=1] - Volume of the sound you want to play.
  65127. * @param {boolean} [loop=false] - Loop when it finished playing?
  65128. */
  65129. restart: function (marker, position, volume, loop) {
  65130. marker = marker || '';
  65131. position = position || 0;
  65132. volume = volume || 1;
  65133. if (loop === undefined) { loop = false; }
  65134. this.play(marker, position, volume, loop, true);
  65135. },
  65136. /**
  65137. * Pauses the sound.
  65138. *
  65139. * @method Phaser.Sound#pause
  65140. */
  65141. pause: function () {
  65142. if (this.isPlaying && this._sound)
  65143. {
  65144. this.paused = true;
  65145. this.pausedPosition = this.currentTime;
  65146. this.pausedTime = this.game.time.time;
  65147. this._tempPause = this._sound.currentTime;
  65148. this.onPause.dispatch(this);
  65149. this.stop();
  65150. }
  65151. },
  65152. /**
  65153. * Resumes the sound.
  65154. *
  65155. * @method Phaser.Sound#resume
  65156. */
  65157. resume: function () {
  65158. if (this.paused && this._sound)
  65159. {
  65160. if (this.usingWebAudio)
  65161. {
  65162. var p = Math.max(0, this.position + (this.pausedPosition / 1000));
  65163. this._sound = this.context.createBufferSource();
  65164. this._sound.buffer = this._buffer;
  65165. if (this.externalNode)
  65166. {
  65167. this._sound.connect(this.externalNode);
  65168. }
  65169. else
  65170. {
  65171. this._sound.connect(this.gainNode);
  65172. }
  65173. if (this.loop)
  65174. {
  65175. this._sound.loop = true;
  65176. }
  65177. if (!this.loop && this.currentMarker === '')
  65178. {
  65179. this._sound.onended = this.onEndedHandler.bind(this);
  65180. }
  65181. var duration = this.duration - (this.pausedPosition / 1000);
  65182. if (this._sound.start === undefined)
  65183. {
  65184. this._sound.noteGrainOn(0, p, duration);
  65185. //this._sound.noteOn(0); // the zero is vitally important, crashes iOS6 without it
  65186. }
  65187. else
  65188. {
  65189. if (this.loop && this.game.device.chrome)
  65190. {
  65191. // Handle chrome bug: https://code.google.com/p/chromium/issues/detail?id=457099
  65192. if (this.game.device.chromeVersion === 42)
  65193. {
  65194. this._sound.start(0);
  65195. }
  65196. else
  65197. {
  65198. this._sound.start(0, p);
  65199. }
  65200. }
  65201. else
  65202. {
  65203. this._sound.start(0, p, duration);
  65204. }
  65205. }
  65206. }
  65207. else
  65208. {
  65209. this._sound.currentTime = this._tempPause;
  65210. this._sound.play();
  65211. }
  65212. this.isPlaying = true;
  65213. this.paused = false;
  65214. this.startTime += (this.game.time.time - this.pausedTime);
  65215. this.onResume.dispatch(this);
  65216. }
  65217. },
  65218. /**
  65219. * Stop playing this sound.
  65220. *
  65221. * @method Phaser.Sound#stop
  65222. */
  65223. stop: function () {
  65224. if (this.isPlaying && this._sound)
  65225. {
  65226. if (this.usingWebAudio)
  65227. {
  65228. if (this._sound.stop === undefined)
  65229. {
  65230. this._sound.noteOff(0);
  65231. }
  65232. else
  65233. {
  65234. try {
  65235. this._sound.stop(0);
  65236. }
  65237. catch (e)
  65238. {
  65239. // Thanks Android 4.4
  65240. }
  65241. }
  65242. if (this.externalNode)
  65243. {
  65244. this._sound.disconnect(this.externalNode);
  65245. }
  65246. else if (this.gainNode)
  65247. {
  65248. this._sound.disconnect(this.gainNode);
  65249. }
  65250. }
  65251. else if (this.usingAudioTag)
  65252. {
  65253. this._sound.pause();
  65254. this._sound.currentTime = 0;
  65255. }
  65256. }
  65257. this.pendingPlayback = false;
  65258. this.isPlaying = false;
  65259. if (!this.paused)
  65260. {
  65261. var prevMarker = this.currentMarker;
  65262. if (this.currentMarker !== '')
  65263. {
  65264. this.onMarkerComplete.dispatch(this.currentMarker, this);
  65265. }
  65266. this.currentMarker = '';
  65267. if (this.fadeTween !== null)
  65268. {
  65269. this.fadeTween.stop();
  65270. }
  65271. this.onStop.dispatch(this, prevMarker);
  65272. }
  65273. },
  65274. /**
  65275. * Starts this sound playing (or restarts it if already doing so) and sets the volume to zero.
  65276. * Then increases the volume from 0 to 1 over the duration specified.
  65277. *
  65278. * At the end of the fade Sound.onFadeComplete is dispatched with this Sound object as the first parameter,
  65279. * and the final volume (1) as the second parameter.
  65280. *
  65281. * @method Phaser.Sound#fadeIn
  65282. * @param {number} [duration=1000] - The time in milliseconds over which the Sound should fade in.
  65283. * @param {boolean} [loop=false] - Should the Sound be set to loop? Note that this doesn't cause the fade to repeat.
  65284. * @param {string} [marker=(current marker)] - The marker to start at; defaults to the current (last played) marker. To start playing from the beginning specify specify a marker of `''`.
  65285. */
  65286. fadeIn: function (duration, loop, marker) {
  65287. if (loop === undefined) { loop = false; }
  65288. if (marker === undefined) { marker = this.currentMarker; }
  65289. if (this.paused)
  65290. {
  65291. return;
  65292. }
  65293. this.play(marker, 0, 0, loop);
  65294. this.fadeTo(duration, 1);
  65295. },
  65296. /**
  65297. * Decreases the volume of this Sound from its current value to 0 over the duration specified.
  65298. * At the end of the fade Sound.onFadeComplete is dispatched with this Sound object as the first parameter,
  65299. * and the final volume (0) as the second parameter.
  65300. *
  65301. * @method Phaser.Sound#fadeOut
  65302. * @param {number} [duration=1000] - The time in milliseconds over which the Sound should fade out.
  65303. */
  65304. fadeOut: function (duration) {
  65305. this.fadeTo(duration, 0);
  65306. },
  65307. /**
  65308. * Fades the volume of this Sound from its current value to the given volume over the duration specified.
  65309. * At the end of the fade Sound.onFadeComplete is dispatched with this Sound object as the first parameter,
  65310. * and the final volume (volume) as the second parameter.
  65311. *
  65312. * @method Phaser.Sound#fadeTo
  65313. * @param {number} [duration=1000] - The time in milliseconds during which the Sound should fade out.
  65314. * @param {number} [volume] - The volume which the Sound should fade to. This is a value between 0 and 1.
  65315. */
  65316. fadeTo: function (duration, volume) {
  65317. if (!this.isPlaying || this.paused || volume === this.volume)
  65318. {
  65319. return;
  65320. }
  65321. if (duration === undefined) { duration = 1000; }
  65322. if (volume === undefined)
  65323. {
  65324. console.warn("Phaser.Sound.fadeTo: No Volume Specified.");
  65325. return;
  65326. }
  65327. this.fadeTween = this.game.add.tween(this).to( { volume: volume }, duration, Phaser.Easing.Linear.None, true);
  65328. this.fadeTween.onComplete.add(this.fadeComplete, this);
  65329. },
  65330. /**
  65331. * Internal handler for Sound.fadeIn, Sound.fadeOut and Sound.fadeTo.
  65332. *
  65333. * @method Phaser.Sound#fadeComplete
  65334. * @private
  65335. */
  65336. fadeComplete: function () {
  65337. this.onFadeComplete.dispatch(this, this.volume);
  65338. if (this.volume === 0)
  65339. {
  65340. this.stop();
  65341. }
  65342. },
  65343. /**
  65344. * Called automatically by SoundManager.volume.
  65345. *
  65346. * Sets the volume of AudioTag Sounds as a percentage of the Global Volume.
  65347. *
  65348. * You should not normally call this directly.
  65349. *
  65350. * @method Phaser.Sound#updateGlobalVolume
  65351. * @protected
  65352. * @param {float} globalVolume - The global SoundManager volume.
  65353. */
  65354. updateGlobalVolume: function (globalVolume) {
  65355. // this._volume is the % of the global volume this sound should be played at
  65356. if (this.usingAudioTag && this._sound)
  65357. {
  65358. this._globalVolume = globalVolume;
  65359. this._sound.volume = this._globalVolume * this._volume;
  65360. }
  65361. },
  65362. /**
  65363. * Destroys this sound and all associated events and removes it from the SoundManager.
  65364. *
  65365. * @method Phaser.Sound#destroy
  65366. * @param {boolean} [remove=true] - If true this Sound is automatically removed from the SoundManager.
  65367. */
  65368. destroy: function (remove) {
  65369. if (remove === undefined) { remove = true; }
  65370. this._markedToDelete = true;
  65371. this._removeFromSoundManager = remove;
  65372. this.stop();
  65373. if (remove)
  65374. {
  65375. this.game.sound.remove(this);
  65376. }
  65377. else
  65378. {
  65379. this.markers = {};
  65380. this.context = null;
  65381. this._buffer = null;
  65382. this.externalNode = null;
  65383. this.onDecoded.dispose();
  65384. this.onPlay.dispose();
  65385. this.onPause.dispose();
  65386. this.onResume.dispose();
  65387. this.onLoop.dispose();
  65388. this.onStop.dispose();
  65389. this.onMute.dispose();
  65390. this.onMarkerComplete.dispose();
  65391. }
  65392. }
  65393. };
  65394. Phaser.Sound.prototype.constructor = Phaser.Sound;
  65395. /**
  65396. * @name Phaser.Sound#isDecoding
  65397. * @property {boolean} isDecoding - Returns true if the sound file is still decoding.
  65398. * @readonly
  65399. */
  65400. Object.defineProperty(Phaser.Sound.prototype, "isDecoding", {
  65401. get: function () {
  65402. return this.game.cache.getSound(this.key).isDecoding;
  65403. }
  65404. });
  65405. /**
  65406. * @name Phaser.Sound#isDecoded
  65407. * @property {boolean} isDecoded - Returns true if the sound file has decoded.
  65408. * @readonly
  65409. */
  65410. Object.defineProperty(Phaser.Sound.prototype, "isDecoded", {
  65411. get: function () {
  65412. return this.game.cache.isSoundDecoded(this.key);
  65413. }
  65414. });
  65415. /**
  65416. * @name Phaser.Sound#mute
  65417. * @property {boolean} mute - Gets or sets the muted state of this sound.
  65418. */
  65419. Object.defineProperty(Phaser.Sound.prototype, "mute", {
  65420. get: function () {
  65421. return (this._muted || this.game.sound.mute);
  65422. },
  65423. set: function (value) {
  65424. value = value || false;
  65425. if (value === this._muted)
  65426. {
  65427. return;
  65428. }
  65429. if (value)
  65430. {
  65431. this._muted = true;
  65432. this._muteVolume = this._tempVolume;
  65433. if (this.usingWebAudio)
  65434. {
  65435. this.gainNode.gain.value = 0;
  65436. }
  65437. else if (this.usingAudioTag && this._sound)
  65438. {
  65439. this._sound.volume = 0;
  65440. }
  65441. }
  65442. else
  65443. {
  65444. this._muted = false;
  65445. if (this.usingWebAudio)
  65446. {
  65447. this.gainNode.gain.value = this._muteVolume;
  65448. }
  65449. else if (this.usingAudioTag && this._sound)
  65450. {
  65451. this._sound.volume = this._muteVolume;
  65452. }
  65453. }
  65454. this.onMute.dispatch(this);
  65455. }
  65456. });
  65457. /**
  65458. * @name Phaser.Sound#volume
  65459. * @property {number} volume - Gets or sets the volume of this sound, a value between 0 and 1. The value given is clamped to the range 0 to 1.
  65460. */
  65461. Object.defineProperty(Phaser.Sound.prototype, "volume", {
  65462. get: function () {
  65463. return this._volume;
  65464. },
  65465. set: function (value) {
  65466. // Causes an Index size error if you don't clamp the value
  65467. if (this.usingAudioTag)
  65468. {
  65469. value = this.game.math.clamp(value, 0, 1);
  65470. }
  65471. if (this._muted)
  65472. {
  65473. this._muteVolume = value;
  65474. return;
  65475. }
  65476. this._tempVolume = value;
  65477. this._volume = value;
  65478. if (this.usingWebAudio)
  65479. {
  65480. this.gainNode.gain.value = value;
  65481. }
  65482. else if (this.usingAudioTag && this._sound)
  65483. {
  65484. this._sound.volume = this._globalVolume * value;
  65485. }
  65486. }
  65487. });
  65488. /**
  65489. * @author Richard Davey <rich@photonstorm.com>
  65490. * @copyright 2016 Photon Storm Ltd.
  65491. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  65492. */
  65493. /**
  65494. * The Sound Manager is responsible for playing back audio via either the Legacy HTML Audio tag or via Web Audio if the browser supports it.
  65495. * Note: On Firefox 25+ on Linux if you have media.gstreamer disabled in about:config then it cannot play back mp3 or m4a files.
  65496. * The audio file type and the encoding of those files are extremely important. Not all browsers can play all audio formats.
  65497. * There is a good guide to what's supported here: http://hpr.dogphilosophy.net/test/
  65498. *
  65499. * If you are reloading a Phaser Game on a page that never properly refreshes (such as in an AngularJS project) then you will quickly run out
  65500. * of AudioContext nodes. If this is the case create a global var called {@link PhaserGlobal} on the window object before creating the game. The active
  65501. * AudioContext will then be saved to `window.PhaserGlobal.audioContext` when the Phaser game is destroyed, and re-used when it starts again.
  65502. *
  65503. * Mobile warning: There are some mobile devices (certain iPad 2 and iPad Mini revisions) that cannot play 48000 Hz audio.
  65504. * When they try to play the audio becomes extremely distorted and buzzes, eventually crashing the sound system.
  65505. * The solution is to use a lower encoding rate such as 44100 Hz. Sometimes the audio context will
  65506. * be created with a sampleRate of 48000. If this happens and audio distorts you should re-create the context.
  65507. *
  65508. * @class Phaser.SoundManager
  65509. * @constructor
  65510. * @param {Phaser.Game} game - Reference to the current game instance.
  65511. */
  65512. Phaser.SoundManager = function (game) {
  65513. /**
  65514. * @property {Phaser.Game} game - Local reference to game.
  65515. */
  65516. this.game = game;
  65517. /**
  65518. * @property {Phaser.Signal} onSoundDecode - The event dispatched when a sound decodes (typically only for mp3 files)
  65519. */
  65520. this.onSoundDecode = new Phaser.Signal();
  65521. /**
  65522. * This signal is dispatched whenever the global volume changes. The new volume is passed as the only parameter to your callback.
  65523. * @property {Phaser.Signal} onVolumeChange
  65524. */
  65525. this.onVolumeChange = new Phaser.Signal();
  65526. /**
  65527. * This signal is dispatched when the SoundManager is globally muted, either directly via game code or as a result of the game pausing.
  65528. * @property {Phaser.Signal} onMute
  65529. */
  65530. this.onMute = new Phaser.Signal();
  65531. /**
  65532. * This signal is dispatched when the SoundManager is globally un-muted, either directly via game code or as a result of the game resuming from a pause.
  65533. * @property {Phaser.Signal} onUnMute
  65534. */
  65535. this.onUnMute = new Phaser.Signal();
  65536. /**
  65537. * @property {AudioContext} context - The AudioContext being used for playback.
  65538. * @default
  65539. */
  65540. this.context = null;
  65541. /**
  65542. * @property {boolean} usingWebAudio - True the SoundManager and device are both using Web Audio.
  65543. * @readonly
  65544. */
  65545. this.usingWebAudio = false;
  65546. /**
  65547. * @property {boolean} usingAudioTag - True the SoundManager and device are both using the Audio tag instead of Web Audio.
  65548. * @readonly
  65549. */
  65550. this.usingAudioTag = false;
  65551. /**
  65552. * @property {boolean} noAudio - True if audio been disabled via the PhaserGlobal (useful if you need to use a 3rd party audio library) or the device doesn't support any audio.
  65553. * @default
  65554. */
  65555. this.noAudio = false;
  65556. /**
  65557. * @property {boolean} connectToMaster - Used in conjunction with Sound.externalNode this allows you to stop a Sound node being connected to the SoundManager master gain node.
  65558. * @default
  65559. */
  65560. this.connectToMaster = true;
  65561. /**
  65562. * @property {boolean} touchLocked - true if the audio system is currently locked awaiting a touch event.
  65563. * @default
  65564. */
  65565. this.touchLocked = false;
  65566. /**
  65567. * @property {number} channels - The number of audio channels to use in playback.
  65568. * @default
  65569. */
  65570. this.channels = 32;
  65571. /**
  65572. * Set to true to have all sound muted when the Phaser game pauses (such as on loss of focus),
  65573. * or set to false to keep audio playing, regardless of the game pause state. You may need to
  65574. * do this should you wish to control audio muting via external DOM buttons or similar.
  65575. * @property {boolean} muteOnPause
  65576. * @default
  65577. */
  65578. this.muteOnPause = true;
  65579. /**
  65580. * @property {boolean} _codeMuted - Internal mute tracking var.
  65581. * @private
  65582. * @default
  65583. */
  65584. this._codeMuted = false;
  65585. /**
  65586. * @property {boolean} _muted - Internal mute tracking var.
  65587. * @private
  65588. * @default
  65589. */
  65590. this._muted = false;
  65591. /**
  65592. * @property {AudioContext} _unlockSource - Internal unlock tracking var.
  65593. * @private
  65594. * @default
  65595. */
  65596. this._unlockSource = null;
  65597. /**
  65598. * @property {number} _volume - The global audio volume. A value between 0 (silence) and 1 (full volume).
  65599. * @private
  65600. * @default
  65601. */
  65602. this._volume = 1;
  65603. /**
  65604. * @property {array} _sounds - An array containing all the sounds
  65605. * @private
  65606. */
  65607. this._sounds = [];
  65608. /**
  65609. * @property {Phaser.ArraySet} _watchList - An array set containing all the sounds being monitored for decoding status.
  65610. * @private
  65611. */
  65612. this._watchList = new Phaser.ArraySet();
  65613. /**
  65614. * @property {boolean} _watching - Is the SoundManager monitoring the watchList?
  65615. * @private
  65616. */
  65617. this._watching = false;
  65618. /**
  65619. * @property {function} _watchCallback - The callback to invoke once the watchlist is clear.
  65620. * @private
  65621. */
  65622. this._watchCallback = null;
  65623. /**
  65624. * @property {object} _watchContext - The context in which to call the watchlist callback.
  65625. * @private
  65626. */
  65627. this._watchContext = null;
  65628. };
  65629. Phaser.SoundManager.prototype = {
  65630. /**
  65631. * Initialises the sound manager.
  65632. * @method Phaser.SoundManager#boot
  65633. * @protected
  65634. */
  65635. boot: function () {
  65636. if (this.game.device.iOS && this.game.device.webAudio === false)
  65637. {
  65638. this.channels = 1;
  65639. }
  65640. // PhaserGlobal overrides
  65641. if (window['PhaserGlobal'])
  65642. {
  65643. // Check to see if all audio playback is disabled (i.e. handled by a 3rd party class)
  65644. if (window['PhaserGlobal'].disableAudio === true)
  65645. {
  65646. this.noAudio = true;
  65647. this.touchLocked = false;
  65648. return;
  65649. }
  65650. // Check if the Web Audio API is disabled (for testing Audio Tag playback during development)
  65651. if (window['PhaserGlobal'].disableWebAudio === true)
  65652. {
  65653. this.usingAudioTag = true;
  65654. this.touchLocked = false;
  65655. return;
  65656. }
  65657. }
  65658. if (window['PhaserGlobal'] && window['PhaserGlobal'].audioContext)
  65659. {
  65660. this.context = window['PhaserGlobal'].audioContext;
  65661. }
  65662. else
  65663. {
  65664. if (!!window['AudioContext'])
  65665. {
  65666. try {
  65667. this.context = new window['AudioContext']();
  65668. } catch (error) {
  65669. this.context = null;
  65670. this.usingWebAudio = false;
  65671. this.touchLocked = false;
  65672. }
  65673. }
  65674. else if (!!window['webkitAudioContext'])
  65675. {
  65676. try {
  65677. this.context = new window['webkitAudioContext']();
  65678. } catch (error) {
  65679. this.context = null;
  65680. this.usingWebAudio = false;
  65681. this.touchLocked = false;
  65682. }
  65683. }
  65684. }
  65685. if (this.context === null)
  65686. {
  65687. // No Web Audio support - how about legacy Audio?
  65688. if (window['Audio'] === undefined)
  65689. {
  65690. this.noAudio = true;
  65691. return;
  65692. }
  65693. else
  65694. {
  65695. this.usingAudioTag = true;
  65696. }
  65697. }
  65698. else
  65699. {
  65700. this.usingWebAudio = true;
  65701. if (this.context.createGain === undefined)
  65702. {
  65703. this.masterGain = this.context.createGainNode();
  65704. }
  65705. else
  65706. {
  65707. this.masterGain = this.context.createGain();
  65708. }
  65709. this.masterGain.gain.value = 1;
  65710. this.masterGain.connect(this.context.destination);
  65711. }
  65712. if (!this.noAudio)
  65713. {
  65714. // On mobile we need a native touch event before we can play anything, so capture it here
  65715. if (this.game.device.needsTouchUnlock())
  65716. {
  65717. this.setTouchLock();
  65718. }
  65719. }
  65720. },
  65721. /**
  65722. * Sets the Input Manager touch callback to be SoundManager.unlock.
  65723. * Required for iOS audio device unlocking. Mostly just used internally.
  65724. *
  65725. * @method Phaser.SoundManager#setTouchLock
  65726. */
  65727. setTouchLock: function () {
  65728. if (this.noAudio || (window['PhaserGlobal'] && window['PhaserGlobal'].disableAudio === true))
  65729. {
  65730. return;
  65731. }
  65732. if (this.game.device.iOSVersion > 8 || this.game.device.chromeVersion >= 55)
  65733. {
  65734. this.game.input.addTouchLockCallback(this.unlock, this, true);
  65735. }
  65736. else
  65737. {
  65738. this.game.input.addTouchLockCallback(this.unlock, this);
  65739. }
  65740. this.touchLocked = true;
  65741. },
  65742. /**
  65743. * Enables the audio, usually after the first touch.
  65744. *
  65745. * @method Phaser.SoundManager#unlock
  65746. * @return {boolean} True if the callback should be removed, otherwise false.
  65747. */
  65748. unlock: function () {
  65749. if (this.noAudio || !this.touchLocked || this._unlockSource !== null)
  65750. {
  65751. return true;
  65752. }
  65753. // Global override (mostly for Audio Tag testing)
  65754. if (this.usingAudioTag)
  65755. {
  65756. this.touchLocked = false;
  65757. this._unlockSource = null;
  65758. }
  65759. else if (this.usingWebAudio)
  65760. {
  65761. // Create empty buffer and play it
  65762. // The SoundManager.update loop captures the state of it and then resets touchLocked to false
  65763. var buffer = this.context.createBuffer(1, 1, 22050);
  65764. this._unlockSource = this.context.createBufferSource();
  65765. this._unlockSource.buffer = buffer;
  65766. this._unlockSource.connect(this.context.destination);
  65767. if (this._unlockSource.start === undefined)
  65768. {
  65769. this._unlockSource.noteOn(0);
  65770. }
  65771. else
  65772. {
  65773. this._unlockSource.start(0);
  65774. }
  65775. //This fixes locked audio in Chrome > 55 cross origin iframes
  65776. if (this._unlockSource.context.state === 'suspended') {
  65777. this._unlockSource.context.resume();
  65778. }
  65779. }
  65780. // We can remove the event because we've done what we needed (started the unlock sound playing)
  65781. return true;
  65782. },
  65783. /**
  65784. * Stops all the sounds in the game.
  65785. *
  65786. * @method Phaser.SoundManager#stopAll
  65787. */
  65788. stopAll: function () {
  65789. if (this.noAudio)
  65790. {
  65791. return;
  65792. }
  65793. for (var i = 0; i < this._sounds.length; i++)
  65794. {
  65795. if (this._sounds[i])
  65796. {
  65797. this._sounds[i].stop();
  65798. }
  65799. }
  65800. },
  65801. /**
  65802. * Pauses all the sounds in the game.
  65803. *
  65804. * @method Phaser.SoundManager#pauseAll
  65805. */
  65806. pauseAll: function () {
  65807. if (this.noAudio)
  65808. {
  65809. return;
  65810. }
  65811. for (var i = 0; i < this._sounds.length; i++)
  65812. {
  65813. if (this._sounds[i])
  65814. {
  65815. this._sounds[i].pause();
  65816. }
  65817. }
  65818. },
  65819. /**
  65820. * Resumes every sound in the game.
  65821. *
  65822. * @method Phaser.SoundManager#resumeAll
  65823. */
  65824. resumeAll: function () {
  65825. if (this.noAudio)
  65826. {
  65827. return;
  65828. }
  65829. for (var i = 0; i < this._sounds.length; i++)
  65830. {
  65831. if (this._sounds[i])
  65832. {
  65833. this._sounds[i].resume();
  65834. }
  65835. }
  65836. },
  65837. /**
  65838. * Decode a sound by its asset key.
  65839. *
  65840. * @method Phaser.SoundManager#decode
  65841. * @param {string} key - Assets key of the sound to be decoded.
  65842. * @param {Phaser.Sound} [sound] - Its buffer will be set to decoded data.
  65843. */
  65844. decode: function (key, sound) {
  65845. sound = sound || null;
  65846. var soundData = this.game.cache.getSoundData(key);
  65847. if (soundData)
  65848. {
  65849. if (this.game.cache.isSoundDecoded(key) === false)
  65850. {
  65851. this.game.cache.updateSound(key, 'isDecoding', true);
  65852. var _this = this;
  65853. try {
  65854. this.context.decodeAudioData(soundData, function (buffer) {
  65855. if (buffer)
  65856. {
  65857. _this.game.cache.decodedSound(key, buffer);
  65858. _this.onSoundDecode.dispatch(key, sound);
  65859. }
  65860. });
  65861. }
  65862. catch (e) {}
  65863. }
  65864. }
  65865. },
  65866. /**
  65867. * This method allows you to give the SoundManager a list of Sound files, or keys, and a callback.
  65868. * Once all of the Sound files have finished decoding the callback will be invoked.
  65869. * The amount of time spent decoding depends on the codec used and file size.
  65870. * If all of the files given have already decoded the callback is triggered immediately.
  65871. *
  65872. * @method Phaser.SoundManager#setDecodedCallback
  65873. * @param {string|array} files - An array containing either Phaser.Sound objects or their key strings as found in the Phaser.Cache.
  65874. * @param {Function} callback - The callback which will be invoked once all files have finished decoding.
  65875. * @param {Object} callbackContext - The context in which the callback will run.
  65876. */
  65877. setDecodedCallback: function (files, callback, callbackContext) {
  65878. if (typeof files === 'string')
  65879. {
  65880. files = [ files ];
  65881. }
  65882. this._watchList.reset();
  65883. for (var i = 0; i < files.length; i++)
  65884. {
  65885. if (files[i] instanceof Phaser.Sound)
  65886. {
  65887. if (!this.game.cache.isSoundDecoded(files[i].key))
  65888. {
  65889. this._watchList.add(files[i].key);
  65890. }
  65891. }
  65892. else if (!this.game.cache.isSoundDecoded(files[i]))
  65893. {
  65894. this._watchList.add(files[i]);
  65895. }
  65896. }
  65897. // All decoded already?
  65898. if (this._watchList.total === 0)
  65899. {
  65900. this._watching = false;
  65901. callback.call(callbackContext);
  65902. }
  65903. else
  65904. {
  65905. this._watching = true;
  65906. this._watchCallback = callback;
  65907. this._watchContext = callbackContext;
  65908. }
  65909. },
  65910. /**
  65911. * Updates every sound in the game, checks for audio unlock on mobile and monitors the decoding watch list.
  65912. *
  65913. * @method Phaser.SoundManager#update
  65914. * @protected
  65915. */
  65916. update: function () {
  65917. if (this.noAudio)
  65918. {
  65919. return;
  65920. }
  65921. if (this.touchLocked && this._unlockSource !== null && (this._unlockSource.playbackState === this._unlockSource.PLAYING_STATE || this._unlockSource.playbackState === this._unlockSource.FINISHED_STATE))
  65922. {
  65923. this.touchLocked = false;
  65924. this._unlockSource = null;
  65925. }
  65926. for (var i = 0; i < this._sounds.length; i++)
  65927. {
  65928. this._sounds[i].update();
  65929. }
  65930. if (this._watching)
  65931. {
  65932. var key = this._watchList.first;
  65933. while (key)
  65934. {
  65935. if (this.game.cache.isSoundDecoded(key))
  65936. {
  65937. this._watchList.remove(key);
  65938. }
  65939. key = this._watchList.next;
  65940. }
  65941. if (this._watchList.total === 0)
  65942. {
  65943. this._watching = false;
  65944. this._watchCallback.call(this._watchContext);
  65945. }
  65946. }
  65947. },
  65948. /**
  65949. * Adds a new Sound into the SoundManager.
  65950. *
  65951. * @method Phaser.SoundManager#add
  65952. * @param {string} key - Asset key for the sound.
  65953. * @param {number} [volume=1] - Default value for the volume.
  65954. * @param {boolean} [loop=false] - Whether or not the sound will loop.
  65955. * @param {boolean} [connect=true] - Controls if the created Sound object will connect to the master gainNode of the SoundManager when running under WebAudio.
  65956. * @return {Phaser.Sound} The new sound instance.
  65957. */
  65958. add: function (key, volume, loop, connect) {
  65959. if (volume === undefined) { volume = 1; }
  65960. if (loop === undefined) { loop = false; }
  65961. if (connect === undefined) { connect = this.connectToMaster; }
  65962. var sound = new Phaser.Sound(this.game, key, volume, loop, connect);
  65963. this._sounds.push(sound);
  65964. return sound;
  65965. },
  65966. /**
  65967. * Adds a new AudioSprite into the SoundManager.
  65968. *
  65969. * @method Phaser.SoundManager#addSprite
  65970. * @param {string} key - Asset key for the sound.
  65971. * @return {Phaser.AudioSprite} The new AudioSprite instance.
  65972. */
  65973. addSprite: function(key) {
  65974. var audioSprite = new Phaser.AudioSprite(this.game, key);
  65975. return audioSprite;
  65976. },
  65977. /**
  65978. * Removes a Sound from the SoundManager. The removed Sound is destroyed before removal.
  65979. *
  65980. * @method Phaser.SoundManager#remove
  65981. * @param {Phaser.Sound} sound - The sound object to remove.
  65982. * @return {boolean} True if the sound was removed successfully, otherwise false.
  65983. */
  65984. remove: function (sound) {
  65985. var i = this._sounds.length;
  65986. while (i--)
  65987. {
  65988. if (this._sounds[i] === sound)
  65989. {
  65990. this._sounds[i].destroy(false);
  65991. this._sounds.splice(i, 1);
  65992. return true;
  65993. }
  65994. }
  65995. return false;
  65996. },
  65997. /**
  65998. * Removes all Sounds from the SoundManager that have an asset key matching the given value.
  65999. * The removed Sounds are destroyed before removal.
  66000. *
  66001. * @method Phaser.SoundManager#removeByKey
  66002. * @param {string} key - The key to match when removing sound objects.
  66003. * @return {number} The number of matching sound objects that were removed.
  66004. */
  66005. removeByKey: function (key) {
  66006. var i = this._sounds.length;
  66007. var removed = 0;
  66008. while (i--)
  66009. {
  66010. if (this._sounds[i].key === key)
  66011. {
  66012. this._sounds[i].destroy(false);
  66013. this._sounds.splice(i, 1);
  66014. removed++;
  66015. }
  66016. }
  66017. return removed;
  66018. },
  66019. /**
  66020. * Adds a new Sound into the SoundManager and starts it playing.
  66021. *
  66022. * @method Phaser.SoundManager#play
  66023. * @param {string} key - Asset key for the sound.
  66024. * @param {number} [volume=1] - Default value for the volume.
  66025. * @param {boolean} [loop=false] - Whether or not the sound will loop.
  66026. * @return {Phaser.Sound} The new sound instance.
  66027. */
  66028. play: function (key, volume, loop) {
  66029. if (this.noAudio)
  66030. {
  66031. return;
  66032. }
  66033. var sound = this.add(key, volume, loop);
  66034. sound.play();
  66035. return sound;
  66036. },
  66037. /**
  66038. * Internal mute handler called automatically by the SoundManager.mute setter.
  66039. *
  66040. * @method Phaser.SoundManager#setMute
  66041. * @private
  66042. */
  66043. setMute: function () {
  66044. if (this._muted)
  66045. {
  66046. return;
  66047. }
  66048. this._muted = true;
  66049. if (this.usingWebAudio)
  66050. {
  66051. this._muteVolume = this.masterGain.gain.value;
  66052. this.masterGain.gain.value = 0;
  66053. }
  66054. // Loop through sounds
  66055. for (var i = 0; i < this._sounds.length; i++)
  66056. {
  66057. if (this._sounds[i].usingAudioTag)
  66058. {
  66059. this._sounds[i].mute = true;
  66060. }
  66061. }
  66062. this.onMute.dispatch();
  66063. },
  66064. /**
  66065. * Internal mute handler called automatically by the SoundManager.mute setter.
  66066. *
  66067. * @method Phaser.SoundManager#unsetMute
  66068. * @private
  66069. */
  66070. unsetMute: function () {
  66071. if (!this._muted || this._codeMuted)
  66072. {
  66073. return;
  66074. }
  66075. this._muted = false;
  66076. if (this.usingWebAudio)
  66077. {
  66078. this.masterGain.gain.value = this._muteVolume;
  66079. }
  66080. // Loop through sounds
  66081. for (var i = 0; i < this._sounds.length; i++)
  66082. {
  66083. if (this._sounds[i].usingAudioTag)
  66084. {
  66085. this._sounds[i].mute = false;
  66086. }
  66087. }
  66088. this.onUnMute.dispatch();
  66089. },
  66090. /**
  66091. * Stops all the sounds in the game, then destroys them and finally clears up any callbacks.
  66092. *
  66093. * @method Phaser.SoundManager#destroy
  66094. */
  66095. destroy: function () {
  66096. this.stopAll();
  66097. for (var i = 0; i < this._sounds.length; i++)
  66098. {
  66099. if (this._sounds[i])
  66100. {
  66101. this._sounds[i].destroy();
  66102. }
  66103. }
  66104. this._sounds = [];
  66105. this.onSoundDecode.dispose();
  66106. if (this.context)
  66107. {
  66108. if (window['PhaserGlobal'])
  66109. {
  66110. // Store this in the PhaserGlobal window var, if set, to allow for re-use if the game is created again without the page refreshing
  66111. window['PhaserGlobal'].audioContext = this.context;
  66112. }
  66113. else
  66114. {
  66115. if (this.context.close)
  66116. {
  66117. this.context.close();
  66118. }
  66119. }
  66120. }
  66121. }
  66122. };
  66123. Phaser.SoundManager.prototype.constructor = Phaser.SoundManager;
  66124. /**
  66125. * @name Phaser.SoundManager#mute
  66126. * @property {boolean} mute - Gets or sets the muted state of the SoundManager. This effects all sounds in the game.
  66127. */
  66128. Object.defineProperty(Phaser.SoundManager.prototype, "mute", {
  66129. get: function () {
  66130. return this._muted;
  66131. },
  66132. set: function (value) {
  66133. value = value || false;
  66134. if (value)
  66135. {
  66136. if (this._muted)
  66137. {
  66138. return;
  66139. }
  66140. this._codeMuted = true;
  66141. this.setMute();
  66142. }
  66143. else
  66144. {
  66145. if (!this._muted)
  66146. {
  66147. return;
  66148. }
  66149. this._codeMuted = false;
  66150. this.unsetMute();
  66151. }
  66152. }
  66153. });
  66154. /**
  66155. * @name Phaser.SoundManager#volume
  66156. * @property {number} volume - Gets or sets the global volume of the SoundManager, a value between 0 and 1. The value given is clamped to the range 0 to 1.
  66157. */
  66158. Object.defineProperty(Phaser.SoundManager.prototype, "volume", {
  66159. get: function () {
  66160. return this._volume;
  66161. },
  66162. set: function (value) {
  66163. if (value < 0)
  66164. {
  66165. value = 0;
  66166. }
  66167. else if (value > 1)
  66168. {
  66169. value = 1;
  66170. }
  66171. if (this._volume !== value)
  66172. {
  66173. this._volume = value;
  66174. if (this.usingWebAudio)
  66175. {
  66176. this.masterGain.gain.value = value;
  66177. }
  66178. else
  66179. {
  66180. // Loop through the sound cache and change the volume of all html audio tags
  66181. for (var i = 0; i < this._sounds.length; i++)
  66182. {
  66183. if (this._sounds[i].usingAudioTag)
  66184. {
  66185. this._sounds[i].updateGlobalVolume(value);
  66186. }
  66187. }
  66188. }
  66189. this.onVolumeChange.dispatch(value);
  66190. }
  66191. }
  66192. });
  66193. /**
  66194. * @author Richard Davey <rich@photonstorm.com>
  66195. * @copyright 2016 Photon Storm Ltd.
  66196. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  66197. */
  66198. /**
  66199. * @classdesc
  66200. * The ScaleManager object handles the the scaling, resizing, and alignment of the
  66201. * Game size and the game Display canvas.
  66202. *
  66203. * The Game size is the logical size of the game; the Display canvas has size as an HTML element.
  66204. *
  66205. * The calculations of these are heavily influenced by the bounding Parent size which is the computed
  66206. * dimensions of the Display canvas's Parent container/element - the _effective CSS rules of the
  66207. * canvas's Parent element play an important role_ in the operation of the ScaleManager.
  66208. *
  66209. * The Display canvas - or Game size, depending {@link #scaleMode} - is updated to best utilize the Parent size.
  66210. * When in Fullscreen mode or with {@link #parentIsWindow} the Parent size is that of the visual viewport (see {@link Phaser.ScaleManager#getParentBounds getParentBounds}).
  66211. *
  66212. * #### Parent and Display canvas containment guidelines:
  66213. *
  66214. * - Style the Parent element (of the game canvas) to control the Parent size and
  66215. * thus the Display canvas's size and layout.
  66216. *
  66217. * - The Parent element's CSS styles should _effectively_ apply maximum (and minimum) bounding behavior.
  66218. *
  66219. * - The Parent element should _not_ apply a padding as this is not accounted for.
  66220. * If a padding is required apply it to the Parent's parent or apply a margin to the Parent.
  66221. * If you need to add a border, margin or any other CSS around your game container, then use a parent element and
  66222. * apply the CSS to this instead, otherwise you'll be constantly resizing the shape of the game container.
  66223. *
  66224. * - The Display canvas layout CSS styles (i.e. margins, size) should not be altered/specified as
  66225. * they may be updated by the ScaleManager.
  66226. *
  66227. * #### Example Uses
  66228. *
  66229. * - ##### Fixed game size; scale canvas proportionally to fill its container
  66230. *
  66231. * Use `scaleMode` SHOW_ALL.
  66232. *
  66233. * - ##### Fixed game size; stretch canvas to fill its container (uncommon)
  66234. *
  66235. * Use `scaleMode` EXACT_FIT.
  66236. *
  66237. * - ##### Fixed game size; scale canvas proportionally by some other criteria
  66238. *
  66239. * Use `scaleMode` USER_SCALE. Examine `parentBounds` in the {@link #setResizeCallback resize callback} and call {@link #setUserScale} if necessary.
  66240. *
  66241. * - ##### Fluid game/canvas size
  66242. *
  66243. * Use `scaleMode` RESIZE. Examine the game or canvas size from the {@link #onSizeChange} signal **or** the {@link Phaser.State#resize} callback and reposition game objects if necessary.
  66244. *
  66245. * - ##### Preferred orientation
  66246. *
  66247. * Call {@link #forceOrientation} with the preferred orientation and use any of the {@link #onOrientationChange}, {@link #enterIncorrectOrientation}, or {@link #leaveIncorrectOrientation} signals.
  66248. *
  66249. * @description
  66250. * Create a new ScaleManager object - this is done automatically by {@link Phaser.Game}
  66251. *
  66252. * The `width` and `height` constructor parameters can either be a number which represents pixels or a string that represents a percentage: e.g. `800` (for 800 pixels) or `"80%"` for 80%.
  66253. *
  66254. * @class
  66255. * @param {Phaser.Game} game - A reference to the currently running game.
  66256. * @param {number|string} width - The width of the game. See above.
  66257. * @param {number|string} height - The height of the game. See above.
  66258. */
  66259. Phaser.ScaleManager = function (game, width, height) {
  66260. /**
  66261. * A reference to the currently running game.
  66262. * @property {Phaser.Game} game
  66263. * @protected
  66264. * @readonly
  66265. */
  66266. this.game = game;
  66267. /**
  66268. * Provides access to some cross-device DOM functions.
  66269. * @property {Phaser.DOM} dom
  66270. * @protected
  66271. * @readonly
  66272. */
  66273. this.dom = Phaser.DOM;
  66274. /**
  66275. * _EXPERIMENTAL:_ A responsive grid on which you can align game objects.
  66276. * @property {Phaser.FlexGrid} grid
  66277. * @public
  66278. */
  66279. this.grid = null;
  66280. /**
  66281. * Target width (in pixels) of the Display canvas.
  66282. * @property {number} width
  66283. * @readonly
  66284. */
  66285. this.width = 0;
  66286. /**
  66287. * Target height (in pixels) of the Display canvas.
  66288. * @property {number} height
  66289. * @readonly
  66290. */
  66291. this.height = 0;
  66292. /**
  66293. * Minimum width the canvas should be scaled to (in pixels).
  66294. * Change with {@link #setMinMax}.
  66295. * @property {?number} minWidth
  66296. * @readonly
  66297. * @protected
  66298. */
  66299. this.minWidth = null;
  66300. /**
  66301. * Maximum width the canvas should be scaled to (in pixels).
  66302. * If null it will scale to whatever width the browser can handle.
  66303. * Change with {@link #setMinMax}.
  66304. * @property {?number} maxWidth
  66305. * @readonly
  66306. * @protected
  66307. */
  66308. this.maxWidth = null;
  66309. /**
  66310. * Minimum height the canvas should be scaled to (in pixels).
  66311. * Change with {@link #setMinMax}.
  66312. * @property {?number} minHeight
  66313. * @readonly
  66314. * @protected
  66315. */
  66316. this.minHeight = null;
  66317. /**
  66318. * Maximum height the canvas should be scaled to (in pixels).
  66319. * If null it will scale to whatever height the browser can handle.
  66320. * Change with {@link #setMinMax}.
  66321. * @property {?number} maxHeight
  66322. * @readonly
  66323. * @protected
  66324. */
  66325. this.maxHeight = null;
  66326. /**
  66327. * The offset coordinates of the Display canvas from the top-left of the browser window.
  66328. * The is used internally by Phaser.Pointer (for Input) and possibly other types.
  66329. * @property {Phaser.Point} offset
  66330. * @readonly
  66331. * @protected
  66332. */
  66333. this.offset = new Phaser.Point();
  66334. /**
  66335. * If true, the game should only run in a landscape orientation.
  66336. * Change with {@link #forceOrientation}.
  66337. * @property {boolean} forceLandscape
  66338. * @readonly
  66339. * @default
  66340. * @protected
  66341. */
  66342. this.forceLandscape = false;
  66343. /**
  66344. * If true, the game should only run in a portrait
  66345. * Change with {@link #forceOrientation}.
  66346. * @property {boolean} forcePortrait
  66347. * @readonly
  66348. * @default
  66349. * @protected
  66350. */
  66351. this.forcePortrait = false;
  66352. /**
  66353. * True if {@link #forceLandscape} or {@link #forcePortrait} are set and do not agree with the browser orientation.
  66354. *
  66355. * This value is not updated immediately.
  66356. *
  66357. * @property {boolean} incorrectOrientation
  66358. * @readonly
  66359. * @protected
  66360. */
  66361. this.incorrectOrientation = false;
  66362. /**
  66363. * See {@link #pageAlignHorizontally}.
  66364. * @property {boolean} _pageAlignHorizontally
  66365. * @private
  66366. */
  66367. this._pageAlignHorizontally = false;
  66368. /**
  66369. * See {@link #pageAlignVertically}.
  66370. * @property {boolean} _pageAlignVertically
  66371. * @private
  66372. */
  66373. this._pageAlignVertically = false;
  66374. /**
  66375. * This signal is dispatched when the orientation changes _or_ the validity of the current orientation changes.
  66376. *
  66377. * The signal is supplied with the following arguments:
  66378. * - `scale` - the ScaleManager object
  66379. * - `prevOrientation`, a string - The previous orientation as per {@link Phaser.ScaleManager#screenOrientation screenOrientation}.
  66380. * - `wasIncorrect`, a boolean - True if the previous orientation was last determined to be incorrect.
  66381. *
  66382. * Access the current orientation and validity with `scale.screenOrientation` and `scale.incorrectOrientation`.
  66383. * Thus the following tests can be done:
  66384. *
  66385. * // The orientation itself changed:
  66386. * scale.screenOrientation !== prevOrientation
  66387. * // The orientation just became incorrect:
  66388. * scale.incorrectOrientation && !wasIncorrect
  66389. *
  66390. * It is possible that this signal is triggered after {@link #forceOrientation} so the orientation
  66391. * correctness changes even if the orientation itself does not change.
  66392. *
  66393. * This is signaled from `preUpdate` (or `pauseUpdate`) _even when_ the game is paused.
  66394. *
  66395. * @property {Phaser.Signal} onOrientationChange
  66396. * @public
  66397. */
  66398. this.onOrientationChange = new Phaser.Signal();
  66399. /**
  66400. * This signal is dispatched when the browser enters an incorrect orientation, as defined by {@link #forceOrientation}.
  66401. *
  66402. * This is signaled from `preUpdate` (or `pauseUpdate`) _even when_ the game is paused.
  66403. *
  66404. * @property {Phaser.Signal} enterIncorrectOrientation
  66405. * @public
  66406. */
  66407. this.enterIncorrectOrientation = new Phaser.Signal();
  66408. /**
  66409. * This signal is dispatched when the browser leaves an incorrect orientation, as defined by {@link #forceOrientation}.
  66410. *
  66411. * This is signaled from `preUpdate` (or `pauseUpdate`) _even when_ the game is paused.
  66412. *
  66413. * @property {Phaser.Signal} leaveIncorrectOrientation
  66414. * @public
  66415. */
  66416. this.leaveIncorrectOrientation = new Phaser.Signal();
  66417. /**
  66418. * This boolean provides you with a way to determine if the browser is in Full Screen
  66419. * mode (via the Full Screen API), and Phaser was the one responsible for activating it.
  66420. *
  66421. * It's possible that ScaleManager.isFullScreen returns `true` even if Phaser wasn't the
  66422. * one that made the browser go full-screen, so this flag lets you determine that.
  66423. *
  66424. * @property {boolean} hasPhaserSetFullScreen
  66425. * @default
  66426. */
  66427. this.hasPhaserSetFullScreen = false;
  66428. /**
  66429. * If specified, this is the DOM element on which the Fullscreen API enter request will be invoked.
  66430. * The target element must have the correct CSS styling and contain the Display canvas.
  66431. *
  66432. * The elements style will be modified (ie. the width and height might be set to 100%)
  66433. * but it will not be added to, removed from, or repositioned within the DOM.
  66434. * An attempt is made to restore relevant style changes when fullscreen mode is left.
  66435. *
  66436. * For pre-2.2.0 behavior set `game.scale.fullScreenTarget = game.canvas`.
  66437. *
  66438. * @property {?DOMElement} fullScreenTarget
  66439. * @default
  66440. */
  66441. this.fullScreenTarget = null;
  66442. /**
  66443. * The fullscreen target, as created by {@link #createFullScreenTarget}.
  66444. * This is not set if {@link #fullScreenTarget} is used and is cleared when fullscreen mode ends.
  66445. * @property {?DOMElement} _createdFullScreenTarget
  66446. * @private
  66447. */
  66448. this._createdFullScreenTarget = null;
  66449. /**
  66450. * This signal is dispatched when fullscreen mode is ready to be initialized but
  66451. * before the fullscreen request.
  66452. *
  66453. * The signal is passed two arguments: `scale` (the ScaleManager), and an object in the form `{targetElement: DOMElement}`.
  66454. *
  66455. * The `targetElement` is the {@link #fullScreenTarget} element,
  66456. * if such is assigned, or a new element created by {@link #createFullScreenTarget}.
  66457. *
  66458. * Custom CSS styling or resets can be applied to `targetElement` as required.
  66459. *
  66460. * If `targetElement` is _not_ the same element as {@link #fullScreenTarget}:
  66461. * - After initialization the Display canvas is moved onto the `targetElement` for
  66462. * the duration of the fullscreen mode, and restored to it's original DOM location when fullscreen is exited.
  66463. * - The `targetElement` is moved/re-parented within the DOM and may have its CSS styles updated.
  66464. *
  66465. * The behavior of a pre-assigned target element is covered in {@link Phaser.ScaleManager#fullScreenTarget fullScreenTarget}.
  66466. *
  66467. * @property {Phaser.Signal} onFullScreenInit
  66468. * @public
  66469. */
  66470. this.onFullScreenInit = new Phaser.Signal();
  66471. /**
  66472. * This signal is dispatched when the browser enters or leaves fullscreen mode, if supported.
  66473. *
  66474. * The signal is supplied with a single argument: `scale` (the ScaleManager). Use `scale.isFullScreen` to determine
  66475. * if currently running in Fullscreen mode.
  66476. *
  66477. * @property {Phaser.Signal} onFullScreenChange
  66478. * @public
  66479. */
  66480. this.onFullScreenChange = new Phaser.Signal();
  66481. /**
  66482. * This signal is dispatched when the browser fails to enter fullscreen mode;
  66483. * or if the device does not support fullscreen mode and `startFullScreen` is invoked.
  66484. *
  66485. * The signal is supplied with a single argument: `scale` (the ScaleManager).
  66486. *
  66487. * @property {Phaser.Signal} onFullScreenError
  66488. * @public
  66489. */
  66490. this.onFullScreenError = new Phaser.Signal();
  66491. /**
  66492. * The _last known_ orientation of the screen, as defined in the Window Screen Web API.
  66493. * See {@link Phaser.DOM.getScreenOrientation} for possible values.
  66494. *
  66495. * @property {string} screenOrientation
  66496. * @readonly
  66497. * @public
  66498. */
  66499. this.screenOrientation = this.dom.getScreenOrientation();
  66500. /**
  66501. * The _current_ scale factor based on the game dimensions vs. the scaled dimensions.
  66502. * @property {Phaser.Point} scaleFactor
  66503. * @readonly
  66504. */
  66505. this.scaleFactor = new Phaser.Point(1, 1);
  66506. /**
  66507. * The _current_ inversed scale factor. The displayed dimensions divided by the game dimensions.
  66508. * @property {Phaser.Point} scaleFactorInversed
  66509. * @readonly
  66510. * @protected
  66511. */
  66512. this.scaleFactorInversed = new Phaser.Point(1, 1);
  66513. /**
  66514. * The Display canvas is aligned by adjusting the margins; the last margins are stored here.
  66515. *
  66516. * @property {Bounds-like} margin
  66517. * @readonly
  66518. * @protected
  66519. */
  66520. this.margin = {left: 0, top: 0, right: 0, bottom: 0, x: 0, y: 0};
  66521. /**
  66522. * The bounds of the scaled game. The x/y will match the offset of the canvas element and the width/height the scaled width and height.
  66523. * @property {Phaser.Rectangle} bounds
  66524. * @readonly
  66525. */
  66526. this.bounds = new Phaser.Rectangle();
  66527. /**
  66528. * The aspect ratio of the scaled Display canvas.
  66529. * @property {number} aspectRatio
  66530. * @readonly
  66531. */
  66532. this.aspectRatio = 0;
  66533. /**
  66534. * The aspect ratio of the original game dimensions.
  66535. * @property {number} sourceAspectRatio
  66536. * @readonly
  66537. */
  66538. this.sourceAspectRatio = 0;
  66539. /**
  66540. * The native browser events from Fullscreen API changes.
  66541. * @property {any} event
  66542. * @readonly
  66543. * @private
  66544. */
  66545. this.event = null;
  66546. /**
  66547. * The edges on which to constrain the game Display/canvas in _addition_ to the restrictions of the parent container.
  66548. *
  66549. * The properties are strings and can be '', 'visual', 'layout', or 'layout-soft'.
  66550. * - If 'visual', the edge will be constrained to the Window / displayed screen area
  66551. * - If 'layout', the edge will be constrained to the CSS Layout bounds
  66552. * - An invalid value is treated as 'visual'
  66553. *
  66554. * @member
  66555. * @property {string} bottom
  66556. * @property {string} right
  66557. * @default
  66558. */
  66559. this.windowConstraints = {
  66560. right: 'layout',
  66561. bottom: ''
  66562. };
  66563. /**
  66564. * Various compatibility settings.
  66565. * A value of "(auto)" indicates the setting is configured based on device and runtime information.
  66566. *
  66567. * A {@link #refresh} may need to be performed after making changes.
  66568. *
  66569. * @protected
  66570. *
  66571. * @property {boolean} [supportsFullScreen=(auto)] - True only if fullscreen support will be used. (Changing to fullscreen still might not work.)
  66572. *
  66573. * @property {boolean} [orientationFallback=(auto)] - See {@link Phaser.DOM.getScreenOrientation}.
  66574. *
  66575. * @property {boolean} [noMargins=false] - If true then the Display canvas's margins will not be updated anymore: existing margins must be manually cleared. Disabling margins prevents automatic canvas alignment/centering, possibly in fullscreen.
  66576. *
  66577. * @property {?Phaser.Point} [scrollTo=(auto)] - If specified the window will be scrolled to this position on every refresh.
  66578. *
  66579. * @property {boolean} [forceMinimumDocumentHeight=false] - If enabled the document elements minimum height is explicitly set on updates.
  66580. * The height set varies by device and may either be the height of the window or the viewport.
  66581. *
  66582. * @property {boolean} [canExpandParent=true] - If enabled then SHOW_ALL and USER_SCALE modes can try and expand the parent element. It may be necessary for the parent element to impose CSS width/height restrictions.
  66583. *
  66584. * @property {string} [clickTrampoline=(auto)] - On certain browsers (eg. IE) FullScreen events need to be triggered via 'click' events.
  66585. * A value of 'when-not-mouse' uses a click trampoline when a pointer that is not the primary mouse is used.
  66586. * Any other string value (including the empty string) prevents using click trampolines.
  66587. * For more details on click trampolines see {@link Phaser.Pointer#addClickTrampoline}.
  66588. */
  66589. this.compatibility = {
  66590. supportsFullScreen: false,
  66591. orientationFallback: null,
  66592. noMargins: false,
  66593. scrollTo: null,
  66594. forceMinimumDocumentHeight: false,
  66595. canExpandParent: true,
  66596. clickTrampoline: ''
  66597. };
  66598. /**
  66599. * Scale mode to be used when not in fullscreen.
  66600. * @property {number} _scaleMode
  66601. * @private
  66602. */
  66603. this._scaleMode = Phaser.ScaleManager.NO_SCALE;
  66604. /*
  66605. * Scale mode to be used in fullscreen.
  66606. * @property {number} _fullScreenScaleMode
  66607. * @private
  66608. */
  66609. this._fullScreenScaleMode = Phaser.ScaleManager.NO_SCALE;
  66610. /**
  66611. * If the parent container of the Game canvas is the browser window itself (i.e. document.body),
  66612. * rather than another div, this should set to `true`.
  66613. *
  66614. * The {@link #parentNode} property is generally ignored while this is in effect.
  66615. *
  66616. * @property {boolean} parentIsWindow
  66617. */
  66618. this.parentIsWindow = false;
  66619. /**
  66620. * The _original_ DOM element for the parent of the Display canvas.
  66621. * This may be different in fullscreen - see {@link #createFullScreenTarget}.
  66622. *
  66623. * This should only be changed after moving the Game canvas to a different DOM parent.
  66624. *
  66625. * @property {?DOMElement} parentNode
  66626. */
  66627. this.parentNode = null;
  66628. /**
  66629. * The scale of the game in relation to its parent container.
  66630. * @property {Phaser.Point} parentScaleFactor
  66631. * @readonly
  66632. */
  66633. this.parentScaleFactor = new Phaser.Point(1, 1);
  66634. /**
  66635. * The maximum time (in ms) between dimension update checks for the Canvas's parent element (or window).
  66636. * Update checks normally happen quicker in response to other events.
  66637. *
  66638. * @property {integer} trackParentInterval
  66639. * @default
  66640. * @protected
  66641. * @see {@link Phaser.ScaleManager#refresh refresh}
  66642. */
  66643. this.trackParentInterval = 2000;
  66644. /**
  66645. * This signal is dispatched when the size of the Display canvas changes _or_ the size of the Game changes.
  66646. * When invoked this is done _after_ the Canvas size/position have been updated.
  66647. *
  66648. * The callback is supplied with three arguments: the Scale Manager, canvas {@link #width}, and canvas {@link #height}. (Game dimensions can be found in `scale.game.width` and `scale.game.height`.)
  66649. *
  66650. * This signal is _only_ called when a change occurs and a reflow may be required.
  66651. * For example, if the canvas does not change sizes because of CSS settings (such as min-width)
  66652. * then this signal will _not_ be triggered.
  66653. *
  66654. * Use this to handle responsive game layout options.
  66655. *
  66656. * This is signaled from `preUpdate` (or `pauseUpdate`) _even when_ the game is paused.
  66657. *
  66658. * @property {Phaser.Signal} onSizeChange
  66659. */
  66660. this.onSizeChange = new Phaser.Signal();
  66661. /**
  66662. * The callback that will be called each the parent container resizes.
  66663. * @property {function} onResize
  66664. * @private
  66665. */
  66666. this.onResize = null;
  66667. /**
  66668. * The context in which the {@link #onResize} callback will be called.
  66669. * @property {object} onResizeContext
  66670. * @private
  66671. */
  66672. this.onResizeContext = null;
  66673. /**
  66674. * @property {integer} _pendingScaleMode - Used to retain the scale mode if set from config before Boot.
  66675. * @private
  66676. */
  66677. this._pendingScaleMode = null;
  66678. /**
  66679. * Information saved when fullscreen mode is started.
  66680. * @property {?object} _fullScreenRestore
  66681. * @private
  66682. */
  66683. this._fullScreenRestore = null;
  66684. /**
  66685. * The _actual_ game dimensions, as initially set or set by {@link #setGameSize}.
  66686. * @property {Phaser.Rectangle} _gameSize
  66687. * @private
  66688. */
  66689. this._gameSize = new Phaser.Rectangle();
  66690. /**
  66691. * The user-supplied scale factor, used with the USER_SCALE scaling mode.
  66692. * @property {Phaser.Point} _userScaleFactor
  66693. * @private
  66694. */
  66695. this._userScaleFactor = new Phaser.Point(1, 1);
  66696. /**
  66697. * The user-supplied scale trim, used with the USER_SCALE scaling mode.
  66698. * @property {Phaser.Point} _userScaleTrim
  66699. * @private
  66700. */
  66701. this._userScaleTrim = new Phaser.Point(0, 0);
  66702. /**
  66703. * The last time the bounds were checked in `preUpdate`.
  66704. * @property {number} _lastUpdate
  66705. * @private
  66706. */
  66707. this._lastUpdate = 0;
  66708. /**
  66709. * Size checks updates are delayed according to the throttle.
  66710. * The throttle increases to `trackParentInterval` over time and is used to more
  66711. * rapidly detect changes in certain browsers (eg. IE) while providing back-off safety.
  66712. * @property {integer} _updateThrottle
  66713. * @private
  66714. */
  66715. this._updateThrottle = 0;
  66716. /**
  66717. * The minimum throttle allowed until it has slowed down sufficiently.
  66718. * @property {integer} _updateThrottleReset
  66719. * @private
  66720. */
  66721. this._updateThrottleReset = 100;
  66722. /**
  66723. * The cached result of the parent (possibly window) bounds; used to invalidate sizing.
  66724. * @property {Phaser.Rectangle} _parentBounds
  66725. * @private
  66726. */
  66727. this._parentBounds = new Phaser.Rectangle();
  66728. /**
  66729. * Temporary bounds used for internal work to cut down on new objects created.
  66730. * @property {Phaser.Rectangle} _parentBounds
  66731. * @private
  66732. */
  66733. this._tempBounds = new Phaser.Rectangle();
  66734. /**
  66735. * The Canvas size at which the last onSizeChange signal was triggered.
  66736. * @property {Phaser.Rectangle} _lastReportedCanvasSize
  66737. * @private
  66738. */
  66739. this._lastReportedCanvasSize = new Phaser.Rectangle();
  66740. /**
  66741. * The Game size at which the last onSizeChange signal was triggered.
  66742. * @property {Phaser.Rectangle} _lastReportedGameSize
  66743. * @private
  66744. */
  66745. this._lastReportedGameSize = new Phaser.Rectangle();
  66746. /**
  66747. * @property {boolean} _booted - ScaleManager booted state.
  66748. * @private
  66749. */
  66750. this._booted = false;
  66751. if (game.config)
  66752. {
  66753. this.parseConfig(game.config);
  66754. }
  66755. this.setupScale(width, height);
  66756. };
  66757. /**
  66758. * A scale mode that stretches content to fill all available space - see {@link Phaser.ScaleManager#scaleMode scaleMode}.
  66759. *
  66760. * @constant
  66761. * @type {integer}
  66762. */
  66763. Phaser.ScaleManager.EXACT_FIT = 0;
  66764. /**
  66765. * A scale mode that prevents any scaling - see {@link Phaser.ScaleManager#scaleMode scaleMode}.
  66766. *
  66767. * @constant
  66768. * @type {integer}
  66769. */
  66770. Phaser.ScaleManager.NO_SCALE = 1;
  66771. /**
  66772. * A scale mode that shows the entire game while maintaining proportions - see {@link Phaser.ScaleManager#scaleMode scaleMode}.
  66773. *
  66774. * @constant
  66775. * @type {integer}
  66776. */
  66777. Phaser.ScaleManager.SHOW_ALL = 2;
  66778. /**
  66779. * A scale mode that causes the Game size to change - see {@link Phaser.ScaleManager#scaleMode scaleMode}.
  66780. *
  66781. * @constant
  66782. * @type {integer}
  66783. */
  66784. Phaser.ScaleManager.RESIZE = 3;
  66785. /**
  66786. * A scale mode that allows a custom scale factor - see {@link Phaser.ScaleManager#scaleMode scaleMode}.
  66787. *
  66788. * @constant
  66789. * @type {integer}
  66790. */
  66791. Phaser.ScaleManager.USER_SCALE = 4;
  66792. Phaser.ScaleManager.prototype = {
  66793. /**
  66794. * Start the ScaleManager.
  66795. *
  66796. * @method Phaser.ScaleManager#boot
  66797. * @protected
  66798. */
  66799. boot: function () {
  66800. // Configure device-dependent compatibility
  66801. var compat = this.compatibility;
  66802. compat.supportsFullScreen = this.game.device.fullscreen && !this.game.device.cocoonJS;
  66803. // We can't do anything about the status bars in iPads, web apps or desktops
  66804. if (!this.game.device.iPad && !this.game.device.webApp && !this.game.device.desktop)
  66805. {
  66806. if (this.game.device.android && !this.game.device.chrome)
  66807. {
  66808. compat.scrollTo = new Phaser.Point(0, 1);
  66809. }
  66810. else
  66811. {
  66812. compat.scrollTo = new Phaser.Point(0, 0);
  66813. }
  66814. }
  66815. if (this.game.device.desktop)
  66816. {
  66817. compat.orientationFallback = 'screen';
  66818. compat.clickTrampoline = 'when-not-mouse';
  66819. }
  66820. else
  66821. {
  66822. compat.orientationFallback = '';
  66823. compat.clickTrampoline = '';
  66824. }
  66825. // Configure event listeners
  66826. var _this = this;
  66827. this._orientationChange = function(event) {
  66828. return _this.orientationChange(event);
  66829. };
  66830. this._windowResize = function(event) {
  66831. return _this.windowResize(event);
  66832. };
  66833. // This does not appear to be on the standards track
  66834. window.addEventListener('orientationchange', this._orientationChange, false);
  66835. window.addEventListener('resize', this._windowResize, false);
  66836. if (this.compatibility.supportsFullScreen)
  66837. {
  66838. this._fullScreenChange = function(event) {
  66839. return _this.fullScreenChange(event);
  66840. };
  66841. this._fullScreenError = function(event) {
  66842. return _this.fullScreenError(event);
  66843. };
  66844. document.addEventListener('webkitfullscreenchange', this._fullScreenChange, false);
  66845. document.addEventListener('mozfullscreenchange', this._fullScreenChange, false);
  66846. document.addEventListener('MSFullscreenChange', this._fullScreenChange, false);
  66847. document.addEventListener('fullscreenchange', this._fullScreenChange, false);
  66848. document.addEventListener('webkitfullscreenerror', this._fullScreenError, false);
  66849. document.addEventListener('mozfullscreenerror', this._fullScreenError, false);
  66850. document.addEventListener('MSFullscreenError', this._fullScreenError, false);
  66851. document.addEventListener('fullscreenerror', this._fullScreenError, false);
  66852. }
  66853. this.game.onResume.add(this._gameResumed, this);
  66854. // Initialize core bounds
  66855. this.dom.getOffset(this.game.canvas, this.offset);
  66856. this.bounds.setTo(this.offset.x, this.offset.y, this.width, this.height);
  66857. this.setGameSize(this.game.width, this.game.height);
  66858. // Don't use updateOrientationState so events are not fired
  66859. this.screenOrientation = this.dom.getScreenOrientation(this.compatibility.orientationFallback);
  66860. if (Phaser.FlexGrid)
  66861. {
  66862. this.grid = new Phaser.FlexGrid(this, this.width, this.height);
  66863. }
  66864. this._booted = true;
  66865. if (this._pendingScaleMode !== null)
  66866. {
  66867. this.scaleMode = this._pendingScaleMode;
  66868. this._pendingScaleMode = null;
  66869. }
  66870. },
  66871. /**
  66872. * Load configuration settings.
  66873. *
  66874. * @method Phaser.ScaleManager#parseConfig
  66875. * @protected
  66876. * @param {object} config - The game configuration object.
  66877. */
  66878. parseConfig: function (config) {
  66879. if (config['scaleMode'] !== undefined)
  66880. {
  66881. if (this._booted)
  66882. {
  66883. this.scaleMode = config['scaleMode'];
  66884. }
  66885. else
  66886. {
  66887. this._pendingScaleMode = config['scaleMode'];
  66888. }
  66889. }
  66890. if (config['fullScreenScaleMode'] !== undefined)
  66891. {
  66892. this.fullScreenScaleMode = config['fullScreenScaleMode'];
  66893. }
  66894. if (config['fullScreenTarget'])
  66895. {
  66896. this.fullScreenTarget = config['fullScreenTarget'];
  66897. }
  66898. },
  66899. /**
  66900. * Calculates and sets the game dimensions based on the given width and height.
  66901. *
  66902. * This should _not_ be called when in fullscreen mode.
  66903. *
  66904. * @method Phaser.ScaleManager#setupScale
  66905. * @protected
  66906. * @param {number|string} width - The width of the game.
  66907. * @param {number|string} height - The height of the game.
  66908. */
  66909. setupScale: function (width, height) {
  66910. var target;
  66911. var rect = new Phaser.Rectangle();
  66912. if (this.game.parent !== '')
  66913. {
  66914. if (typeof this.game.parent === 'string')
  66915. {
  66916. // hopefully an element ID
  66917. target = document.getElementById(this.game.parent);
  66918. }
  66919. else if (this.game.parent && this.game.parent.nodeType === 1)
  66920. {
  66921. // quick test for a HTMLelement
  66922. target = this.game.parent;
  66923. }
  66924. }
  66925. // Fallback, covers an invalid ID and a non HTMLelement object
  66926. if (!target)
  66927. {
  66928. // Use the full window
  66929. this.parentNode = null;
  66930. this.parentIsWindow = true;
  66931. rect.width = this.dom.visualBounds.width;
  66932. rect.height = this.dom.visualBounds.height;
  66933. this.offset.set(0, 0);
  66934. }
  66935. else
  66936. {
  66937. this.parentNode = target;
  66938. this.parentIsWindow = false;
  66939. this.getParentBounds(this._parentBounds);
  66940. rect.width = this._parentBounds.width;
  66941. rect.height = this._parentBounds.height;
  66942. this.offset.set(this._parentBounds.x, this._parentBounds.y);
  66943. }
  66944. var newWidth = 0;
  66945. var newHeight = 0;
  66946. if (typeof width === 'number')
  66947. {
  66948. newWidth = width;
  66949. }
  66950. else
  66951. {
  66952. // Percentage based
  66953. this.parentScaleFactor.x = parseInt(width, 10) / 100;
  66954. newWidth = rect.width * this.parentScaleFactor.x;
  66955. }
  66956. if (typeof height === 'number')
  66957. {
  66958. newHeight = height;
  66959. }
  66960. else
  66961. {
  66962. // Percentage based
  66963. this.parentScaleFactor.y = parseInt(height, 10) / 100;
  66964. newHeight = rect.height * this.parentScaleFactor.y;
  66965. }
  66966. newWidth = Math.floor(newWidth);
  66967. newHeight = Math.floor(newHeight);
  66968. this._gameSize.setTo(0, 0, newWidth, newHeight);
  66969. this.updateDimensions(newWidth, newHeight, false);
  66970. },
  66971. /**
  66972. * Invoked when the game is resumed.
  66973. *
  66974. * @method Phaser.ScaleManager#_gameResumed
  66975. * @private
  66976. */
  66977. _gameResumed: function () {
  66978. this.queueUpdate(true);
  66979. },
  66980. /**
  66981. * Set the actual Game size.
  66982. * Use this instead of directly changing `game.width` or `game.height`.
  66983. *
  66984. * The actual physical display (Canvas element size) depends on various settings including
  66985. * - Scale mode
  66986. * - Scaling factor
  66987. * - Size of Canvas's parent element or CSS rules such as min-height/max-height;
  66988. * - The size of the Window
  66989. *
  66990. * @method Phaser.ScaleManager#setGameSize
  66991. * @public
  66992. * @param {integer} width - _Game width_, in pixels.
  66993. * @param {integer} height - _Game height_, in pixels.
  66994. */
  66995. setGameSize: function (width, height) {
  66996. this._gameSize.setTo(0, 0, width, height);
  66997. if (this.currentScaleMode !== Phaser.ScaleManager.RESIZE)
  66998. {
  66999. this.updateDimensions(width, height, true);
  67000. }
  67001. this.queueUpdate(true);
  67002. },
  67003. /**
  67004. * Set a User scaling factor used in the USER_SCALE scaling mode.
  67005. *
  67006. * The target canvas size is computed by:
  67007. *
  67008. * canvas.width = (game.width * hScale) - hTrim
  67009. * canvas.height = (game.height * vScale) - vTrim
  67010. *
  67011. * This method can be used in the {@link Phaser.ScaleManager#setResizeCallback resize callback}. Set `queueUpdate` and `force` to false if the resize callback is being called repeatedly.
  67012. *
  67013. * @method Phaser.ScaleManager#setUserScale
  67014. * @param {number} hScale - Horizontal scaling factor.
  67015. * @param {numer} vScale - Vertical scaling factor.
  67016. * @param {integer} [hTrim=0] - Horizontal trim, applied after scaling.
  67017. * @param {integer} [vTrim=0] - Vertical trim, applied after scaling.
  67018. * @param {boolean} [queueUpdate=true] - Queue a size/bounds check at next preUpdate
  67019. * @param {boolean} [force=true] - Force a resize during the next preUpdate
  67020. */
  67021. setUserScale: function (hScale, vScale, hTrim, vTrim, queueUpdate, force) {
  67022. this._userScaleFactor.setTo(hScale, vScale);
  67023. this._userScaleTrim.setTo(hTrim | 0, vTrim | 0);
  67024. if (queueUpdate === undefined) { queueUpdate = true; }
  67025. if (force === undefined) { force = true; }
  67026. if (queueUpdate)
  67027. {
  67028. this.queueUpdate(force);
  67029. }
  67030. },
  67031. /**
  67032. * Sets the callback that will be invoked before sizing calculations.
  67033. *
  67034. * Typically this is triggered when the Scale Manager has detected a change to the canvas's boundaries:
  67035. * the browser window has been resized, the device has been rotated, or the parent container's size has changed.
  67036. * At this point the Scale Manager has not resized the game or canvas yet (and may not resize them at all
  67037. * after it makes its sizing calculations). You can read the size of the parent container from the
  67038. * `parentBounds` argument to the callback.
  67039. *
  67040. * This is the appropriate place to call {@link #setUserScale} if needing custom dynamic scaling.
  67041. *
  67042. * The callback is supplied with two arguments `scale` and `parentBounds` where `scale` is the ScaleManager
  67043. * and `parentBounds`, a Phaser.Rectangle, is the size of the Parent element.
  67044. *
  67045. * This callback
  67046. * - May be invoked even though the parent container or canvas sizes have not changed
  67047. * - Unlike {@link #onSizeChange}, it runs _before_ the canvas is guaranteed to be updated
  67048. * - Will be invoked from `preUpdate`, _even when_ the game is paused
  67049. *
  67050. * See {@link #onSizeChange} for a better way of reacting to layout updates.
  67051. *
  67052. * @method Phaser.ScaleManager#setResizeCallback
  67053. * @public
  67054. * @param {function} callback - The callback that will be called each time a window.resize event happens or if set, the parent container resizes.
  67055. * @param {object} context - The context in which the callback will be called.
  67056. */
  67057. setResizeCallback: function (callback, context) {
  67058. this.onResize = callback;
  67059. this.onResizeContext = context;
  67060. },
  67061. /**
  67062. * Signals a resize - IF the canvas or Game size differs from the last signal.
  67063. *
  67064. * This also triggers updates on {@link #grid} (FlexGrid) and, if in a RESIZE mode, `game.state` (StateManager).
  67065. *
  67066. * It dispatches the {@link #onSizeChange} signal.
  67067. *
  67068. * @method Phaser.ScaleManager#signalSizeChange
  67069. * @private
  67070. */
  67071. signalSizeChange: function () {
  67072. if (!Phaser.Rectangle.sameDimensions(this, this._lastReportedCanvasSize) ||
  67073. !Phaser.Rectangle.sameDimensions(this.game, this._lastReportedGameSize))
  67074. {
  67075. var width = this.width;
  67076. var height = this.height;
  67077. this._lastReportedCanvasSize.setTo(0, 0, width, height);
  67078. this._lastReportedGameSize.setTo(0, 0, this.game.width, this.game.height);
  67079. if (this.grid)
  67080. {
  67081. this.grid.onResize(width, height);
  67082. }
  67083. this.onSizeChange.dispatch(this, width, height);
  67084. // Per StateManager#onResizeCallback, it only occurs when in RESIZE mode.
  67085. if (this.currentScaleMode === Phaser.ScaleManager.RESIZE)
  67086. {
  67087. this.game.state.resize(width, height);
  67088. this.game.load.resize(width, height);
  67089. }
  67090. }
  67091. },
  67092. /**
  67093. * Set the min and max dimensions for the Display canvas.
  67094. *
  67095. * _Note:_ The min/max dimensions are only applied in some cases
  67096. * - When the device is not in an incorrect orientation; or
  67097. * - The scale mode is EXACT_FIT when not in fullscreen
  67098. *
  67099. * @method Phaser.ScaleManager#setMinMax
  67100. * @public
  67101. * @param {number} minWidth - The minimum width the game is allowed to scale down to.
  67102. * @param {number} minHeight - The minimum height the game is allowed to scale down to.
  67103. * @param {number} [maxWidth] - The maximum width the game is allowed to scale up to; only changed if specified.
  67104. * @param {number} [maxHeight] - The maximum height the game is allowed to scale up to; only changed if specified.
  67105. * @todo These values are only sometimes honored.
  67106. */
  67107. setMinMax: function (minWidth, minHeight, maxWidth, maxHeight) {
  67108. this.minWidth = minWidth;
  67109. this.minHeight = minHeight;
  67110. if (typeof maxWidth !== 'undefined')
  67111. {
  67112. this.maxWidth = maxWidth;
  67113. }
  67114. if (typeof maxHeight !== 'undefined')
  67115. {
  67116. this.maxHeight = maxHeight;
  67117. }
  67118. },
  67119. /**
  67120. * The ScaleManager.preUpdate is called automatically by the core Game loop.
  67121. *
  67122. * @method Phaser.ScaleManager#preUpdate
  67123. * @protected
  67124. */
  67125. preUpdate: function () {
  67126. if (this.game.time.time < (this._lastUpdate + this._updateThrottle))
  67127. {
  67128. return;
  67129. }
  67130. var prevThrottle = this._updateThrottle;
  67131. this._updateThrottleReset = prevThrottle >= 400 ? 0 : 100;
  67132. this.dom.getOffset(this.game.canvas, this.offset);
  67133. var prevWidth = this._parentBounds.width;
  67134. var prevHeight = this._parentBounds.height;
  67135. var bounds = this.getParentBounds(this._parentBounds);
  67136. var boundsChanged = bounds.width !== prevWidth || bounds.height !== prevHeight;
  67137. // Always invalidate on a newly detected orientation change
  67138. var orientationChanged = this.updateOrientationState();
  67139. if (boundsChanged || orientationChanged)
  67140. {
  67141. if (this.onResize)
  67142. {
  67143. this.onResize.call(this.onResizeContext, this, bounds);
  67144. }
  67145. this.updateLayout();
  67146. this.signalSizeChange();
  67147. }
  67148. // Next throttle, eg. 25, 50, 100, 200..
  67149. var throttle = this._updateThrottle * 2;
  67150. // Don't let an update be too eager about resetting the throttle.
  67151. if (this._updateThrottle < prevThrottle)
  67152. {
  67153. throttle = Math.min(prevThrottle, this._updateThrottleReset);
  67154. }
  67155. this._updateThrottle = Phaser.Math.clamp(throttle, 25, this.trackParentInterval);
  67156. this._lastUpdate = this.game.time.time;
  67157. },
  67158. /**
  67159. * Update method while paused.
  67160. *
  67161. * @method Phaser.ScaleManager#pauseUpdate
  67162. * @private
  67163. */
  67164. pauseUpdate: function () {
  67165. this.preUpdate();
  67166. // Updates at slowest.
  67167. this._updateThrottle = this.trackParentInterval;
  67168. },
  67169. /**
  67170. * Update the dimensions taking the parent scaling factor into account.
  67171. *
  67172. * @method Phaser.ScaleManager#updateDimensions
  67173. * @private
  67174. * @param {number} width - The new width of the parent container.
  67175. * @param {number} height - The new height of the parent container.
  67176. * @param {boolean} resize - True if the renderer should be resized, otherwise false to just update the internal vars.
  67177. */
  67178. updateDimensions: function (width, height, resize) {
  67179. this.width = width * this.parentScaleFactor.x;
  67180. this.height = height * this.parentScaleFactor.y;
  67181. this.game.width = this.width;
  67182. this.game.height = this.height;
  67183. this.sourceAspectRatio = this.width / this.height;
  67184. this.updateScalingAndBounds();
  67185. if (resize)
  67186. {
  67187. // Resize the renderer (which in turn resizes the Display canvas!)
  67188. this.game.renderer.resize(this.width, this.height);
  67189. // The Camera can never be smaller than the Game size
  67190. this.game.camera.setSize(this.width, this.height);
  67191. // This should only happen if the world is smaller than the new canvas size
  67192. this.game.world.resize(this.width, this.height);
  67193. }
  67194. },
  67195. /**
  67196. * Update relevant scaling values based on the ScaleManager dimension and game dimensions,
  67197. * which should already be set. This does not change {@link #sourceAspectRatio}.
  67198. *
  67199. * @method Phaser.ScaleManager#updateScalingAndBounds
  67200. * @private
  67201. */
  67202. updateScalingAndBounds: function () {
  67203. this.scaleFactor.x = this.game.width / this.width;
  67204. this.scaleFactor.y = this.game.height / this.height;
  67205. this.scaleFactorInversed.x = this.width / this.game.width;
  67206. this.scaleFactorInversed.y = this.height / this.game.height;
  67207. this.aspectRatio = this.width / this.height;
  67208. // This can be invoked in boot pre-canvas
  67209. if (this.game.canvas)
  67210. {
  67211. this.dom.getOffset(this.game.canvas, this.offset);
  67212. }
  67213. this.bounds.setTo(this.offset.x, this.offset.y, this.width, this.height);
  67214. // Can be invoked in boot pre-input
  67215. if (this.game.input && this.game.input.scale)
  67216. {
  67217. this.game.input.scale.setTo(this.scaleFactor.x, this.scaleFactor.y);
  67218. }
  67219. },
  67220. /**
  67221. * Force the game to run in only one orientation.
  67222. *
  67223. * This enables generation of incorrect orientation signals and affects resizing but does not otherwise rotate or lock the orientation.
  67224. *
  67225. * Orientation checks are performed via the Screen Orientation API, if available in browser. This means it will check your monitor
  67226. * orientation on desktop, or your device orientation on mobile, rather than comparing actual game dimensions. If you need to check the
  67227. * viewport dimensions instead and bypass the Screen Orientation API then set: `ScaleManager.compatibility.orientationFallback = 'viewport'`
  67228. *
  67229. * @method Phaser.ScaleManager#forceOrientation
  67230. * @public
  67231. * @param {boolean} forceLandscape - true if the game should run in landscape mode only.
  67232. * @param {boolean} [forcePortrait=false] - true if the game should run in portrait mode only.
  67233. */
  67234. forceOrientation: function (forceLandscape, forcePortrait) {
  67235. if (forcePortrait === undefined) { forcePortrait = false; }
  67236. if (forceLandscape === true && forcePortrait === true)
  67237. {
  67238. console.warn('Phaser.ScaleManager: forceLandscape and forcePortrait cannot both be true.');
  67239. return;
  67240. }
  67241. this.forceLandscape = forceLandscape;
  67242. this.forcePortrait = forcePortrait;
  67243. this.queueUpdate(true);
  67244. },
  67245. /**
  67246. * Classify the orientation, per `getScreenOrientation`.
  67247. *
  67248. * @method Phaser.ScaleManager#classifyOrientation
  67249. * @private
  67250. * @param {string} orientation - The orientation string, e.g. 'portrait-primary'.
  67251. * @return {?string} The classified orientation: 'portrait', 'landscape`, or null.
  67252. */
  67253. classifyOrientation: function (orientation) {
  67254. if (orientation === 'portrait-primary' || orientation === 'portrait-secondary')
  67255. {
  67256. return 'portrait';
  67257. }
  67258. else if (orientation === 'landscape-primary' || orientation === 'landscape-secondary')
  67259. {
  67260. return 'landscape';
  67261. }
  67262. else
  67263. {
  67264. return null;
  67265. }
  67266. },
  67267. /**
  67268. * Updates the current orientation and dispatches orientation change events.
  67269. *
  67270. * @method Phaser.ScaleManager#updateOrientationState
  67271. * @private
  67272. * @return {boolean} True if the orientation state changed which means a forced update is likely required.
  67273. */
  67274. updateOrientationState: function () {
  67275. var previousOrientation = this.screenOrientation;
  67276. var previouslyIncorrect = this.incorrectOrientation;
  67277. this.screenOrientation = this.dom.getScreenOrientation(this.compatibility.orientationFallback);
  67278. this.incorrectOrientation = (this.forceLandscape && !this.isLandscape) ||
  67279. (this.forcePortrait && !this.isPortrait);
  67280. var changed = previousOrientation !== this.screenOrientation;
  67281. var correctnessChanged = previouslyIncorrect !== this.incorrectOrientation;
  67282. if (correctnessChanged)
  67283. {
  67284. if (this.incorrectOrientation)
  67285. {
  67286. this.enterIncorrectOrientation.dispatch();
  67287. }
  67288. else
  67289. {
  67290. this.leaveIncorrectOrientation.dispatch();
  67291. }
  67292. }
  67293. if (changed || correctnessChanged)
  67294. {
  67295. this.onOrientationChange.dispatch(this, previousOrientation, previouslyIncorrect);
  67296. }
  67297. return changed || correctnessChanged;
  67298. },
  67299. /**
  67300. * window.orientationchange event handler.
  67301. *
  67302. * @method Phaser.ScaleManager#orientationChange
  67303. * @private
  67304. * @param {Event} event - The orientationchange event data.
  67305. */
  67306. orientationChange: function (event) {
  67307. this.event = event;
  67308. this.queueUpdate(true);
  67309. },
  67310. /**
  67311. * window.resize event handler.
  67312. *
  67313. * @method Phaser.ScaleManager#windowResize
  67314. * @private
  67315. * @param {Event} event - The resize event data.
  67316. */
  67317. windowResize: function (event) {
  67318. this.event = event;
  67319. this.queueUpdate(true);
  67320. },
  67321. /**
  67322. * Scroll to the top - in some environments. See `compatibility.scrollTo`.
  67323. *
  67324. * @method Phaser.ScaleManager#scrollTop
  67325. * @private
  67326. */
  67327. scrollTop: function () {
  67328. var scrollTo = this.compatibility.scrollTo;
  67329. if (scrollTo)
  67330. {
  67331. window.scrollTo(scrollTo.x, scrollTo.y);
  67332. }
  67333. },
  67334. /**
  67335. * The "refresh" methods informs the ScaleManager that a layout refresh is required.
  67336. *
  67337. * The ScaleManager automatically queues a layout refresh (eg. updates the Game size or Display canvas layout)
  67338. * when the browser is resized, the orientation changes, or when there is a detected change
  67339. * of the Parent size. Refreshing is also done automatically when public properties,
  67340. * such as {@link #scaleMode}, are updated or state-changing methods are invoked.
  67341. *
  67342. * The "refresh" method _may_ need to be used in a few (rare) situtations when
  67343. *
  67344. * - a device change event is not correctly detected; or
  67345. * - the Parent size changes (and an immediate reflow is desired); or
  67346. * - the ScaleManager state is updated by non-standard means; or
  67347. * - certain {@link #compatibility} properties are manually changed.
  67348. *
  67349. * The queued layout refresh is not immediate but will run promptly in an upcoming `preRender`.
  67350. *
  67351. * @method Phaser.ScaleManager#refresh
  67352. * @public
  67353. */
  67354. refresh: function () {
  67355. this.scrollTop();
  67356. this.queueUpdate(true);
  67357. },
  67358. /**
  67359. * Updates the game / canvas position and size.
  67360. *
  67361. * @method Phaser.ScaleManager#updateLayout
  67362. * @private
  67363. */
  67364. updateLayout: function () {
  67365. var scaleMode = this.currentScaleMode;
  67366. if (scaleMode === Phaser.ScaleManager.RESIZE)
  67367. {
  67368. this.reflowGame();
  67369. return;
  67370. }
  67371. this.scrollTop();
  67372. if (this.compatibility.forceMinimumDocumentHeight)
  67373. {
  67374. // (This came from older code, by why is it here?)
  67375. // Set minimum height of content to new window height
  67376. document.documentElement.style.minHeight = window.innerHeight + 'px';
  67377. }
  67378. if (this.incorrectOrientation)
  67379. {
  67380. this.setMaximum();
  67381. }
  67382. else
  67383. {
  67384. if (scaleMode === Phaser.ScaleManager.EXACT_FIT)
  67385. {
  67386. this.setExactFit();
  67387. }
  67388. else if (scaleMode === Phaser.ScaleManager.SHOW_ALL)
  67389. {
  67390. if (!this.isFullScreen && this.boundingParent &&
  67391. this.compatibility.canExpandParent)
  67392. {
  67393. // Try to expand parent out, but choosing maximizing dimensions.
  67394. // Then select minimize dimensions which should then honor parent
  67395. // maximum bound applications.
  67396. this.setShowAll(true);
  67397. this.resetCanvas();
  67398. this.setShowAll();
  67399. }
  67400. else
  67401. {
  67402. this.setShowAll();
  67403. }
  67404. }
  67405. else if (scaleMode === Phaser.ScaleManager.NO_SCALE)
  67406. {
  67407. this.width = this.game.width;
  67408. this.height = this.game.height;
  67409. }
  67410. else if (scaleMode === Phaser.ScaleManager.USER_SCALE)
  67411. {
  67412. this.width = (this.game.width * this._userScaleFactor.x) - this._userScaleTrim.x;
  67413. this.height = (this.game.height * this._userScaleFactor.y) - this._userScaleTrim.y;
  67414. }
  67415. }
  67416. if (!this.compatibility.canExpandParent &&
  67417. (scaleMode === Phaser.ScaleManager.SHOW_ALL || scaleMode === Phaser.ScaleManager.USER_SCALE))
  67418. {
  67419. var bounds = this.getParentBounds(this._tempBounds);
  67420. this.width = Math.min(this.width, bounds.width);
  67421. this.height = Math.min(this.height, bounds.height);
  67422. }
  67423. // Always truncate / force to integer
  67424. this.width = this.width | 0;
  67425. this.height = this.height | 0;
  67426. this.reflowCanvas();
  67427. },
  67428. /**
  67429. * Returns the computed Parent size/bounds that the Display canvas is allowed/expected to fill.
  67430. *
  67431. * If in fullscreen mode or without parent (see {@link #parentIsWindow}),
  67432. * this will be the bounds of the visual viewport itself.
  67433. *
  67434. * This function takes the {@link #windowConstraints} into consideration - if the parent is partially outside
  67435. * the viewport then this function may return a smaller than expected size.
  67436. *
  67437. * Values are rounded to the nearest pixel.
  67438. *
  67439. * @method Phaser.ScaleManager#getParentBounds
  67440. * @protected
  67441. * @param {Phaser.Rectangle} [target=(new Rectangle)] - The rectangle to update; a new one is created as needed.
  67442. * @return {Phaser.Rectangle} The established parent bounds.
  67443. */
  67444. getParentBounds: function (target) {
  67445. var bounds = target || new Phaser.Rectangle();
  67446. var parentNode = this.boundingParent;
  67447. var visualBounds = this.dom.visualBounds;
  67448. var layoutBounds = this.dom.layoutBounds;
  67449. if (!parentNode)
  67450. {
  67451. bounds.setTo(0, 0, visualBounds.width, visualBounds.height);
  67452. }
  67453. else
  67454. {
  67455. // Ref. http://msdn.microsoft.com/en-us/library/hh781509(v=vs.85).aspx for getBoundingClientRect
  67456. var clientRect = parentNode.getBoundingClientRect();
  67457. var parentRect = (parentNode.offsetParent) ? parentNode.offsetParent.getBoundingClientRect() : parentNode.getBoundingClientRect();
  67458. bounds.setTo(clientRect.left - parentRect.left, clientRect.top - parentRect.top, clientRect.width, clientRect.height);
  67459. var wc = this.windowConstraints;
  67460. if (wc.right)
  67461. {
  67462. var windowBounds = wc.right === 'layout' ? layoutBounds : visualBounds;
  67463. bounds.right = Math.min(bounds.right, windowBounds.width);
  67464. }
  67465. if (wc.bottom)
  67466. {
  67467. var windowBounds = wc.bottom === 'layout' ? layoutBounds : visualBounds;
  67468. bounds.bottom = Math.min(bounds.bottom, windowBounds.height);
  67469. }
  67470. }
  67471. bounds.setTo(
  67472. Math.round(bounds.x), Math.round(bounds.y),
  67473. Math.round(bounds.width), Math.round(bounds.height));
  67474. return bounds;
  67475. },
  67476. /**
  67477. * Shorthand for setting {@link #pageAlignHorizontally} and {@link #pageAlignVertically}.
  67478. *
  67479. * @method Phaser.ScaleManager#align
  67480. * @param {boolean} [horizontal] - Value for {@link #pageAlignHorizontally}. Pass `null` to leave unchanged.
  67481. * @param {boolean} [vertical] - Value for {@link #pageAlignVertically}. Omit or pass `null` to leave unchanged.
  67482. */
  67483. align: function (horizontal, vertical) {
  67484. if (horizontal != null)
  67485. {
  67486. this.pageAlignHorizontally = horizontal;
  67487. }
  67488. if (vertical != null)
  67489. {
  67490. this.pageAlignVertically = vertical;
  67491. }
  67492. },
  67493. /**
  67494. * Update the canvas position/margins - for alignment within the parent container.
  67495. *
  67496. * The canvas margins _must_ be reset/cleared prior to invoking this.
  67497. *
  67498. * @method Phaser.ScaleManager#alignCanvas
  67499. * @private
  67500. * @param {boolean} horizontal - Align horizontally?
  67501. * @param {boolean} vertical - Align vertically?
  67502. */
  67503. alignCanvas: function (horizontal, vertical) {
  67504. var parentBounds = this.getParentBounds(this._tempBounds);
  67505. var canvas = this.game.canvas;
  67506. var margin = this.margin;
  67507. if (horizontal)
  67508. {
  67509. margin.left = margin.right = 0;
  67510. var canvasBounds = canvas.getBoundingClientRect();
  67511. if (this.width < parentBounds.width && !this.incorrectOrientation)
  67512. {
  67513. var currentEdge = canvasBounds.left - parentBounds.x;
  67514. var targetEdge = (parentBounds.width / 2) - (this.width / 2);
  67515. targetEdge = Math.max(targetEdge, 0);
  67516. var offset = targetEdge - currentEdge;
  67517. margin.left = Math.round(offset);
  67518. }
  67519. canvas.style.marginLeft = margin.left + 'px';
  67520. if (margin.left !== 0)
  67521. {
  67522. margin.right = -(parentBounds.width - canvasBounds.width - margin.left);
  67523. canvas.style.marginRight = margin.right + 'px';
  67524. }
  67525. }
  67526. if (vertical)
  67527. {
  67528. margin.top = margin.bottom = 0;
  67529. var canvasBounds = canvas.getBoundingClientRect();
  67530. if (this.height < parentBounds.height && !this.incorrectOrientation)
  67531. {
  67532. var currentEdge = canvasBounds.top - parentBounds.y;
  67533. var targetEdge = (parentBounds.height / 2) - (this.height / 2);
  67534. targetEdge = Math.max(targetEdge, 0);
  67535. var offset = targetEdge - currentEdge;
  67536. margin.top = Math.round(offset);
  67537. }
  67538. canvas.style.marginTop = margin.top + 'px';
  67539. if (margin.top !== 0)
  67540. {
  67541. margin.bottom = -(parentBounds.height - canvasBounds.height - margin.top);
  67542. canvas.style.marginBottom = margin.bottom + 'px';
  67543. }
  67544. }
  67545. // Silly backwards compatibility..
  67546. margin.x = margin.left;
  67547. margin.y = margin.top;
  67548. },
  67549. /**
  67550. * Updates the Game state / size.
  67551. *
  67552. * The canvas margins may always be adjusted, even if alignment is not in effect.
  67553. *
  67554. * @method Phaser.ScaleManager#reflowGame
  67555. * @private
  67556. */
  67557. reflowGame: function () {
  67558. this.resetCanvas('', '');
  67559. var bounds = this.getParentBounds(this._tempBounds);
  67560. this.updateDimensions(bounds.width, bounds.height, true);
  67561. },
  67562. /**
  67563. * Updates the Display canvas size.
  67564. *
  67565. * The canvas margins may always be adjusted, even alignment is not in effect.
  67566. *
  67567. * @method Phaser.ScaleManager#reflowCanvas
  67568. * @private
  67569. */
  67570. reflowCanvas: function () {
  67571. if (!this.incorrectOrientation)
  67572. {
  67573. this.width = Phaser.Math.clamp(this.width, this.minWidth || 0, this.maxWidth || this.width);
  67574. this.height = Phaser.Math.clamp(this.height, this.minHeight || 0, this.maxHeight || this.height);
  67575. }
  67576. this.resetCanvas();
  67577. if (!this.compatibility.noMargins)
  67578. {
  67579. if (this.isFullScreen && this._createdFullScreenTarget)
  67580. {
  67581. this.alignCanvas(true, true);
  67582. }
  67583. else
  67584. {
  67585. this.alignCanvas(this.pageAlignHorizontally, this.pageAlignVertically);
  67586. }
  67587. }
  67588. this.updateScalingAndBounds();
  67589. },
  67590. /**
  67591. * "Reset" the Display canvas and set the specified width/height.
  67592. *
  67593. * @method Phaser.ScaleManager#resetCanvas
  67594. * @private
  67595. * @param {string} [cssWidth=(current width)] - The css width to set.
  67596. * @param {string} [cssHeight=(current height)] - The css height to set.
  67597. */
  67598. resetCanvas: function (cssWidth, cssHeight) {
  67599. if (cssWidth === undefined) { cssWidth = this.width + 'px'; }
  67600. if (cssHeight === undefined) { cssHeight = this.height + 'px'; }
  67601. var canvas = this.game.canvas;
  67602. if (!this.compatibility.noMargins)
  67603. {
  67604. canvas.style.marginLeft = '';
  67605. canvas.style.marginTop = '';
  67606. canvas.style.marginRight = '';
  67607. canvas.style.marginBottom = '';
  67608. }
  67609. canvas.style.width = cssWidth;
  67610. canvas.style.height = cssHeight;
  67611. },
  67612. /**
  67613. * Queues/marks a size/bounds check as needing to occur (from `preUpdate`).
  67614. *
  67615. * @method Phaser.ScaleManager#queueUpdate
  67616. * @private
  67617. * @param {boolean} force - If true resets the parent bounds to ensure the check is dirty.
  67618. */
  67619. queueUpdate: function (force) {
  67620. if (force)
  67621. {
  67622. this._parentBounds.width = 0;
  67623. this._parentBounds.height = 0;
  67624. }
  67625. this._updateThrottle = this._updateThrottleReset;
  67626. },
  67627. /**
  67628. * Reset internal data/state.
  67629. *
  67630. * @method Phaser.ScaleManager#reset
  67631. * @private
  67632. */
  67633. reset: function (clearWorld) {
  67634. if (clearWorld && this.grid)
  67635. {
  67636. this.grid.reset();
  67637. }
  67638. },
  67639. /**
  67640. * Updates the width/height to that of the window.
  67641. *
  67642. * @method Phaser.ScaleManager#setMaximum
  67643. * @private
  67644. */
  67645. setMaximum: function () {
  67646. this.width = this.dom.visualBounds.width;
  67647. this.height = this.dom.visualBounds.height;
  67648. },
  67649. /**
  67650. * Updates the width/height such that the game is scaled proportionally.
  67651. *
  67652. * @method Phaser.ScaleManager#setShowAll
  67653. * @private
  67654. * @param {boolean} expanding - If true then the maximizing dimension is chosen.
  67655. */
  67656. setShowAll: function (expanding) {
  67657. var bounds = this.getParentBounds(this._tempBounds);
  67658. var width = bounds.width;
  67659. var height = bounds.height;
  67660. var multiplier;
  67661. if (expanding)
  67662. {
  67663. multiplier = Math.max((height / this.game.height), (width / this.game.width));
  67664. }
  67665. else
  67666. {
  67667. multiplier = Math.min((height / this.game.height), (width / this.game.width));
  67668. }
  67669. this.width = Math.round(this.game.width * multiplier);
  67670. this.height = Math.round(this.game.height * multiplier);
  67671. },
  67672. /**
  67673. * Updates the width/height such that the game is stretched to the available size.
  67674. * Honors {@link #maxWidth} and {@link #maxHeight} when _not_ in fullscreen.
  67675. *
  67676. * @method Phaser.ScaleManager#setExactFit
  67677. * @private
  67678. */
  67679. setExactFit: function () {
  67680. var bounds = this.getParentBounds(this._tempBounds);
  67681. this.width = bounds.width;
  67682. this.height = bounds.height;
  67683. if (this.isFullScreen)
  67684. {
  67685. // Max/min not honored fullscreen
  67686. return;
  67687. }
  67688. if (this.maxWidth)
  67689. {
  67690. this.width = Math.min(this.width, this.maxWidth);
  67691. }
  67692. if (this.maxHeight)
  67693. {
  67694. this.height = Math.min(this.height, this.maxHeight);
  67695. }
  67696. },
  67697. /**
  67698. * Creates a fullscreen target. This is called automatically as as needed when entering
  67699. * fullscreen mode and the resulting element is supplied to {@link #onFullScreenInit}.
  67700. *
  67701. * Use {@link #onFullScreenInit} to customize the created object.
  67702. *
  67703. * @method Phaser.ScaleManager#createFullScreenTarget
  67704. * @protected
  67705. */
  67706. createFullScreenTarget: function () {
  67707. var fsTarget = document.createElement('div');
  67708. fsTarget.style.margin = '0';
  67709. fsTarget.style.padding = '0';
  67710. fsTarget.style.background = '#000';
  67711. return fsTarget;
  67712. },
  67713. /**
  67714. * Display the game in the browser's fullscreen mode.
  67715. *
  67716. * This _must_ be called from a user-input Pointer or Mouse event (and possibly a {@link https://www.chromestatus.com/feature/6131337345892352 "user gesture"}), e.g.,
  67717. *
  67718. * - {@link Phaser.Events#onInputUp}
  67719. * - {@link Phaser.Input#onUp} or {@link Phaser.Input#onTap}
  67720. * - `click`, `mousedown`, `mouseup`, `pointerup`, or `touchend`
  67721. *
  67722. * Games within an iframe will also be blocked from fullscreen unless the iframe has the `allowfullscreen` attribute.
  67723. *
  67724. * The {@link https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API Fullscreen API} must be {@link http://caniuse.com/#search=fullscreen supported by the browser} for this to work - it is not the same as setting
  67725. * the game size to fill the browser window. See {@link Phaser.ScaleManager#compatibility compatibility.supportsFullScreen} to check if the current
  67726. * device is reported to support fullscreen mode.
  67727. *
  67728. * The {@link #fullScreenFailed} signal will be dispatched if the fullscreen change request failed or the game does not support the Fullscreen API.
  67729. *
  67730. * Safari blocks access to keyboard events in fullscreen mode (as a security measure).
  67731. *
  67732. * @method Phaser.ScaleManager#startFullScreen
  67733. * @public
  67734. * @param {boolean} [antialias] - Changes the anti-alias feature of the canvas before jumping in to fullscreen (false = retain pixel art, true = smooth art). If not specified then no change is made. Only works in CANVAS mode.
  67735. * @param {boolean} [allowTrampoline=undefined] - Internal argument. If `false` click trampolining is suppressed.
  67736. * @return {boolean} Returns true if the device supports fullscreen mode and fullscreen mode was attempted to be started. (It might not actually start, wait for the signals.)
  67737. */
  67738. startFullScreen: function (antialias, allowTrampoline) {
  67739. if (this.isFullScreen)
  67740. {
  67741. return false;
  67742. }
  67743. if (!this.compatibility.supportsFullScreen)
  67744. {
  67745. // Error is called in timeout to emulate the real fullscreenerror event better
  67746. var _this = this;
  67747. setTimeout(function () {
  67748. _this.fullScreenError();
  67749. }, 10);
  67750. return;
  67751. }
  67752. if (this.compatibility.clickTrampoline === 'when-not-mouse')
  67753. {
  67754. var input = this.game.input;
  67755. if (input.activePointer &&
  67756. input.activePointer !== input.mousePointer &&
  67757. (allowTrampoline || allowTrampoline !== false))
  67758. {
  67759. input.activePointer.addClickTrampoline("startFullScreen", this.startFullScreen, this, [antialias, false]);
  67760. return;
  67761. }
  67762. }
  67763. if (antialias !== undefined && this.game.renderType === Phaser.CANVAS)
  67764. {
  67765. this.game.stage.smoothed = antialias;
  67766. }
  67767. var fsTarget = this.fullScreenTarget;
  67768. if (!fsTarget)
  67769. {
  67770. this.cleanupCreatedTarget();
  67771. this._createdFullScreenTarget = this.createFullScreenTarget();
  67772. fsTarget = this._createdFullScreenTarget;
  67773. }
  67774. var initData = {
  67775. targetElement: fsTarget
  67776. };
  67777. this.hasPhaserSetFullScreen = true;
  67778. this.onFullScreenInit.dispatch(this, initData);
  67779. if (this._createdFullScreenTarget)
  67780. {
  67781. // Move the Display canvas inside of the target and add the target to the DOM
  67782. // (The target has to be added for the Fullscreen API to work.)
  67783. var canvas = this.game.canvas;
  67784. var parent = canvas.parentNode;
  67785. parent.insertBefore(fsTarget, canvas);
  67786. fsTarget.appendChild(canvas);
  67787. }
  67788. if (this.game.device.fullscreenKeyboard)
  67789. {
  67790. fsTarget[this.game.device.requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
  67791. }
  67792. else
  67793. {
  67794. fsTarget[this.game.device.requestFullscreen]();
  67795. }
  67796. return true;
  67797. },
  67798. /**
  67799. * Stops / exits fullscreen mode, if active.
  67800. *
  67801. * @method Phaser.ScaleManager#stopFullScreen
  67802. * @public
  67803. * @return {boolean} Returns true if the browser supports fullscreen mode and fullscreen mode will be exited.
  67804. */
  67805. stopFullScreen: function () {
  67806. if (!this.isFullScreen || !this.compatibility.supportsFullScreen)
  67807. {
  67808. return false;
  67809. }
  67810. this.hasPhaserSetFullScreen = false;
  67811. document[this.game.device.cancelFullscreen]();
  67812. return true;
  67813. },
  67814. /**
  67815. * Cleans up the previous fullscreen target, if such was automatically created.
  67816. * This ensures the canvas is restored to its former parent, assuming the target didn't move.
  67817. *
  67818. * @method Phaser.ScaleManager#cleanupCreatedTarget
  67819. * @private
  67820. */
  67821. cleanupCreatedTarget: function () {
  67822. var fsTarget = this._createdFullScreenTarget;
  67823. if (fsTarget && fsTarget.parentNode)
  67824. {
  67825. // Make sure to cleanup synthetic target for sure;
  67826. // swap the canvas back to the parent.
  67827. var parent = fsTarget.parentNode;
  67828. parent.insertBefore(this.game.canvas, fsTarget);
  67829. parent.removeChild(fsTarget);
  67830. }
  67831. this._createdFullScreenTarget = null;
  67832. },
  67833. /**
  67834. * Used to prepare/restore extra fullscreen mode settings.
  67835. * (This does move any elements within the DOM tree.)
  67836. *
  67837. * @method Phaser.ScaleManager#prepScreenMode
  67838. * @private
  67839. * @param {boolean} enteringFullscreen - True if _entering_ fullscreen, false if _leaving_.
  67840. */
  67841. prepScreenMode: function (enteringFullscreen) {
  67842. var createdTarget = !!this._createdFullScreenTarget;
  67843. var fsTarget = this._createdFullScreenTarget || this.fullScreenTarget;
  67844. if (enteringFullscreen)
  67845. {
  67846. if (createdTarget || this.fullScreenScaleMode === Phaser.ScaleManager.EXACT_FIT)
  67847. {
  67848. // Resize target, as long as it's not the canvas
  67849. if (fsTarget !== this.game.canvas)
  67850. {
  67851. this._fullScreenRestore = {
  67852. targetWidth: fsTarget.style.width,
  67853. targetHeight: fsTarget.style.height
  67854. };
  67855. fsTarget.style.width = '100%';
  67856. fsTarget.style.height = '100%';
  67857. }
  67858. }
  67859. }
  67860. else
  67861. {
  67862. // Have restore information
  67863. if (this._fullScreenRestore)
  67864. {
  67865. fsTarget.style.width = this._fullScreenRestore.targetWidth;
  67866. fsTarget.style.height = this._fullScreenRestore.targetHeight;
  67867. this._fullScreenRestore = null;
  67868. }
  67869. // Always reset to game size
  67870. this.updateDimensions(this._gameSize.width, this._gameSize.height, true);
  67871. this.resetCanvas();
  67872. }
  67873. },
  67874. /**
  67875. * Called automatically when the browser enters of leaves fullscreen mode.
  67876. *
  67877. * @method Phaser.ScaleManager#fullScreenChange
  67878. * @private
  67879. * @param {Event} [event=undefined] - The fullscreenchange event
  67880. */
  67881. fullScreenChange: function (event) {
  67882. this.event = event;
  67883. if (this.isFullScreen)
  67884. {
  67885. this.prepScreenMode(true);
  67886. this.updateLayout();
  67887. this.queueUpdate(true);
  67888. }
  67889. else
  67890. {
  67891. this.prepScreenMode(false);
  67892. this.cleanupCreatedTarget();
  67893. this.updateLayout();
  67894. this.queueUpdate(true);
  67895. }
  67896. this.onFullScreenChange.dispatch(this, this.width, this.height);
  67897. },
  67898. /**
  67899. * Called automatically when the browser fullscreen request fails;
  67900. * or called when a fullscreen request is made on a device for which it is not supported.
  67901. *
  67902. * @method Phaser.ScaleManager#fullScreenError
  67903. * @private
  67904. * @param {Event} [event=undefined] - The fullscreenerror event; undefined if invoked on a device that does not support the Fullscreen API.
  67905. */
  67906. fullScreenError: function (event) {
  67907. this.event = event;
  67908. this.cleanupCreatedTarget();
  67909. console.warn('Phaser.ScaleManager: requestFullscreen failed or device does not support the Fullscreen API');
  67910. this.onFullScreenError.dispatch(this);
  67911. },
  67912. /**
  67913. * Takes a Sprite or Image object and scales it to fit the given dimensions.
  67914. * Scaling happens proportionally without distortion to the sprites texture.
  67915. * The letterBox parameter controls if scaling will produce a letter-box effect or zoom the
  67916. * sprite until it fills the given values. Note that with letterBox set to false the scaled sprite may spill out over either
  67917. * the horizontal or vertical sides of the target dimensions. If you wish to stop this you can crop the Sprite.
  67918. *
  67919. * @method Phaser.ScaleManager#scaleSprite
  67920. * @protected
  67921. * @param {Phaser.Sprite|Phaser.Image} sprite - The sprite we want to scale.
  67922. * @param {integer} [width] - The target width that we want to fit the sprite in to. If not given it defaults to ScaleManager.width.
  67923. * @param {integer} [height] - The target height that we want to fit the sprite in to. If not given it defaults to ScaleManager.height.
  67924. * @param {boolean} [letterBox=false] - True if we want the `fitted` mode. Otherwise, the function uses the `zoom` mode.
  67925. * @return {Phaser.Sprite|Phaser.Image} The scaled sprite.
  67926. */
  67927. scaleSprite: function (sprite, width, height, letterBox) {
  67928. if (width === undefined) { width = this.width; }
  67929. if (height === undefined) { height = this.height; }
  67930. if (letterBox === undefined) { letterBox = false; }
  67931. if (!sprite || !sprite['scale'])
  67932. {
  67933. return sprite;
  67934. }
  67935. sprite.scale.x = 1;
  67936. sprite.scale.y = 1;
  67937. if ((sprite.width <= 0) || (sprite.height <= 0) || (width <= 0) || (height <= 0))
  67938. {
  67939. return sprite;
  67940. }
  67941. var scaleX1 = width;
  67942. var scaleY1 = (sprite.height * width) / sprite.width;
  67943. var scaleX2 = (sprite.width * height) / sprite.height;
  67944. var scaleY2 = height;
  67945. var scaleOnWidth = (scaleX2 > width);
  67946. if (scaleOnWidth)
  67947. {
  67948. scaleOnWidth = letterBox;
  67949. }
  67950. else
  67951. {
  67952. scaleOnWidth = !letterBox;
  67953. }
  67954. if (scaleOnWidth)
  67955. {
  67956. sprite.width = Math.floor(scaleX1);
  67957. sprite.height = Math.floor(scaleY1);
  67958. }
  67959. else
  67960. {
  67961. sprite.width = Math.floor(scaleX2);
  67962. sprite.height = Math.floor(scaleY2);
  67963. }
  67964. // Enable at some point?
  67965. // sprite.x = Math.floor((width - sprite.width) / 2);
  67966. // sprite.y = Math.floor((height - sprite.height) / 2);
  67967. return sprite;
  67968. },
  67969. /**
  67970. * Destroys the ScaleManager and removes any event listeners.
  67971. * This should probably only be called when the game is destroyed.
  67972. *
  67973. * @method Phaser.ScaleManager#destroy
  67974. * @protected
  67975. */
  67976. destroy: function () {
  67977. this.game.onResume.remove(this._gameResumed, this);
  67978. window.removeEventListener('orientationchange', this._orientationChange, false);
  67979. window.removeEventListener('resize', this._windowResize, false);
  67980. if (this.compatibility.supportsFullScreen)
  67981. {
  67982. document.removeEventListener('webkitfullscreenchange', this._fullScreenChange, false);
  67983. document.removeEventListener('mozfullscreenchange', this._fullScreenChange, false);
  67984. document.removeEventListener('MSFullscreenChange', this._fullScreenChange, false);
  67985. document.removeEventListener('fullscreenchange', this._fullScreenChange, false);
  67986. document.removeEventListener('webkitfullscreenerror', this._fullScreenError, false);
  67987. document.removeEventListener('mozfullscreenerror', this._fullScreenError, false);
  67988. document.removeEventListener('MSFullscreenError', this._fullScreenError, false);
  67989. document.removeEventListener('fullscreenerror', this._fullScreenError, false);
  67990. }
  67991. }
  67992. };
  67993. Phaser.ScaleManager.prototype.constructor = Phaser.ScaleManager;
  67994. /**
  67995. * The DOM element that is considered the Parent bounding element, if any.
  67996. *
  67997. * This `null` if {@link #parentIsWindow} is true or if fullscreen mode is entered and {@link #fullScreenTarget} is specified.
  67998. * It will also be null if there is no game canvas or if the game canvas has no parent.
  67999. *
  68000. * @name Phaser.ScaleManager#boundingParent
  68001. * @property {?DOMElement} boundingParent
  68002. * @readonly
  68003. */
  68004. Object.defineProperty(Phaser.ScaleManager.prototype, "boundingParent", {
  68005. get: function () {
  68006. if (this.parentIsWindow ||
  68007. (this.isFullScreen && this.hasPhaserSetFullScreen && !this._createdFullScreenTarget))
  68008. {
  68009. return null;
  68010. }
  68011. var parentNode = this.game.canvas && this.game.canvas.parentNode;
  68012. return parentNode || null;
  68013. }
  68014. });
  68015. /**
  68016. * The scaling method used by the ScaleManager when not in fullscreen.
  68017. *
  68018. * <dl>
  68019. * <dt>{@link Phaser.ScaleManager.NO_SCALE}</dt>
  68020. * <dd>
  68021. * The Game display area will not be scaled - even if it is too large for the canvas/screen.
  68022. * This mode _ignores_ any applied scaling factor and displays the canvas at the Game size.
  68023. * </dd>
  68024. * <dt>{@link Phaser.ScaleManager.EXACT_FIT}</dt>
  68025. * <dd>
  68026. * The Game display area will be _stretched_ to fill the entire size of the canvas's parent element and/or screen.
  68027. * Proportions are not maintained.
  68028. * </dd>
  68029. * <dt>{@link Phaser.ScaleManager.SHOW_ALL}</dt>
  68030. * <dd>
  68031. * Show the entire game display area while _maintaining_ the original aspect ratio.
  68032. * </dd>
  68033. * <dt>{@link Phaser.ScaleManager.RESIZE}</dt>
  68034. * <dd>
  68035. * The dimensions of the game display area are changed to match the size of the parent container.
  68036. * That is, this mode _changes the Game size_ to match the display size.
  68037. * <p>
  68038. * Any manually set Game size (see {@link #setGameSize}) is ignored while in effect.
  68039. * </dd>
  68040. * <dt>{@link Phaser.ScaleManager.USER_SCALE}</dt>
  68041. * <dd>
  68042. * The game Display is scaled according to the user-specified scale set by {@link Phaser.ScaleManager#setUserScale setUserScale}.
  68043. * <p>
  68044. * This scale can be adjusted in the {@link Phaser.ScaleManager#setResizeCallback resize callback}
  68045. * for flexible custom-sizing needs.
  68046. * </dd>
  68047. * </dl>
  68048. *
  68049. * @name Phaser.ScaleManager#scaleMode
  68050. * @property {integer} scaleMode
  68051. */
  68052. Object.defineProperty(Phaser.ScaleManager.prototype, "scaleMode", {
  68053. get: function () {
  68054. return this._scaleMode;
  68055. },
  68056. set: function (value) {
  68057. if (value !== this._scaleMode)
  68058. {
  68059. if (!this.isFullScreen)
  68060. {
  68061. this.updateDimensions(this._gameSize.width, this._gameSize.height, true);
  68062. this.queueUpdate(true);
  68063. }
  68064. this._scaleMode = value;
  68065. }
  68066. return this._scaleMode;
  68067. }
  68068. });
  68069. /**
  68070. * The scaling method used by the ScaleManager when in fullscreen.
  68071. *
  68072. * See {@link Phaser.ScaleManager#scaleMode scaleMode} for the different modes allowed.
  68073. *
  68074. * @name Phaser.ScaleManager#fullScreenScaleMode
  68075. * @property {integer} fullScreenScaleMode
  68076. */
  68077. Object.defineProperty(Phaser.ScaleManager.prototype, "fullScreenScaleMode", {
  68078. get: function () {
  68079. return this._fullScreenScaleMode;
  68080. },
  68081. set: function (value) {
  68082. if (value !== this._fullScreenScaleMode)
  68083. {
  68084. // If in fullscreen then need a wee bit more work
  68085. if (this.isFullScreen)
  68086. {
  68087. this.prepScreenMode(false);
  68088. this._fullScreenScaleMode = value;
  68089. this.prepScreenMode(true);
  68090. this.queueUpdate(true);
  68091. }
  68092. else
  68093. {
  68094. this._fullScreenScaleMode = value;
  68095. }
  68096. }
  68097. return this._fullScreenScaleMode;
  68098. }
  68099. });
  68100. /**
  68101. * Returns the current scale mode - for normal or fullscreen operation.
  68102. *
  68103. * See {@link Phaser.ScaleManager#scaleMode scaleMode} for the different modes allowed.
  68104. *
  68105. * @name Phaser.ScaleManager#currentScaleMode
  68106. * @property {number} currentScaleMode
  68107. * @protected
  68108. * @readonly
  68109. */
  68110. Object.defineProperty(Phaser.ScaleManager.prototype, "currentScaleMode", {
  68111. get: function () {
  68112. return this.isFullScreen ? this._fullScreenScaleMode : this._scaleMode;
  68113. }
  68114. });
  68115. /**
  68116. * When enabled the Display canvas will be horizontally-aligned _in the Parent container_ (or {@link Phaser.ScaleManager#parentIsWindow window}).
  68117. *
  68118. * To align horizontally across the page the Display canvas should be added directly to page;
  68119. * or the parent container should itself be horizontally aligned.
  68120. *
  68121. * Horizontal alignment is not applicable with the {@link .RESIZE} scaling mode.
  68122. *
  68123. * @name Phaser.ScaleManager#pageAlignHorizontally
  68124. * @property {boolean} pageAlignHorizontally
  68125. * @default false
  68126. */
  68127. Object.defineProperty(Phaser.ScaleManager.prototype, "pageAlignHorizontally", {
  68128. get: function () {
  68129. return this._pageAlignHorizontally;
  68130. },
  68131. set: function (value) {
  68132. if (value !== this._pageAlignHorizontally)
  68133. {
  68134. this._pageAlignHorizontally = value;
  68135. this.queueUpdate(true);
  68136. }
  68137. }
  68138. });
  68139. /**
  68140. * When enabled the Display canvas will be vertically-aligned _in the Parent container_ (or {@link Phaser.ScaleManager#parentIsWindow window}).
  68141. *
  68142. * To align vertically the Parent element should have a _non-collapsible_ height, such that it will maintain
  68143. * a height _larger_ than the height of the contained Game canvas - the game canvas will then be scaled vertically
  68144. * _within_ the remaining available height dictated by the Parent element.
  68145. *
  68146. * One way to prevent the parent from collapsing is to add an absolute "min-height" CSS property to the parent element.
  68147. * If specifying a relative "min-height/height" or adjusting margins, the Parent height must still be non-collapsible (see note).
  68148. *
  68149. * _Note_: In version 2.2 the minimum document height is _not_ automatically set to the viewport/window height.
  68150. * To automatically update the minimum document height set {@link Phaser.ScaleManager#compatibility compatibility.forceMinimumDocumentHeight} to true.
  68151. *
  68152. * Vertical alignment is not applicable with the {@link .RESIZE} scaling mode.
  68153. *
  68154. * @name Phaser.ScaleManager#pageAlignVertically
  68155. * @property {boolean} pageAlignVertically
  68156. * @default false
  68157. */
  68158. Object.defineProperty(Phaser.ScaleManager.prototype, "pageAlignVertically", {
  68159. get: function () {
  68160. return this._pageAlignVertically;
  68161. },
  68162. set: function (value) {
  68163. if (value !== this._pageAlignVertically)
  68164. {
  68165. this._pageAlignVertically = value;
  68166. this.queueUpdate(true);
  68167. }
  68168. }
  68169. });
  68170. /**
  68171. * Returns true if the browser is in fullscreen mode, otherwise false.
  68172. * @name Phaser.ScaleManager#isFullScreen
  68173. * @property {boolean} isFullScreen
  68174. * @readonly
  68175. */
  68176. Object.defineProperty(Phaser.ScaleManager.prototype, "isFullScreen", {
  68177. get: function () {
  68178. return !!(document['fullscreenElement'] ||
  68179. document['webkitFullscreenElement'] ||
  68180. document['mozFullScreenElement'] ||
  68181. document['msFullscreenElement']);
  68182. }
  68183. });
  68184. /**
  68185. * Returns true if the screen orientation is in portrait mode.
  68186. *
  68187. * @name Phaser.ScaleManager#isPortrait
  68188. * @property {boolean} isPortrait
  68189. * @readonly
  68190. */
  68191. Object.defineProperty(Phaser.ScaleManager.prototype, "isPortrait", {
  68192. get: function () {
  68193. return this.classifyOrientation(this.screenOrientation) === 'portrait';
  68194. }
  68195. });
  68196. /**
  68197. * Returns true if the screen orientation is in landscape mode.
  68198. *
  68199. * @name Phaser.ScaleManager#isLandscape
  68200. * @property {boolean} isLandscape
  68201. * @readonly
  68202. */
  68203. Object.defineProperty(Phaser.ScaleManager.prototype, "isLandscape", {
  68204. get: function () {
  68205. return this.classifyOrientation(this.screenOrientation) === 'landscape';
  68206. }
  68207. });
  68208. /**
  68209. * Returns true if the game dimensions are portrait (height > width).
  68210. * This is especially useful to check when using the RESIZE scale mode
  68211. * but wanting to maintain game orientation on desktop browsers,
  68212. * where typically the screen orientation will always be landscape regardless of the browser viewport.
  68213. *
  68214. * @name Phaser.ScaleManager#isGamePortrait
  68215. * @property {boolean} isGamePortrait
  68216. * @readonly
  68217. */
  68218. Object.defineProperty(Phaser.ScaleManager.prototype, "isGamePortrait", {
  68219. get: function () {
  68220. return (this.height > this.width);
  68221. }
  68222. });
  68223. /**
  68224. * Returns true if the game dimensions are landscape (width > height).
  68225. * This is especially useful to check when using the RESIZE scale mode
  68226. * but wanting to maintain game orientation on desktop browsers,
  68227. * where typically the screen orientation will always be landscape regardless of the browser viewport.
  68228. *
  68229. * @name Phaser.ScaleManager#isGameLandscape
  68230. * @property {boolean} isGameLandscape
  68231. * @readonly
  68232. */
  68233. Object.defineProperty(Phaser.ScaleManager.prototype, "isGameLandscape", {
  68234. get: function () {
  68235. return (this.width > this.height);
  68236. }
  68237. });
  68238. /**
  68239. * @author Richard Davey <rich@photonstorm.com>
  68240. * @copyright 2016 Photon Storm Ltd.
  68241. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  68242. */
  68243. /**
  68244. * A collection of methods for displaying debug information about game objects.
  68245. *
  68246. * If your game is running in Canvas mode, then you should invoke all of the Debug methods from
  68247. * your games `render` function. This is because they are drawn directly onto the game canvas
  68248. * itself, so if you call any debug methods outside of `render` they are likely to be overwritten
  68249. * by the game itself.
  68250. *
  68251. * If your game is running in WebGL then Debug will create a Sprite that is placed at the top of the Stage display list and bind a canvas texture
  68252. * to it, which must be uploaded every frame. Be advised: this is very expensive, especially in browsers like Firefox. So please only enable Debug
  68253. * in WebGL mode if you really need it (or your desktop can cope with it well) and disable it for production!
  68254. *
  68255. * @class Phaser.Utils.Debug
  68256. * @constructor
  68257. * @param {Phaser.Game} game - A reference to the currently running game.
  68258. */
  68259. Phaser.Utils.Debug = function (game) {
  68260. /**
  68261. * @property {Phaser.Game} game - A reference to the currently running Game.
  68262. */
  68263. this.game = game;
  68264. /**
  68265. * @property {Phaser.Image} sprite - If debugging in WebGL mode, this is the Image displaying the debug {@link #bmd BitmapData}.
  68266. */
  68267. this.sprite = null;
  68268. /**
  68269. * @property {Phaser.BitmapData} bmd - In WebGL mode this BitmapData contains a copy of the debug canvas.
  68270. */
  68271. this.bmd = null;
  68272. /**
  68273. * @property {HTMLCanvasElement} canvas - The canvas to which Debug calls draws.
  68274. */
  68275. this.canvas = null;
  68276. /**
  68277. * @property {CanvasRenderingContext2D} context - The 2d context of the canvas.
  68278. */
  68279. this.context = null;
  68280. /**
  68281. * @property {string} font - The font that the debug information is rendered in.
  68282. * @default
  68283. */
  68284. this.font = '14px Courier';
  68285. /**
  68286. * @property {number} columnWidth - The spacing between columns.
  68287. * @default
  68288. */
  68289. this.columnWidth = 100;
  68290. /**
  68291. * @property {number} lineHeight - The line height between the debug text.
  68292. * @default
  68293. */
  68294. this.lineHeight = 16;
  68295. /**
  68296. * @property {number} lineWidth - The width of the stroke on lines and shapes. A positive number.
  68297. * @default
  68298. */
  68299. this.lineWidth = 1;
  68300. /**
  68301. * @property {boolean} renderShadow - Should the text be rendered with a slight shadow? Makes it easier to read on different types of background.
  68302. * @default
  68303. */
  68304. this.renderShadow = true;
  68305. /**
  68306. * @property {number} currentX - The current X position the debug information will be rendered at.
  68307. * @default
  68308. */
  68309. this.currentX = 0;
  68310. /**
  68311. * @property {number} currentY - The current Y position the debug information will be rendered at.
  68312. * @default
  68313. */
  68314. this.currentY = 0;
  68315. /**
  68316. * @property {number} currentAlpha - The alpha of the Debug context, set before all debug information is rendered to it.
  68317. * @default
  68318. */
  68319. this.currentAlpha = 1;
  68320. /**
  68321. * @property {boolean} dirty - Does the canvas need re-rendering?
  68322. * @default
  68323. */
  68324. this.dirty = false;
  68325. /**
  68326. * @property {boolean} isDisabled - If `enableDebug: false` is passed to {@link Phaser.Game} or if Phaser is built without the Debug class, this will be true.
  68327. * @default
  68328. * @readonly
  68329. */
  68330. this.isDisabled = false;
  68331. /**
  68332. * @property {Phaser.Line} _line - A reusable rendering line.
  68333. * @private
  68334. */
  68335. this._line = null;
  68336. /**
  68337. * @property {Phaser.Rectangle} _rect - A reusable rendering rectangle.
  68338. * @private
  68339. */
  68340. this._rect = null;
  68341. };
  68342. Phaser.Utils.Debug.prototype = {
  68343. /**
  68344. * Internal method that boots the debug displayer.
  68345. *
  68346. * @method Phaser.Utils.Debug#boot
  68347. * @protected
  68348. */
  68349. boot: function () {
  68350. if (this.game.renderType === Phaser.CANVAS)
  68351. {
  68352. this.context = this.game.context;
  68353. }
  68354. else
  68355. {
  68356. this.bmd = new Phaser.BitmapData(this.game, '__DEBUG', this.game.width, this.game.height, true);
  68357. this.sprite = this.game.make.image(0, 0, this.bmd);
  68358. this.game.stage.addChild(this.sprite);
  68359. this.game.scale.onSizeChange.add(this.resize, this);
  68360. this.canvas = Phaser.CanvasPool.create(this, this.game.width, this.game.height);
  68361. this.context = this.canvas.getContext('2d');
  68362. }
  68363. this._line = new Phaser.Line();
  68364. this._rect = new Phaser.Rectangle();
  68365. },
  68366. /**
  68367. * Internal method that resizes the BitmapData and Canvas.
  68368. * Called by ScaleManager.onSizeChange only in WebGL mode.
  68369. *
  68370. * @method Phaser.Utils.Debug#resize
  68371. * @protected
  68372. */
  68373. resize: function () {
  68374. this.bmd.resize(this.game.width, this.game.height);
  68375. this.canvas.width = this.game.width;
  68376. this.canvas.height = this.game.height;
  68377. },
  68378. /**
  68379. * Internal method that clears the canvas (if a Sprite) ready for a new debug session.
  68380. *
  68381. * @method Phaser.Utils.Debug#preUpdate
  68382. * @protected
  68383. */
  68384. preUpdate: function () {
  68385. if (this.dirty && this.sprite)
  68386. {
  68387. this.bmd.clear();
  68388. this.bmd.draw(this.canvas, 0, 0);
  68389. this.context.clearRect(0, 0, this.game.width, this.game.height);
  68390. this.dirty = false;
  68391. }
  68392. },
  68393. /**
  68394. * Clears the Debug canvas.
  68395. *
  68396. * @method Phaser.Utils.Debug#reset
  68397. */
  68398. reset: function () {
  68399. if (this.context)
  68400. {
  68401. this.context.clearRect(0, 0, this.game.width, this.game.height);
  68402. }
  68403. if (this.sprite)
  68404. {
  68405. this.bmd.clear();
  68406. }
  68407. },
  68408. /**
  68409. * Internal method that resets and starts the debug output values.
  68410. *
  68411. * @method Phaser.Utils.Debug#start
  68412. * @protected
  68413. * @param {number} [x=0] - The X value the debug info will start from.
  68414. * @param {number} [y=0] - The Y value the debug info will start from.
  68415. * @param {string} [color='rgb(255,255,255)'] - The color the debug text will drawn in.
  68416. * @param {number} [columnWidth=0] - The spacing between columns.
  68417. */
  68418. start: function (x, y, color, columnWidth) {
  68419. if (typeof x !== 'number') { x = 0; }
  68420. if (typeof y !== 'number') { y = 0; }
  68421. color = color || 'rgb(255,255,255)';
  68422. if (columnWidth === undefined) { columnWidth = 0; }
  68423. this.currentX = x;
  68424. this.currentY = y;
  68425. this.currentColor = color;
  68426. this.columnWidth = columnWidth;
  68427. this.dirty = true;
  68428. this.context.save();
  68429. this.context.setTransform(1, 0, 0, 1, 0, 0);
  68430. this.context.strokeStyle = color;
  68431. this.context.fillStyle = color;
  68432. this.context.font = this.font;
  68433. this.context.globalAlpha = this.currentAlpha;
  68434. },
  68435. /**
  68436. * Internal method that stops the debug output.
  68437. *
  68438. * @method Phaser.Utils.Debug#stop
  68439. * @protected
  68440. */
  68441. stop: function () {
  68442. this.context.restore();
  68443. },
  68444. /**
  68445. * Internal method that outputs a single line of text split over as many columns as needed, one per parameter.
  68446. *
  68447. * @method Phaser.Utils.Debug#line
  68448. * @protected
  68449. */
  68450. line: function () {
  68451. var x = this.currentX;
  68452. for (var i = 0; i < arguments.length; i++)
  68453. {
  68454. if (this.renderShadow)
  68455. {
  68456. this.context.fillStyle = 'rgb(0,0,0)';
  68457. this.context.fillText(arguments[i], x + 1, this.currentY + 1);
  68458. this.context.fillStyle = this.currentColor;
  68459. }
  68460. this.context.fillText(arguments[i], x, this.currentY);
  68461. x += this.columnWidth;
  68462. }
  68463. this.currentY += this.lineHeight;
  68464. },
  68465. /**
  68466. * Render Sound information, including decoded state, duration, volume and more.
  68467. *
  68468. * @method Phaser.Utils.Debug#soundInfo
  68469. * @param {Phaser.Sound} sound - The sound object to debug.
  68470. * @param {number} x - X position of the debug info to be rendered.
  68471. * @param {number} y - Y position of the debug info to be rendered.
  68472. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68473. */
  68474. soundInfo: function (sound, x, y, color) {
  68475. this.start(x, y, color);
  68476. this.line('Sound: ' + sound.key + ' Locked: ' + sound.game.sound.touchLocked);
  68477. this.line('Is Ready?: ' + this.game.cache.isSoundReady(sound.key) + ' Pending Playback: ' + sound.pendingPlayback);
  68478. this.line('Decoded: ' + sound.isDecoded + ' Decoding: ' + sound.isDecoding);
  68479. this.line('Total Duration: ' + sound.totalDuration + ' Playing: ' + sound.isPlaying);
  68480. this.line('Time: ' + sound.currentTime);
  68481. this.line('Volume: ' + sound.volume + ' Muted: ' + sound.mute);
  68482. this.line('WebAudio: ' + sound.usingWebAudio + ' Audio: ' + sound.usingAudioTag);
  68483. if (sound.currentMarker !== '')
  68484. {
  68485. this.line('Marker: ' + sound.currentMarker + ' Duration: ' + sound.duration + ' (ms: ' + sound.durationMS + ')');
  68486. this.line('Start: ' + sound.markers[sound.currentMarker].start + ' Stop: ' + sound.markers[sound.currentMarker].stop);
  68487. this.line('Position: ' + sound.position);
  68488. }
  68489. this.stop();
  68490. },
  68491. /**
  68492. * Marks the follow {@link #target} and {@link #deadzone}.
  68493. *
  68494. * @method Phaser.Utils.Debug#camera
  68495. * @param {Phaser.Camera} camera - The Phaser.Camera to show the debug information for.
  68496. * @param {string} [color] - Color of the debug shapes to be rendered (format is css color string).
  68497. * @param {boolean} [filled=true] - Render the shapes filled (default, true) or stroked (false).
  68498. */
  68499. camera: function (camera, color, filled) {
  68500. var deadzone = camera.deadzone;
  68501. var target = camera.target;
  68502. var view = camera.view;
  68503. if (deadzone)
  68504. {
  68505. this._rect.setTo(view.x + deadzone.x, view.y + deadzone.y, deadzone.width, deadzone.height);
  68506. this.rectangle(this._rect, color, filled);
  68507. }
  68508. if (target)
  68509. {
  68510. this._line.setTo(view.centerX, view.centerY, target.x, target.y);
  68511. this.geom(this._line, color, filled);
  68512. this.geom(target, color, false, 3);
  68513. }
  68514. },
  68515. /**
  68516. * Render camera information including dimensions and location.
  68517. *
  68518. * @method Phaser.Utils.Debug#cameraInfo
  68519. * @param {Phaser.Camera} camera - The Phaser.Camera to show the debug information for.
  68520. * @param {number} x - X position of the debug info to be rendered.
  68521. * @param {number} y - Y position of the debug info to be rendered.
  68522. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68523. */
  68524. cameraInfo: function (camera, x, y, color) {
  68525. var bounds = camera.bounds;
  68526. var deadzone = camera.deadzone;
  68527. var target = camera.target;
  68528. var view = camera.view;
  68529. this.start(x, y, color);
  68530. this.line('Camera (' + camera.width + ' x ' + camera.height + ')');
  68531. this.line('x: ' + camera.x + ' y: ' + camera.y);
  68532. if (bounds)
  68533. {
  68534. this.line('Bounds x: ' + bounds.x + ' y: ' + bounds.y + ' w: ' + bounds.width + ' h: ' + bounds.height);
  68535. }
  68536. this.line('View x: ' + view.x + ' y: ' + view.y + ' w: ' + view.width + ' h: ' + view.height);
  68537. this.line('Deadzone: ' + (deadzone ? ('x: ' + deadzone.x + ' y: ' + deadzone.y + ' w: ' + deadzone.width + ' h: ' + deadzone.height) : deadzone));
  68538. this.line('Total in view: ' + camera.totalInView);
  68539. this.line('At limit: x: ' + camera.atLimit.x + ' y: ' + camera.atLimit.y);
  68540. this.line('Target: ' + (target ? (target.name || target) : target));
  68541. this.stop();
  68542. },
  68543. /**
  68544. * Render Timer information.
  68545. *
  68546. * @method Phaser.Utils.Debug#timer
  68547. * @param {Phaser.Timer} timer - The Phaser.Timer to show the debug information for.
  68548. * @param {number} x - X position of the debug info to be rendered.
  68549. * @param {number} y - Y position of the debug info to be rendered.
  68550. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68551. */
  68552. timer: function (timer, x, y, color) {
  68553. this.start(x, y, color);
  68554. this.line('Timer (running: ' + timer.running + ' expired: ' + timer.expired + ')');
  68555. this.line('Next Tick: ' + timer.next + ' Duration: ' + timer.duration);
  68556. this.line('Paused: ' + timer.paused + ' Length: ' + timer.length);
  68557. this.stop();
  68558. },
  68559. /**
  68560. * Renders the Pointer.circle object onto the stage in green if down or red if up along with debug text.
  68561. *
  68562. * @method Phaser.Utils.Debug#pointer
  68563. * @param {Phaser.Pointer} pointer - The Pointer you wish to display.
  68564. * @param {boolean} [hideIfUp=false] - Doesn't render the circle if the pointer is up.
  68565. * @param {string} [downColor='rgba(0,255,0,0.5)'] - The color the circle is rendered in if down.
  68566. * @param {string} [upColor='rgba(255,0,0,0.5)'] - The color the circle is rendered in if up (and hideIfUp is false).
  68567. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68568. */
  68569. pointer: function (pointer, hideIfUp, downColor, upColor, color) {
  68570. if (pointer == null)
  68571. {
  68572. return;
  68573. }
  68574. if (hideIfUp === undefined) { hideIfUp = false; }
  68575. downColor = downColor || 'rgba(0,255,0,0.5)';
  68576. upColor = upColor || 'rgba(255,0,0,0.5)';
  68577. if (hideIfUp === true && pointer.isUp === true)
  68578. {
  68579. return;
  68580. }
  68581. this.start(pointer.x, pointer.y - 100, color);
  68582. this.context.beginPath();
  68583. this.context.arc(pointer.x, pointer.y, pointer.circle.radius, 0, Math.PI * 2);
  68584. if (pointer.active)
  68585. {
  68586. this.context.fillStyle = downColor;
  68587. }
  68588. else
  68589. {
  68590. this.context.fillStyle = upColor;
  68591. }
  68592. this.context.fill();
  68593. this.context.closePath();
  68594. // Render the points
  68595. this.context.beginPath();
  68596. this.context.moveTo(pointer.positionDown.x, pointer.positionDown.y);
  68597. this.context.lineTo(pointer.position.x, pointer.position.y);
  68598. this.context.lineWidth = 2;
  68599. this.context.stroke();
  68600. this.context.closePath();
  68601. // Render the text
  68602. this.line('ID: ' + pointer.id + " Active: " + pointer.active);
  68603. this.line('World X: ' + pointer.worldX + " World Y: " + pointer.worldY);
  68604. this.line('Screen X: ' + pointer.x + " Screen Y: " + pointer.y + " In: " + pointer.withinGame);
  68605. this.line('Duration: ' + pointer.duration + " ms");
  68606. this.line('is Down: ' + pointer.isDown + " is Up: " + pointer.isUp);
  68607. this.stop();
  68608. },
  68609. /**
  68610. * Render Sprite Input Debug information.
  68611. *
  68612. * @method Phaser.Utils.Debug#spriteInputInfo
  68613. * @param {Phaser.Sprite|Phaser.Image} sprite - The sprite to display the input data for.
  68614. * @param {number} x - X position of the debug info to be rendered.
  68615. * @param {number} y - Y position of the debug info to be rendered.
  68616. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68617. */
  68618. spriteInputInfo: function (sprite, x, y, color) {
  68619. this.start(x, y, color);
  68620. this.line('Sprite Input: (' + sprite.width + ' x ' + sprite.height + ')');
  68621. this.line('x: ' + sprite.input.pointerX().toFixed(1) + ' y: ' + sprite.input.pointerY().toFixed(1));
  68622. this.line('over: ' + sprite.input.pointerOver() + ' duration: ' + sprite.input.overDuration().toFixed(0));
  68623. this.line('down: ' + sprite.input.pointerDown() + ' duration: ' + sprite.input.downDuration().toFixed(0));
  68624. this.line('just over: ' + sprite.input.justOver() + ' just out: ' + sprite.input.justOut());
  68625. this.stop();
  68626. },
  68627. /**
  68628. * Renders Phaser.Key object information.
  68629. *
  68630. * @method Phaser.Utils.Debug#key
  68631. * @param {Phaser.Key} key - The Key to render the information for.
  68632. * @param {number} x - X position of the debug info to be rendered.
  68633. * @param {number} y - Y position of the debug info to be rendered.
  68634. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68635. */
  68636. key: function (key, x, y, color) {
  68637. this.start(x, y, color, 150);
  68638. this.line('Key:', key.keyCode, 'isDown:', key.isDown);
  68639. this.line('justDown:', key.justDown, 'justUp:', key.justUp);
  68640. this.line('Time Down:', key.timeDown.toFixed(0), 'duration:', key.duration.toFixed(0));
  68641. this.stop();
  68642. },
  68643. /**
  68644. * Render debug information about the Input object.
  68645. *
  68646. * @method Phaser.Utils.Debug#inputInfo
  68647. * @param {number} x - X position of the debug info to be rendered.
  68648. * @param {number} y - Y position of the debug info to be rendered.
  68649. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68650. */
  68651. inputInfo: function (x, y, color) {
  68652. this.start(x, y, color);
  68653. this.line('Input');
  68654. this.line('X: ' + this.game.input.x + ' Y: ' + this.game.input.y);
  68655. this.line('World X: ' + this.game.input.worldX + ' World Y: ' + this.game.input.worldY);
  68656. this.line('Scale X: ' + this.game.input.scale.x.toFixed(1) + ' Scale Y: ' + this.game.input.scale.x.toFixed(1));
  68657. this.line('Screen X: ' + this.game.input.activePointer.screenX + ' Screen Y: ' + this.game.input.activePointer.screenY);
  68658. this.stop();
  68659. },
  68660. /**
  68661. * Renders the Sprites bounds. Note: This is really expensive as it has to calculate the bounds every time you call it!
  68662. *
  68663. * @method Phaser.Utils.Debug#spriteBounds
  68664. * @param {Phaser.Sprite|Phaser.Image} sprite - The sprite to display the bounds of.
  68665. * @param {string} [color] - Color of the debug info to be rendered (format is css color string).
  68666. * @param {boolean} [filled=true] - Render the rectangle as a fillRect (default, true) or a strokeRect (false)
  68667. */
  68668. spriteBounds: function (sprite, color, filled) {
  68669. var bounds = sprite.getBounds();
  68670. bounds.x += this.game.camera.x;
  68671. bounds.y += this.game.camera.y;
  68672. this.rectangle(bounds, color, filled);
  68673. },
  68674. /**
  68675. * Renders the Rope's segments. Note: This is really expensive as it has to calculate new segments every time you call it
  68676. *
  68677. * @method Phaser.Utils.Debug#ropeSegments
  68678. * @param {Phaser.Rope} rope - The rope to display the segments of.
  68679. * @param {string} [color] - Color of the debug info to be rendered (format is css color string).
  68680. * @param {boolean} [filled=true] - Render the rectangle as a fillRect (default, true) or a strokeRect (false)
  68681. */
  68682. ropeSegments: function (rope, color, filled) {
  68683. var segments = rope.segments;
  68684. var self = this;
  68685. segments.forEach(function(segment) {
  68686. self.rectangle(segment, color, filled);
  68687. }, this);
  68688. },
  68689. /**
  68690. * Render debug infos (including name, bounds info, position and some other properties) about the Sprite.
  68691. *
  68692. * @method Phaser.Utils.Debug#spriteInfo
  68693. * @param {Phaser.Sprite} sprite - The Sprite to display the information of.
  68694. * @param {number} x - X position of the debug info to be rendered.
  68695. * @param {number} y - Y position of the debug info to be rendered.
  68696. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68697. */
  68698. spriteInfo: function (sprite, x, y, color) {
  68699. this.start(x, y, color);
  68700. this.line('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ') anchor: ' + sprite.anchor.x + ' x ' + sprite.anchor.y);
  68701. this.line('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1));
  68702. this.line('angle: ' + sprite.angle.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1));
  68703. this.line('visible: ' + sprite.visible + ' in camera: ' + sprite.inCamera);
  68704. this.line('bounds x: ' + sprite._bounds.x.toFixed(1) + ' y: ' + sprite._bounds.y.toFixed(1) + ' w: ' + sprite._bounds.width.toFixed(1) + ' h: ' + sprite._bounds.height.toFixed(1));
  68705. this.stop();
  68706. },
  68707. /**
  68708. * Renders the sprite coordinates in local, positional and world space.
  68709. *
  68710. * @method Phaser.Utils.Debug#spriteCoords
  68711. * @param {Phaser.Sprite|Phaser.Image} sprite - The sprite to display the coordinates for.
  68712. * @param {number} x - X position of the debug info to be rendered.
  68713. * @param {number} y - Y position of the debug info to be rendered.
  68714. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68715. */
  68716. spriteCoords: function (sprite, x, y, color) {
  68717. this.start(x, y, color, 100);
  68718. if (sprite.name)
  68719. {
  68720. this.line(sprite.name);
  68721. }
  68722. this.line('x:', sprite.x.toFixed(2), 'y:', sprite.y.toFixed(2));
  68723. this.line('pos x:', sprite.position.x.toFixed(2), 'pos y:', sprite.position.y.toFixed(2));
  68724. this.line('world x:', sprite.world.x.toFixed(2), 'world y:', sprite.world.y.toFixed(2));
  68725. this.stop();
  68726. },
  68727. /**
  68728. * Renders Line information in the given color.
  68729. *
  68730. * @method Phaser.Utils.Debug#lineInfo
  68731. * @param {Phaser.Line} line - The Line to display the data for.
  68732. * @param {number} x - X position of the debug info to be rendered.
  68733. * @param {number} y - Y position of the debug info to be rendered.
  68734. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68735. */
  68736. lineInfo: function (line, x, y, color) {
  68737. this.start(x, y, color, 80);
  68738. this.line('start.x:', line.start.x.toFixed(2), 'start.y:', line.start.y.toFixed(2));
  68739. this.line('end.x:', line.end.x.toFixed(2), 'end.y:', line.end.y.toFixed(2));
  68740. this.line('length:', line.length.toFixed(2), 'angle:', line.angle);
  68741. this.stop();
  68742. },
  68743. /**
  68744. * Renders a single pixel at the given size.
  68745. *
  68746. * @method Phaser.Utils.Debug#pixel
  68747. * @param {number} x - X position of the pixel to be rendered.
  68748. * @param {number} y - Y position of the pixel to be rendered.
  68749. * @param {string} [color] - Color of the pixel (format is css color string).
  68750. * @param {number} [size=2] - The 'size' to render the pixel at.
  68751. */
  68752. pixel: function (x, y, color, size) {
  68753. size = size || 2;
  68754. this.start();
  68755. this.context.fillStyle = color;
  68756. this.context.fillRect(x, y, size, size);
  68757. this.stop();
  68758. },
  68759. /**
  68760. * Renders a Phaser geometry object including Rectangle, Circle, Ellipse, Point or Line.
  68761. *
  68762. * @method Phaser.Utils.Debug#geom
  68763. * @param {Phaser.Rectangle|Phaser.Circle|Phaser.Ellipse|Phaser.Point|Phaser.Line} object - The geometry object to render.
  68764. * @param {string} [color] - Color of the debug info to be rendered (format is css color string).
  68765. * @param {boolean} [filled=true] - Render the objected as a filled (default, true) or a stroked (false)
  68766. * @param {number} [forceType=0] - Force rendering of a specific type. If 0 no type will be forced, otherwise 1 = Rectangle, 2 = Circle,3 = Point, 4 = Line and 5 = Ellipse.
  68767. */
  68768. geom: function (object, color, filled, forceType) {
  68769. if (filled === undefined) { filled = true; }
  68770. if (forceType === undefined) { forceType = 0; }
  68771. color = color || 'rgba(0,255,0,0.4)';
  68772. this.start();
  68773. this.context.fillStyle = color;
  68774. this.context.strokeStyle = color;
  68775. this.context.lineWidth = this.lineWidth;
  68776. if (object instanceof Phaser.Rectangle || forceType === 1)
  68777. {
  68778. if (filled)
  68779. {
  68780. this.context.fillRect(object.x - this.game.camera.x, object.y - this.game.camera.y, object.width, object.height);
  68781. }
  68782. else
  68783. {
  68784. this.context.strokeRect(object.x - this.game.camera.x, object.y - this.game.camera.y, object.width, object.height);
  68785. }
  68786. }
  68787. else if (object instanceof Phaser.Circle || forceType === 2)
  68788. {
  68789. this.context.beginPath();
  68790. this.context.arc(object.x - this.game.camera.x, object.y - this.game.camera.y, object.radius, 0, Math.PI * 2, false);
  68791. this.context.closePath();
  68792. if (filled)
  68793. {
  68794. this.context.fill();
  68795. }
  68796. else
  68797. {
  68798. this.context.stroke();
  68799. }
  68800. }
  68801. else if (object instanceof Phaser.Point || forceType === 3)
  68802. {
  68803. this.context.fillRect(object.x - this.game.camera.x, object.y - this.game.camera.y, 4, 4);
  68804. }
  68805. else if (object instanceof Phaser.Line || forceType === 4)
  68806. {
  68807. this.context.beginPath();
  68808. this.context.moveTo((object.start.x + 0.5) - this.game.camera.x, (object.start.y + 0.5) - this.game.camera.y);
  68809. this.context.lineTo((object.end.x + 0.5) - this.game.camera.x, (object.end.y + 0.5) - this.game.camera.y);
  68810. this.context.closePath();
  68811. this.context.stroke();
  68812. }
  68813. else if (object instanceof Phaser.Ellipse || forceType === 5)
  68814. {
  68815. this.context.beginPath();
  68816. this.context.ellipse(object.x - this.game.camera.x, object.y - this.game.camera.y, object.width/2, object.height/2, 0,2 * Math.PI,false);
  68817. this.context.closePath();
  68818. if (filled)
  68819. {
  68820. this.context.fill();
  68821. }
  68822. else
  68823. {
  68824. this.context.stroke();
  68825. }
  68826. }
  68827. this.stop();
  68828. },
  68829. /**
  68830. * Renders a Rectangle.
  68831. *
  68832. * @method Phaser.Utils.Debug#rectangle
  68833. * @param {Phaser.Rectangle|object} object - The rectangle to render.
  68834. * @param {string} [color] - Color of the debug info to be rendered (format is css color string).
  68835. * @param {boolean} [filled=true] - Render the rectangle as filled (default, true) or a stroked (false)
  68836. */
  68837. rectangle: function (object, color, filled) {
  68838. if (filled === undefined) { filled = true; }
  68839. color = color || 'rgba(0, 255, 0, 0.4)';
  68840. this.start();
  68841. if (filled)
  68842. {
  68843. this.context.fillStyle = color;
  68844. this.context.fillRect(object.x - this.game.camera.x, object.y - this.game.camera.y, object.width, object.height);
  68845. }
  68846. else
  68847. {
  68848. this.context.lineWidth = this.lineWidth;
  68849. this.context.strokeStyle = color;
  68850. this.context.strokeRect(object.x - this.game.camera.x, object.y - this.game.camera.y, object.width, object.height);
  68851. }
  68852. this.stop();
  68853. },
  68854. /**
  68855. * Render a string of text.
  68856. *
  68857. * @method Phaser.Utils.Debug#text
  68858. * @param {string} text - The line of text to draw.
  68859. * @param {number} x - X position of the debug info to be rendered.
  68860. * @param {number} y - Y position of the debug info to be rendered.
  68861. * @param {string} [color] - Color of the debug info to be rendered (format is css color string).
  68862. * @param {string} [font] - The font of text to draw.
  68863. */
  68864. text: function (text, x, y, color, font) {
  68865. color = color || 'rgb(255,255,255)';
  68866. font = font || '16px Courier';
  68867. this.start();
  68868. this.context.font = font;
  68869. if (this.renderShadow)
  68870. {
  68871. this.context.fillStyle = 'rgb(0,0,0)';
  68872. this.context.fillText(text, x + 1, y + 1);
  68873. }
  68874. this.context.fillStyle = color;
  68875. this.context.fillText(text, x, y);
  68876. this.stop();
  68877. },
  68878. /**
  68879. * Visually renders a QuadTree to the display.
  68880. *
  68881. * @method Phaser.Utils.Debug#quadTree
  68882. * @param {Phaser.QuadTree} quadtree - The quadtree to render.
  68883. * @param {string} color - The color of the lines in the quadtree.
  68884. */
  68885. quadTree: function (quadtree, color) {
  68886. color = color || 'rgba(255,0,0,0.3)';
  68887. this.start();
  68888. var bounds = quadtree.bounds;
  68889. if (quadtree.nodes.length === 0)
  68890. {
  68891. this.context.strokeStyle = color;
  68892. this.context.strokeRect(bounds.x, bounds.y, bounds.width, bounds.height);
  68893. this.text('size: ' + quadtree.objects.length, bounds.x + 4, bounds.y + 16, 'rgb(0,200,0)', '12px Courier');
  68894. this.context.strokeStyle = 'rgb(0,255,0)';
  68895. for (var i = 0; i < quadtree.objects.length; i++)
  68896. {
  68897. this.context.strokeRect(quadtree.objects[i].x, quadtree.objects[i].y, quadtree.objects[i].width, quadtree.objects[i].height);
  68898. }
  68899. }
  68900. else
  68901. {
  68902. for (var i = 0; i < quadtree.nodes.length; i++)
  68903. {
  68904. this.quadTree(quadtree.nodes[i]);
  68905. }
  68906. }
  68907. this.stop();
  68908. },
  68909. /**
  68910. * Render a Sprites Physics body if it has one set. The body is rendered as a filled or stroked rectangle.
  68911. * This only works for Arcade Physics, Ninja Physics (AABB and Circle only) and Box2D Physics bodies.
  68912. * To display a P2 Physics body you should enable debug mode on the body when creating it.
  68913. *
  68914. * @method Phaser.Utils.Debug#body
  68915. * @param {Phaser.Sprite} sprite - The Sprite who's body will be rendered.
  68916. * @param {string} [color='rgba(0,255,0,0.4)'] - Color of the debug rectangle to be rendered. The format is a CSS color string such as '#ff0000' or 'rgba(255,0,0,0.5)'.
  68917. * @param {boolean} [filled=true] - Render the body as a filled rectangle (true) or a stroked rectangle (false)
  68918. */
  68919. body: function (sprite, color, filled) {
  68920. if (sprite.body)
  68921. {
  68922. this.start();
  68923. if (sprite.body.type === Phaser.Physics.ARCADE)
  68924. {
  68925. Phaser.Physics.Arcade.Body.render(this.context, sprite.body, color, filled, this.lineWidth);
  68926. }
  68927. else if (sprite.body.type === Phaser.Physics.NINJA)
  68928. {
  68929. Phaser.Physics.Ninja.Body.render(this.context, sprite.body, color, filled);
  68930. }
  68931. else if (sprite.body.type === Phaser.Physics.BOX2D)
  68932. {
  68933. Phaser.Physics.Box2D.renderBody(this.context, sprite.body, color);
  68934. }
  68935. this.stop();
  68936. }
  68937. },
  68938. /**
  68939. * Render a Sprites Physic Body information.
  68940. *
  68941. * @method Phaser.Utils.Debug#bodyInfo
  68942. * @param {Phaser.Sprite} sprite - The sprite to be rendered.
  68943. * @param {number} x - X position of the debug info to be rendered.
  68944. * @param {number} y - Y position of the debug info to be rendered.
  68945. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  68946. */
  68947. bodyInfo: function (sprite, x, y, color) {
  68948. if (sprite.body)
  68949. {
  68950. this.start(x, y, color, 210);
  68951. if (sprite.body.type === Phaser.Physics.ARCADE)
  68952. {
  68953. Phaser.Physics.Arcade.Body.renderBodyInfo(this, sprite.body);
  68954. }
  68955. else if (sprite.body.type === Phaser.Physics.BOX2D)
  68956. {
  68957. this.game.physics.box2d.renderBodyInfo(this, sprite.body);
  68958. }
  68959. this.stop();
  68960. }
  68961. },
  68962. /**
  68963. * Renders 'debug draw' data for the Box2D world if it exists.
  68964. * This uses the standard debug drawing feature of Box2D, so colors will be decided by
  68965. * the Box2D engine.
  68966. *
  68967. * @method Phaser.Utils.Debug#box2dWorld
  68968. */
  68969. box2dWorld: function () {
  68970. this.start();
  68971. this.context.translate(-this.game.camera.view.x, -this.game.camera.view.y, 0);
  68972. this.game.physics.box2d.renderDebugDraw(this.context);
  68973. this.stop();
  68974. },
  68975. /**
  68976. * Renders 'debug draw' data for the given Box2D body.
  68977. * This uses the standard debug drawing feature of Box2D, so colors will be decided by the Box2D engine.
  68978. *
  68979. * @method Phaser.Utils.Debug#box2dBody
  68980. * @param {Phaser.Physics.Box2D.Body} body - The body to be rendered.
  68981. * @param {string} [color='rgb(0,255,0)'] - Color of the rendering (format is css color string).
  68982. */
  68983. box2dBody: function (body, color) {
  68984. this.start();
  68985. Phaser.Physics.Box2D.renderBody(this.context, body, color);
  68986. this.stop();
  68987. },
  68988. /**
  68989. * Call this function from the Dev Tools console.
  68990. *
  68991. * It will scan the display list and output all of the Objects it finds, and their renderOrderIDs.
  68992. *
  68993. * **Note** Requires a browser that supports console.group and console.groupEnd (such as Chrome)
  68994. *
  68995. * @method Phaser.Utils.Debug#displayList
  68996. * @param {Object} [displayObject] - The displayObject level display object to start from. Defaults to the World.
  68997. */
  68998. displayList: function (displayObject) {
  68999. if (displayObject === undefined) { displayObject = this.game.world; }
  69000. if (displayObject.hasOwnProperty('renderOrderID'))
  69001. {
  69002. console.log('[' + displayObject.renderOrderID + ']', displayObject);
  69003. }
  69004. else
  69005. {
  69006. console.log('[]', displayObject);
  69007. }
  69008. if (displayObject.children && displayObject.children.length > 0)
  69009. {
  69010. for (var i = 0; i < displayObject.children.length; i++)
  69011. {
  69012. this.game.debug.displayList(displayObject.children[i]);
  69013. }
  69014. }
  69015. },
  69016. /**
  69017. * Prints a description of the {@link Phaser.Game#renderer renderer} and render session.
  69018. *
  69019. * @method Phaser.Utils.Debug#renderer
  69020. * @param {number} [x=0] - The X value the debug info will start from.
  69021. * @param {number} [y=0] - The Y value the debug info will start from.
  69022. * @param {string} [color='rgb(255,255,255)'] - The color the debug text will drawn in.
  69023. */
  69024. renderer: function (x, y, color) {
  69025. var r = this.game.renderer;
  69026. var s = r.renderSession;
  69027. this.start(x, y, color);
  69028. this.line((r.gl ? 'WebGL' : 'Canvas') + ' Renderer (' + r.width + ' x ' + r.height + ')');
  69029. this.line('autoResize: ' + r.autoResize);
  69030. this.line('clearBeforeRender: ' + r.clearBeforeRender);
  69031. this.line('resolution: ' + r.resolution);
  69032. this.line('transparent: ' + r.transparent);
  69033. this.line('renderSession:');
  69034. if (r.gl)
  69035. {
  69036. this.line(' currentBatchedTextures: ('+ r.currentBatchedTextures.length + ')');
  69037. for (var i = 0; i < r.currentBatchedTextures.length; i++)
  69038. {
  69039. this.line(' ' + r.currentBatchedTextures[i]);
  69040. }
  69041. this.line(' drawCount: ' + s.drawCount);
  69042. this.line(' maxTextures: ' + r.maxTextures);
  69043. this.line(' maxTextureSize: ' + r.maxTextureSize);
  69044. this.line(' maxTextureAvailableSpace: ' + s.maxTextureAvailableSpace);
  69045. this.line(' roundPixels: ' + s.roundPixels);
  69046. }
  69047. else
  69048. {
  69049. this.line(' roundPixels: ' + s.roundPixels);
  69050. this.line(' scaleMode: ' + (s.scaleMode === 0 ? 'LINEAR' : (s.scaleMode === 1 ? 'NEAREST' : s.scaleMode)));
  69051. }
  69052. this.stop();
  69053. },
  69054. canvasPool: function (x, y, color, columnWidth) {
  69055. var pool = Phaser.CanvasPool;
  69056. this.start(x, y, color, columnWidth || 100);
  69057. this.line('Canvas Pool');
  69058. this.line('Used:', pool.getTotal());
  69059. this.line('Free:', pool.getFree());
  69060. this.line('Total:', pool.length);
  69061. this.stop();
  69062. },
  69063. /**
  69064. * Render each physics {@link #body} in a group.
  69065. *
  69066. * @method Phaser.Utils.Debug#physicsGroup
  69067. * @param {Phaser.Group} group - A group containing physics-enabled sprites.
  69068. * @param {string} [color='rgba(0,255,0,0.4)'] - Color of the debug rectangle to be rendered. The format is a CSS color string such as '#ff0000' or 'rgba(255,0,0,0.5)'.
  69069. * @param {boolean} [filled=true] - Render the body as a filled rectangle (true) or a stroked rectangle (false).
  69070. * @param {boolean} [checkExists=false] Render only children with `exists=true`.
  69071. */
  69072. physicsGroup: function (group, color, filled, checkExists) {
  69073. group.forEach(this.body, this, checkExists, color, filled);
  69074. },
  69075. /**
  69076. * Prints Phaser {@link Phaser.VERSION version}, {@link Phaser.Game.#renderType rendering mode}, and {@link Phaser.Device#webAudio device audio support}.
  69077. *
  69078. * @method Phaser.Utils.Debug#phaser
  69079. * @param {number} x - The X value the debug info will start from.
  69080. * @param {number} y - The Y value the debug info will start from.
  69081. * @param {string} [color='rgb(255,255,255)'] - The color the debug text will drawn in.
  69082. */
  69083. phaser: function (x, y, color) {
  69084. this.text('Phaser v' + Phaser.VERSION + ' ' +
  69085. (this.game.renderType === Phaser.WEBGL ? 'WebGL' : 'Canvas') + ' ' +
  69086. (this.game.device.webAudio ? 'WebAudio' : 'HTML Audio'),
  69087. x, y, color, this.font);
  69088. },
  69089. /**
  69090. * Destroy this object.
  69091. *
  69092. * @method Phaser.Utils.Debug#destroy
  69093. */
  69094. destroy: function () {
  69095. Phaser.CanvasPool.remove(this);
  69096. }
  69097. };
  69098. Phaser.Utils.Debug.prototype.constructor = Phaser.Utils.Debug;
  69099. /**
  69100. * @author Richard Davey <rich@photonstorm.com>
  69101. * @copyright 2016 Photon Storm Ltd.
  69102. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  69103. */
  69104. /**
  69105. * DOM utility class.
  69106. *
  69107. * Provides a useful Window and Element functions as well as cross-browser compatibility buffer.
  69108. *
  69109. * Some code originally derived from {@link https://github.com/ryanve/verge verge}.
  69110. * Some parts were inspired by the research of Ryan Van Etten, released under MIT License 2013.
  69111. *
  69112. * @class Phaser.DOM
  69113. * @static
  69114. */
  69115. Phaser.DOM = {
  69116. /**
  69117. * Get the [absolute] position of the element relative to the Document.
  69118. *
  69119. * The value may vary slightly as the page is scrolled due to rounding errors.
  69120. *
  69121. * @method Phaser.DOM.getOffset
  69122. * @param {DOMElement} element - The targeted element that we want to retrieve the offset.
  69123. * @param {Phaser.Point} [point] - The point we want to take the x/y values of the offset.
  69124. * @return {Phaser.Point} - A point objet with the offsetX and Y as its properties.
  69125. */
  69126. getOffset: function (element, point) {
  69127. point = point || new Phaser.Point();
  69128. var box = element.getBoundingClientRect();
  69129. var scrollTop = Phaser.DOM.scrollY;
  69130. var scrollLeft = Phaser.DOM.scrollX;
  69131. var clientTop = document.documentElement.clientTop;
  69132. var clientLeft = document.documentElement.clientLeft;
  69133. point.x = box.left + scrollLeft - clientLeft;
  69134. point.y = box.top + scrollTop - clientTop;
  69135. return point;
  69136. },
  69137. /**
  69138. * A cross-browser element.getBoundingClientRect method with optional cushion.
  69139. *
  69140. * Returns a plain object containing the properties `top/bottom/left/right/width/height` with respect to the top-left corner of the current viewport.
  69141. * Its properties match the native rectangle.
  69142. * The cushion parameter is an amount of pixels (+/-) to cushion the element.
  69143. * It adjusts the measurements such that it is possible to detect when an element is near the viewport.
  69144. *
  69145. * @method Phaser.DOM.getBounds
  69146. * @param {DOMElement|Object} element - The element or stack (uses first item) to get the bounds for.
  69147. * @param {number} [cushion] - A +/- pixel adjustment amount.
  69148. * @return {Object|boolean} A plain object containing the properties `top/bottom/left/right/width/height` or `false` if a non-valid element is given.
  69149. */
  69150. getBounds: function (element, cushion) {
  69151. if (cushion === undefined) { cushion = 0; }
  69152. element = element && !element.nodeType ? element[0] : element;
  69153. if (!element || element.nodeType !== 1)
  69154. {
  69155. return false;
  69156. }
  69157. else
  69158. {
  69159. return this.calibrate(element.getBoundingClientRect(), cushion);
  69160. }
  69161. },
  69162. /**
  69163. * Calibrates element coordinates for `inLayoutViewport` checks.
  69164. *
  69165. * @method Phaser.DOM.calibrate
  69166. * @private
  69167. * @param {object} coords - An object containing the following properties: `{top: number, right: number, bottom: number, left: number}`
  69168. * @param {number} [cushion] - A value to adjust the coordinates by.
  69169. * @return {object} The calibrated element coordinates
  69170. */
  69171. calibrate: function (coords, cushion) {
  69172. cushion = +cushion || 0;
  69173. var output = { width: 0, height: 0, left: 0, right: 0, top: 0, bottom: 0 };
  69174. output.width = (output.right = coords.right + cushion) - (output.left = coords.left - cushion);
  69175. output.height = (output.bottom = coords.bottom + cushion) - (output.top = coords.top - cushion);
  69176. return output;
  69177. },
  69178. /**
  69179. * Get the Visual viewport aspect ratio (or the aspect ratio of an object or element)
  69180. *
  69181. * @method Phaser.DOM.getAspectRatio
  69182. * @param {(DOMElement|Object)} [object=(visualViewport)] - The object to determine the aspect ratio for. Must have public `width` and `height` properties or methods.
  69183. * @return {number} The aspect ratio.
  69184. */
  69185. getAspectRatio: function (object) {
  69186. object = null == object ? this.visualBounds : 1 === object.nodeType ? this.getBounds(object) : object;
  69187. var w = object['width'];
  69188. var h = object['height'];
  69189. if (typeof w === 'function')
  69190. {
  69191. w = w.call(object);
  69192. }
  69193. if (typeof h === 'function')
  69194. {
  69195. h = h.call(object);
  69196. }
  69197. return w / h;
  69198. },
  69199. /**
  69200. * Tests if the given DOM element is within the Layout viewport.
  69201. *
  69202. * The optional cushion parameter allows you to specify a distance.
  69203. *
  69204. * inLayoutViewport(element, 100) is `true` if the element is in the viewport or 100px near it.
  69205. * inLayoutViewport(element, -100) is `true` if the element is in the viewport or at least 100px near it.
  69206. *
  69207. * @method Phaser.DOM.inLayoutViewport
  69208. * @param {DOMElement|Object} element - The DOM element to check. If no element is given it defaults to the Phaser game canvas.
  69209. * @param {number} [cushion] - The cushion allows you to specify a distance within which the element must be within the viewport.
  69210. * @return {boolean} True if the element is within the viewport, or within `cushion` distance from it.
  69211. */
  69212. inLayoutViewport: function (element, cushion) {
  69213. var r = this.getBounds(element, cushion);
  69214. return !!r && r.bottom >= 0 && r.right >= 0 && r.top <= this.layoutBounds.width && r.left <= this.layoutBounds.height;
  69215. },
  69216. /**
  69217. * Returns the device screen orientation.
  69218. *
  69219. * Orientation values: 'portrait-primary', 'landscape-primary', 'portrait-secondary', 'landscape-secondary'.
  69220. *
  69221. * Order of resolving:
  69222. * - Screen Orientation API, or variation of - Future track. Most desktop and mobile browsers.
  69223. * - Screen size ratio check - If fallback is 'screen', suited for desktops.
  69224. * - Viewport size ratio check - If fallback is 'viewport', suited for mobile.
  69225. * - window.orientation - If fallback is 'window.orientation', works iOS and probably most Android; non-recommended track.
  69226. * - Media query
  69227. * - Viewport size ratio check (probably only IE9 and legacy mobile gets here..)
  69228. *
  69229. * See
  69230. * - https://w3c.github.io/screen-orientation/ (conflicts with mozOrientation/msOrientation)
  69231. * - https://developer.mozilla.org/en-US/docs/Web/API/Screen.orientation (mozOrientation)
  69232. * - http://msdn.microsoft.com/en-us/library/ie/dn342934(v=vs.85).aspx
  69233. * - https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Testing_media_queries
  69234. * - http://stackoverflow.com/questions/4917664/detect-viewport-orientation
  69235. * - http://www.matthewgifford.com/blog/2011/12/22/a-misconception-about-window-orientation
  69236. *
  69237. * @method Phaser.DOM.getScreenOrientation
  69238. * @protected
  69239. * @param {string} [primaryFallback=(none)] - Specify 'screen', 'viewport', or 'window.orientation'.
  69240. */
  69241. getScreenOrientation: function (primaryFallback) {
  69242. var screen = window.screen;
  69243. var orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
  69244. if (orientation && typeof orientation.type === 'string')
  69245. {
  69246. // Screen Orientation API specification
  69247. return orientation.type;
  69248. }
  69249. else if (typeof orientation === 'string')
  69250. {
  69251. // moz/ms-orientation are strings
  69252. return orientation;
  69253. }
  69254. var PORTRAIT = 'portrait-primary';
  69255. var LANDSCAPE = 'landscape-primary';
  69256. if (primaryFallback === 'screen')
  69257. {
  69258. return (screen.height > screen.width) ? PORTRAIT : LANDSCAPE;
  69259. }
  69260. else if (primaryFallback === 'viewport')
  69261. {
  69262. return (this.visualBounds.height > this.visualBounds.width) ? PORTRAIT : LANDSCAPE;
  69263. }
  69264. else if (primaryFallback === 'window.orientation' && typeof window.orientation === 'number')
  69265. {
  69266. // This may change by device based on "natural" orientation.
  69267. return (window.orientation === 0 || window.orientation === 180) ? PORTRAIT : LANDSCAPE;
  69268. }
  69269. else if (window.matchMedia)
  69270. {
  69271. if (window.matchMedia("(orientation: portrait)").matches)
  69272. {
  69273. return PORTRAIT;
  69274. }
  69275. else if (window.matchMedia("(orientation: landscape)").matches)
  69276. {
  69277. return LANDSCAPE;
  69278. }
  69279. }
  69280. return (this.visualBounds.height > this.visualBounds.width) ? PORTRAIT : LANDSCAPE;
  69281. },
  69282. /**
  69283. * The bounds of the Visual viewport, as discussed in
  69284. * {@link http://www.quirksmode.org/mobile/viewports.html A tale of two viewports — part one}
  69285. * with one difference: the viewport size _excludes_ scrollbars, as found on some desktop browsers.
  69286. *
  69287. * Supported mobile:
  69288. * iOS/Safari, Android 4, IE10, Firefox OS (maybe not Firefox Android), Opera Mobile 16
  69289. *
  69290. * The properties change dynamically.
  69291. *
  69292. * @type {Phaser.Rectangle}
  69293. * @property {number} x - Scroll, left offset - eg. "scrollX"
  69294. * @property {number} y - Scroll, top offset - eg. "scrollY"
  69295. * @property {number} width - Viewport width in pixels.
  69296. * @property {number} height - Viewport height in pixels.
  69297. * @readonly
  69298. */
  69299. visualBounds: new Phaser.Rectangle(),
  69300. /**
  69301. * The bounds of the Layout viewport, as discussed in
  69302. * {@link http://www.quirksmode.org/mobile/viewports2.html A tale of two viewports — part two};
  69303. * but honoring the constraints as specified applicable viewport meta-tag.
  69304. *
  69305. * The bounds returned are not guaranteed to be fully aligned with CSS media queries (see
  69306. * {@link http://www.matanich.com/2013/01/07/viewport-size/ What size is my viewport?}).
  69307. *
  69308. * This is _not_ representative of the Visual bounds: in particular the non-primary axis will
  69309. * generally be significantly larger than the screen height on mobile devices when running with a
  69310. * constrained viewport.
  69311. *
  69312. * The properties change dynamically.
  69313. *
  69314. * @type {Phaser.Rectangle}
  69315. * @property {number} width - Viewport width in pixels.
  69316. * @property {number} height - Viewport height in pixels.
  69317. * @readonly
  69318. */
  69319. layoutBounds: new Phaser.Rectangle(),
  69320. /**
  69321. * The size of the document / Layout viewport.
  69322. *
  69323. * This incorrectly reports the dimensions in IE.
  69324. *
  69325. * The properties change dynamically.
  69326. *
  69327. * @type {Phaser.Rectangle}
  69328. * @property {number} width - Document width in pixels.
  69329. * @property {number} height - Document height in pixels.
  69330. * @readonly
  69331. */
  69332. documentBounds: new Phaser.Rectangle()
  69333. };
  69334. Phaser.Device.whenReady(function (device) {
  69335. // All target browsers should support page[XY]Offset.
  69336. var scrollX = window && ('pageXOffset' in window) ?
  69337. function () { return window.pageXOffset; } :
  69338. function () { return document.documentElement.scrollLeft; };
  69339. var scrollY = window && ('pageYOffset' in window) ?
  69340. function () { return window.pageYOffset; } :
  69341. function () { return document.documentElement.scrollTop; };
  69342. /**
  69343. * A cross-browser window.scrollX.
  69344. *
  69345. * @name Phaser.DOM.scrollX
  69346. * @property {number} scrollX
  69347. * @readonly
  69348. * @protected
  69349. */
  69350. Object.defineProperty(Phaser.DOM, "scrollX", {
  69351. get: scrollX
  69352. });
  69353. /**
  69354. * A cross-browser window.scrollY.
  69355. *
  69356. * @name Phaser.DOM.scrollY
  69357. * @property {number} scrollY
  69358. * @readonly
  69359. * @protected
  69360. */
  69361. Object.defineProperty(Phaser.DOM, "scrollY", {
  69362. get: scrollY
  69363. });
  69364. Object.defineProperty(Phaser.DOM.visualBounds, "x", {
  69365. get: scrollX
  69366. });
  69367. Object.defineProperty(Phaser.DOM.visualBounds, "y", {
  69368. get: scrollY
  69369. });
  69370. Object.defineProperty(Phaser.DOM.layoutBounds, "x", {
  69371. value: 0
  69372. });
  69373. Object.defineProperty(Phaser.DOM.layoutBounds, "y", {
  69374. value: 0
  69375. });
  69376. var treatAsDesktop = device.desktop &&
  69377. (document.documentElement.clientWidth <= window.innerWidth) &&
  69378. (document.documentElement.clientHeight <= window.innerHeight);
  69379. // Desktop browsers align the layout viewport with the visual viewport.
  69380. // This differs from mobile browsers with their zooming design.
  69381. // Ref. http://quirksmode.org/mobile/tableViewport.html
  69382. if (treatAsDesktop)
  69383. {
  69384. // PST- When scrollbars are not included this causes upstream issues in ScaleManager.
  69385. // So reverted to the old "include scrollbars."
  69386. var clientWidth = function () {
  69387. return Math.max(window.innerWidth, document.documentElement.clientWidth);
  69388. };
  69389. var clientHeight = function () {
  69390. return Math.max(window.innerHeight, document.documentElement.clientHeight);
  69391. };
  69392. // Interested in area sans-scrollbar
  69393. Object.defineProperty(Phaser.DOM.visualBounds, "width", {
  69394. get: clientWidth
  69395. });
  69396. Object.defineProperty(Phaser.DOM.visualBounds, "height", {
  69397. get: clientHeight
  69398. });
  69399. Object.defineProperty(Phaser.DOM.layoutBounds, "width", {
  69400. get: clientWidth
  69401. });
  69402. Object.defineProperty(Phaser.DOM.layoutBounds, "height", {
  69403. get: clientHeight
  69404. });
  69405. } else {
  69406. Object.defineProperty(Phaser.DOM.visualBounds, "width", {
  69407. get: function () {
  69408. return window.innerWidth;
  69409. }
  69410. });
  69411. Object.defineProperty(Phaser.DOM.visualBounds, "height", {
  69412. get: function () {
  69413. return window.innerHeight;
  69414. }
  69415. });
  69416. Object.defineProperty(Phaser.DOM.layoutBounds, "width", {
  69417. get: function () {
  69418. var a = document.documentElement.clientWidth;
  69419. var b = window.innerWidth;
  69420. return a < b ? b : a; // max
  69421. }
  69422. });
  69423. Object.defineProperty(Phaser.DOM.layoutBounds, "height", {
  69424. get: function () {
  69425. var a = document.documentElement.clientHeight;
  69426. var b = window.innerHeight;
  69427. return a < b ? b : a; // max
  69428. }
  69429. });
  69430. }
  69431. // For Phaser.DOM.documentBounds
  69432. // Ref. http://www.quirksmode.org/mobile/tableViewport_desktop.html
  69433. Object.defineProperty(Phaser.DOM.documentBounds, "x", {
  69434. value: 0
  69435. });
  69436. Object.defineProperty(Phaser.DOM.documentBounds, "y", {
  69437. value: 0
  69438. });
  69439. Object.defineProperty(Phaser.DOM.documentBounds, "width", {
  69440. get: function () {
  69441. var d = document.documentElement;
  69442. return Math.max(d.clientWidth, d.offsetWidth, d.scrollWidth);
  69443. }
  69444. });
  69445. Object.defineProperty(Phaser.DOM.documentBounds, "height", {
  69446. get: function () {
  69447. var d = document.documentElement;
  69448. return Math.max(d.clientHeight, d.offsetHeight, d.scrollHeight);
  69449. }
  69450. });
  69451. }, null, true);
  69452. /**
  69453. * @author Richard Davey <rich@photonstorm.com>
  69454. * @copyright 2016 Photon Storm Ltd.
  69455. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  69456. */
  69457. /**
  69458. * ArraySet is a Set data structure (items must be unique within the set) that also maintains order.
  69459. * This allows specific items to be easily added or removed from the Set.
  69460. *
  69461. * Item equality (and uniqueness) is determined by the behavior of `Array.indexOf`.
  69462. *
  69463. * This used primarily by the Input subsystem.
  69464. *
  69465. * @class Phaser.ArraySet
  69466. * @constructor
  69467. * @param {any[]} [list=(new array)] - The backing array: if specified the items in the list _must_ be unique, per `Array.indexOf`, and the ownership of the array _should_ be relinquished to the ArraySet.
  69468. */
  69469. Phaser.ArraySet = function (list) {
  69470. /**
  69471. * Current cursor position as established by `first` and `next`.
  69472. * @property {integer} position
  69473. * @default
  69474. */
  69475. this.position = 0;
  69476. /**
  69477. * The backing array.
  69478. * @property {any[]} list
  69479. */
  69480. this.list = list || [];
  69481. };
  69482. Phaser.ArraySet.prototype = {
  69483. /**
  69484. * Adds a new element to the end of the list.
  69485. * If the item already exists in the list it is not moved.
  69486. *
  69487. * @method Phaser.ArraySet#add
  69488. * @param {any} item - The element to add to this list.
  69489. * @return {any} The item that was added.
  69490. */
  69491. add: function (item) {
  69492. if (!this.exists(item))
  69493. {
  69494. this.list.push(item);
  69495. }
  69496. return item;
  69497. },
  69498. /**
  69499. * Gets the index of the item in the list, or -1 if it isn't in the list.
  69500. *
  69501. * @method Phaser.ArraySet#getIndex
  69502. * @param {any} item - The element to get the list index for.
  69503. * @return {integer} The index of the item or -1 if not found.
  69504. */
  69505. getIndex: function (item) {
  69506. return this.list.indexOf(item);
  69507. },
  69508. /**
  69509. * Gets an item from the set based on the property strictly equaling the value given.
  69510. * Returns null if not found.
  69511. *
  69512. * @method Phaser.ArraySet#getByKey
  69513. * @param {string} property - The property to check against the value.
  69514. * @param {any} value - The value to check if the property strictly equals.
  69515. * @return {any} The item that was found, or null if nothing matched.
  69516. */
  69517. getByKey: function (property, value) {
  69518. var i = this.list.length;
  69519. while (i--)
  69520. {
  69521. if (this.list[i][property] === value)
  69522. {
  69523. return this.list[i];
  69524. }
  69525. }
  69526. return null;
  69527. },
  69528. /**
  69529. * Checks for the item within this list.
  69530. *
  69531. * @method Phaser.ArraySet#exists
  69532. * @param {any} item - The element to get the list index for.
  69533. * @return {boolean} True if the item is found in the list, otherwise false.
  69534. */
  69535. exists: function (item) {
  69536. return (this.list.indexOf(item) > -1);
  69537. },
  69538. /**
  69539. * Removes all the items.
  69540. *
  69541. * @method Phaser.ArraySet#reset
  69542. */
  69543. reset: function () {
  69544. this.list.length = 0;
  69545. },
  69546. /**
  69547. * Removes the given element from this list if it exists.
  69548. *
  69549. * @method Phaser.ArraySet#remove
  69550. * @param {any} item - The item to be removed from the list.
  69551. * @return {any} item - The item that was removed.
  69552. */
  69553. remove: function (item) {
  69554. var idx = this.list.indexOf(item);
  69555. if (idx > -1)
  69556. {
  69557. this.list.splice(idx, 1);
  69558. return item;
  69559. }
  69560. },
  69561. /**
  69562. * Sets the property `key` to the given value on all members of this list.
  69563. *
  69564. * @method Phaser.ArraySet#setAll
  69565. * @param {any} key - The property of the item to set.
  69566. * @param {any} value - The value to set the property to.
  69567. */
  69568. setAll: function (key, value) {
  69569. var i = this.list.length;
  69570. while (i--)
  69571. {
  69572. if (this.list[i])
  69573. {
  69574. this.list[i][key] = value;
  69575. }
  69576. }
  69577. },
  69578. /**
  69579. * Calls a function on all members of this list, using the member as the context for the callback.
  69580. *
  69581. * If the `key` property is present it must be a function.
  69582. * The function is invoked using the item as the context.
  69583. *
  69584. * @method Phaser.ArraySet#callAll
  69585. * @param {string} key - The name of the property with the function to call.
  69586. * @param {...*} parameter - Additional parameters that will be passed to the callback.
  69587. */
  69588. callAll: function (key) {
  69589. var args = Array.prototype.slice.call(arguments, 1);
  69590. var i = this.list.length;
  69591. while (i--)
  69592. {
  69593. if (this.list[i] && this.list[i][key])
  69594. {
  69595. this.list[i][key].apply(this.list[i], args);
  69596. }
  69597. }
  69598. },
  69599. /**
  69600. * Removes every member from this ArraySet and optionally destroys it.
  69601. *
  69602. * @method Phaser.ArraySet#removeAll
  69603. * @param {boolean} [destroy=false] - Call `destroy` on each member as it's removed from this set.
  69604. */
  69605. removeAll: function (destroy) {
  69606. if (destroy === undefined) { destroy = false; }
  69607. var i = this.list.length;
  69608. while (i--)
  69609. {
  69610. if (this.list[i])
  69611. {
  69612. var item = this.remove(this.list[i]);
  69613. if (destroy)
  69614. {
  69615. item.destroy();
  69616. }
  69617. }
  69618. }
  69619. this.position = 0;
  69620. this.list = [];
  69621. }
  69622. };
  69623. /**
  69624. * Number of items in the ArraySet. Same as `list.length`.
  69625. *
  69626. * @name Phaser.ArraySet#total
  69627. * @property {integer} total
  69628. */
  69629. Object.defineProperty(Phaser.ArraySet.prototype, "total", {
  69630. get: function () {
  69631. return this.list.length;
  69632. }
  69633. });
  69634. /**
  69635. * Returns the first item and resets the cursor to the start.
  69636. *
  69637. * @name Phaser.ArraySet#first
  69638. * @property {any} first
  69639. */
  69640. Object.defineProperty(Phaser.ArraySet.prototype, "first", {
  69641. get: function () {
  69642. this.position = 0;
  69643. if (this.list.length > 0)
  69644. {
  69645. return this.list[0];
  69646. }
  69647. else
  69648. {
  69649. return null;
  69650. }
  69651. }
  69652. });
  69653. /**
  69654. * Returns the the next item (based on the cursor) and advances the cursor.
  69655. *
  69656. * @name Phaser.ArraySet#next
  69657. * @property {any} next
  69658. */
  69659. Object.defineProperty(Phaser.ArraySet.prototype, "next", {
  69660. get: function () {
  69661. if (this.position < this.list.length)
  69662. {
  69663. this.position++;
  69664. return this.list[this.position];
  69665. }
  69666. else
  69667. {
  69668. return null;
  69669. }
  69670. }
  69671. });
  69672. Phaser.ArraySet.prototype.constructor = Phaser.ArraySet;
  69673. /**
  69674. * @author Richard Davey <rich@photonstorm.com>
  69675. * @copyright 2016 Photon Storm Ltd.
  69676. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  69677. */
  69678. /**
  69679. * Utility functions for dealing with Arrays.
  69680. *
  69681. * @class Phaser.ArrayUtils
  69682. * @static
  69683. */
  69684. Phaser.ArrayUtils = {
  69685. /**
  69686. * Fetch a random entry from the given array.
  69687. *
  69688. * Will return null if there are no array items that fall within the specified range
  69689. * or if there is no item for the randomly chosen index.
  69690. *
  69691. * @method Phaser.ArrayUtils.getRandomItem
  69692. * @param {any[]} objects - An array of objects.
  69693. * @param {integer} startIndex - Optional offset off the front of the array. Default value is 0, or the beginning of the array.
  69694. * @param {integer} length - Optional restriction on the number of values you want to randomly select from.
  69695. * @return {object} The random object that was selected.
  69696. */
  69697. getRandomItem: function (objects, startIndex, length) {
  69698. if (objects === null) { return null; }
  69699. if (startIndex === undefined) { startIndex = 0; }
  69700. if (length === undefined) { length = objects.length; }
  69701. var randomIndex = startIndex + Math.floor(Math.random() * length);
  69702. return objects[randomIndex] === undefined ? null : objects[randomIndex];
  69703. },
  69704. /**
  69705. * Removes a random object from the given array and returns it.
  69706. *
  69707. * Will return null if there are no array items that fall within the specified range
  69708. * or if there is no item for the randomly chosen index.
  69709. *
  69710. * @method Phaser.ArrayUtils.removeRandomItem
  69711. * @param {any[]} objects - An array of objects.
  69712. * @param {integer} startIndex - Optional offset off the front of the array. Default value is 0, or the beginning of the array.
  69713. * @param {integer} length - Optional restriction on the number of values you want to randomly select from.
  69714. * @return {object} The random object that was removed.
  69715. */
  69716. removeRandomItem: function (objects, startIndex, length) {
  69717. if (objects == null) { // undefined or null
  69718. return null;
  69719. }
  69720. if (startIndex === undefined) { startIndex = 0; }
  69721. if (length === undefined) { length = objects.length; }
  69722. var randomIndex = startIndex + Math.floor(Math.random() * length);
  69723. if (randomIndex < objects.length)
  69724. {
  69725. var removed = objects.splice(randomIndex, 1);
  69726. return removed[0] === undefined ? null : removed[0];
  69727. }
  69728. else
  69729. {
  69730. return null;
  69731. }
  69732. },
  69733. /**
  69734. * Remove one or more items at the given index and reorder the array.
  69735. *
  69736. * The new array length will be `array.length - count`.
  69737. *
  69738. * This is an alternative to `array.splice(startIndex, count)`.
  69739. *
  69740. * @see https://github.com/mreinstein/remove-array-items
  69741. * @see https://gamealchemist.wordpress.com/2013/05/01/lets-get-those-javascript-arrays-to-work-fast/
  69742. *
  69743. * @method Phaser.ArrayUtils.remove
  69744. * @param {any[]} array
  69745. * @param {integer} startIndex
  69746. * @param {integer} [count=1]
  69747. * @return {any[]} The modified array.
  69748. */
  69749. remove: function (array, startIndex, count)
  69750. {
  69751. var length = array.length;
  69752. if (startIndex >= length || count === 0) { return; }
  69753. if (count == null) { count = 1; }
  69754. var newLength = length - count;
  69755. for (var i = startIndex; i < newLength; ++i)
  69756. {
  69757. array[i] = array[i + count];
  69758. }
  69759. array.length = newLength;
  69760. },
  69761. /**
  69762. * A standard Fisher-Yates Array shuffle implementation which modifies the array in place.
  69763. *
  69764. * @method Phaser.ArrayUtils.shuffle
  69765. * @param {any[]} array - The array to shuffle.
  69766. * @return {any[]} The original array, now shuffled.
  69767. */
  69768. shuffle: function (array) {
  69769. for (var i = array.length - 1; i > 0; i--)
  69770. {
  69771. var j = Math.floor(Math.random() * (i + 1));
  69772. var temp = array[i];
  69773. array[i] = array[j];
  69774. array[j] = temp;
  69775. }
  69776. return array;
  69777. },
  69778. /**
  69779. * Transposes the elements of the given matrix (array of arrays).
  69780. *
  69781. * @method Phaser.ArrayUtils.transposeMatrix
  69782. * @param {Array<any[]>} array - The matrix to transpose.
  69783. * @return {Array<any[]>} A new transposed matrix
  69784. */
  69785. transposeMatrix: function (array) {
  69786. var sourceRowCount = array.length;
  69787. var sourceColCount = array[0].length;
  69788. var result = new Array(sourceColCount);
  69789. for (var i = 0; i < sourceColCount; i++)
  69790. {
  69791. result[i] = new Array(sourceRowCount);
  69792. for (var j = sourceRowCount - 1; j > -1; j--)
  69793. {
  69794. result[i][j] = array[j][i];
  69795. }
  69796. }
  69797. return result;
  69798. },
  69799. /**
  69800. * Rotates the given matrix (array of arrays).
  69801. *
  69802. * Based on the routine from {@link http://jsfiddle.net/MrPolywhirl/NH42z/}.
  69803. *
  69804. * @method Phaser.ArrayUtils.rotateMatrix
  69805. * @param {Array<any[]>} matrix - The array to rotate; this matrix _may_ be altered.
  69806. * @param {number|string} direction - The amount to rotate: the rotation in degrees (90, -90, 270, -270, 180) or a string command ('rotateLeft', 'rotateRight' or 'rotate180').
  69807. * @return {Array<any[]>} The rotated matrix. The source matrix should be discarded for the returned matrix.
  69808. */
  69809. rotateMatrix: function (matrix, direction) {
  69810. if (typeof direction !== 'string')
  69811. {
  69812. direction = ((direction % 360) + 360) % 360;
  69813. }
  69814. if (direction === 90 || direction === -270 || direction === 'rotateLeft')
  69815. {
  69816. matrix = Phaser.ArrayUtils.transposeMatrix(matrix);
  69817. matrix = matrix.reverse();
  69818. }
  69819. else if (direction === -90 || direction === 270 || direction === 'rotateRight')
  69820. {
  69821. matrix = matrix.reverse();
  69822. matrix = Phaser.ArrayUtils.transposeMatrix(matrix);
  69823. }
  69824. else if (Math.abs(direction) === 180 || direction === 'rotate180')
  69825. {
  69826. for (var i = 0; i < matrix.length; i++)
  69827. {
  69828. matrix[i].reverse();
  69829. }
  69830. matrix = matrix.reverse();
  69831. }
  69832. return matrix;
  69833. },
  69834. /**
  69835. * Snaps a value to the nearest value in a sorted numeric array.
  69836. * The result will always be in the range `[first_value, last_value]`.
  69837. *
  69838. * @method Phaser.ArrayUtils.findClosest
  69839. * @param {number} value - The search value
  69840. * @param {number[]} arr - The input array which _must_ be sorted.
  69841. * @return {number} The nearest value found.
  69842. */
  69843. findClosest: function (value, arr) {
  69844. if (!arr.length)
  69845. {
  69846. return NaN;
  69847. }
  69848. else if (arr.length === 1 || value < arr[0])
  69849. {
  69850. return arr[0];
  69851. }
  69852. var i = 1;
  69853. while (arr[i] < value) {
  69854. i++;
  69855. }
  69856. var low = arr[i - 1];
  69857. var high = (i < arr.length) ? arr[i] : Number.POSITIVE_INFINITY;
  69858. return ((high - value) <= (value - low)) ? high : low;
  69859. },
  69860. /**
  69861. * Moves the element from the end of the array to the start, shifting all items in the process.
  69862. * The "rotation" happens to the right.
  69863. *
  69864. * Before: `[ A, B, C, D, E, F ]`
  69865. * After: `[ F, A, B, C, D, E ]`
  69866. *
  69867. * See also Phaser.ArrayUtils.rotateLeft.
  69868. *
  69869. * @method Phaser.ArrayUtils.rotateRight
  69870. * @param {any[]} array - The array to rotate. The array is modified.
  69871. * @return {any} The shifted value.
  69872. */
  69873. rotateRight: function (array) {
  69874. var s = array.pop();
  69875. array.unshift(s);
  69876. return s;
  69877. },
  69878. /**
  69879. * Moves the element from the start of the array to the end, shifting all items in the process.
  69880. * The "rotation" happens to the left.
  69881. *
  69882. * Before: `[ A, B, C, D, E, F ]`
  69883. * After: `[ B, C, D, E, F, A ]`
  69884. *
  69885. * See also Phaser.ArrayUtils.rotateRight
  69886. *
  69887. * @method Phaser.ArrayUtils.rotateLeft
  69888. * @param {any[]} array - The array to rotate. The array is modified.
  69889. * @return {any} The rotated value.
  69890. */
  69891. rotateLeft: function (array) {
  69892. var s = array.shift();
  69893. array.push(s);
  69894. return s;
  69895. },
  69896. /**
  69897. * Moves the element from the start of the array to the end, shifting all items in the process.
  69898. * The "rotation" happens to the left.
  69899. *
  69900. * Before: `[ A, B, C, D, E, F ]`
  69901. * After: `[ B, C, D, E, F, A ]`
  69902. *
  69903. * See also Phaser.ArrayUtils.rotateRight
  69904. *
  69905. * @method Phaser.ArrayUtils.rotate
  69906. * @deprecated Please use Phaser.ArrayUtils.rotate instead.
  69907. * @param {any[]} array - The array to rotate. The array is modified.
  69908. * @return {any} The rotated value.
  69909. */
  69910. rotate: function (array) {
  69911. var s = array.shift();
  69912. array.push(s);
  69913. return s;
  69914. },
  69915. /**
  69916. * Create an array representing the inclusive range of numbers (usually integers) in `[start, end]` (or `[0, start]`, if `end` is omitted).
  69917. * This is equivalent to `numberArrayStep(start, 1 + end, 1)`.
  69918. *
  69919. * When exactly one argument is passed, it's used as `end` and 0 is used as `start`. The length of the result is (1 + end).
  69920. *
  69921. * ##### Examples
  69922. *
  69923. * ```javascript
  69924. * numberArray(3); // -> [0, 1, 2, 3]
  69925. * numberArray(0, 3); // -> [0, 1, 2, 3]
  69926. * numberArray(1, 3); // -> [1, 2, 3]
  69927. * ```
  69928. *
  69929. * @method Phaser.ArrayUtils.numberArray
  69930. * @param {number} start - The minimum value the array starts with.
  69931. * @param {number} [end] - The maximum value the array contains.
  69932. * @return {number[]} The array of number values.
  69933. */
  69934. numberArray: function (start, end) {
  69935. if (end === undefined || end === null)
  69936. {
  69937. end = start;
  69938. start = 0;
  69939. }
  69940. var result = [];
  69941. for (var i = start; i <= end; i++)
  69942. {
  69943. result.push(i);
  69944. }
  69945. return result;
  69946. },
  69947. /**
  69948. * Create an array of numbers (positive and/or negative) progressing from `start`
  69949. * up to but not including `end` by advancing by `step`.
  69950. *
  69951. * If `start` is less than `end` a zero-length range is created unless a negative `step` is specified.
  69952. *
  69953. * Certain values for `start` and `end` (eg. NaN/undefined/null) are currently coerced to 0;
  69954. * for forward compatibility make sure to pass in actual numbers.
  69955. *
  69956. * @method Phaser.ArrayUtils.numberArrayStep
  69957. * @param {number} start - The start of the range.
  69958. * @param {number} [end] - The end of the range.
  69959. * @param {number} [step=1] - The value to increment or decrement by.
  69960. * @returns {Array} Returns the new array of numbers.
  69961. * @example
  69962. * Phaser.ArrayUtils.numberArrayStep(4);
  69963. * // => [0, 1, 2, 3]
  69964. *
  69965. * Phaser.ArrayUtils.numberArrayStep(1, 5);
  69966. * // => [1, 2, 3, 4]
  69967. *
  69968. * Phaser.ArrayUtils.numberArrayStep(0, 20, 5);
  69969. * // => [0, 5, 10, 15]
  69970. *
  69971. * Phaser.ArrayUtils.numberArrayStep(0, -4, -1);
  69972. * // => [0, -1, -2, -3]
  69973. *
  69974. * Phaser.ArrayUtils.numberArrayStep(1, 4, 0);
  69975. * // => [1, 1, 1]
  69976. *
  69977. * Phaser.ArrayUtils.numberArrayStep(0);
  69978. * // => []
  69979. */
  69980. numberArrayStep: function (start, end, step) {
  69981. if (start === undefined || start === null) { start = 0; }
  69982. if (end === undefined || end === null)
  69983. {
  69984. end = start;
  69985. start = 0;
  69986. }
  69987. if (step === undefined) { step = 1; }
  69988. var result = [];
  69989. var total = Math.max(Phaser.Math.roundAwayFromZero((end - start) / (step || 1)), 0);
  69990. for (var i = 0; i < total; i++)
  69991. {
  69992. result.push(start);
  69993. start += step;
  69994. }
  69995. return result;
  69996. }
  69997. };
  69998. /**
  69999. * @author Richard Davey <rich@photonstorm.com>
  70000. * @copyright 2016 Photon Storm Ltd.
  70001. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  70002. */
  70003. /**
  70004. * A basic Linked List data structure.
  70005. *
  70006. * This implementation _modifies_ the `prev` and `next` properties of each item added:
  70007. * - The `prev` and `next` properties must be writable and should not be used for any other purpose.
  70008. * - Items _cannot_ be added to multiple LinkedLists at the same time.
  70009. * - Only objects can be added.
  70010. *
  70011. * @class Phaser.LinkedList
  70012. * @constructor
  70013. */
  70014. Phaser.LinkedList = function () {
  70015. /**
  70016. * Next element in the list.
  70017. * @property {object} next
  70018. * @default
  70019. */
  70020. this.next = null;
  70021. /**
  70022. * Previous element in the list.
  70023. * @property {object} prev
  70024. * @default
  70025. */
  70026. this.prev = null;
  70027. /**
  70028. * First element in the list.
  70029. * @property {object} first
  70030. * @default
  70031. */
  70032. this.first = null;
  70033. /**
  70034. * Last element in the list.
  70035. * @property {object} last
  70036. * @default
  70037. */
  70038. this.last = null;
  70039. /**
  70040. * Number of elements in the list.
  70041. * @property {integer} total
  70042. * @default
  70043. */
  70044. this.total = 0;
  70045. };
  70046. Phaser.LinkedList.prototype = {
  70047. /**
  70048. * Adds a new element to this linked list.
  70049. *
  70050. * @method Phaser.LinkedList#add
  70051. * @param {object} item - The element to add to this list. Can be a Phaser.Sprite or any other object you need to quickly iterate through.
  70052. * @return {object} The item that was added.
  70053. */
  70054. add: function (item) {
  70055. // If the list is empty
  70056. if (this.total === 0 && this.first === null && this.last === null)
  70057. {
  70058. this.first = item;
  70059. this.last = item;
  70060. this.next = item;
  70061. item.prev = this;
  70062. this.total++;
  70063. return item;
  70064. }
  70065. // Gets appended to the end of the list, regardless of anything, and it won't have any children of its own (non-nested list)
  70066. this.last.next = item;
  70067. item.prev = this.last;
  70068. this.last = item;
  70069. this.total++;
  70070. return item;
  70071. },
  70072. /**
  70073. * Resets the first, last, next and previous node pointers in this list.
  70074. *
  70075. * @method Phaser.LinkedList#reset
  70076. */
  70077. reset: function () {
  70078. this.first = null;
  70079. this.last = null;
  70080. this.next = null;
  70081. this.prev = null;
  70082. this.total = 0;
  70083. },
  70084. /**
  70085. * Removes the given element from this linked list if it exists.
  70086. *
  70087. * @method Phaser.LinkedList#remove
  70088. * @param {object} item - The item to be removed from the list.
  70089. */
  70090. remove: function (item) {
  70091. if (this.total === 1)
  70092. {
  70093. this.reset();
  70094. item.next = item.prev = null;
  70095. return;
  70096. }
  70097. if (item === this.first)
  70098. {
  70099. // It was 'first', make 'first' point to first.next
  70100. this.first = this.first.next;
  70101. }
  70102. else if (item === this.last)
  70103. {
  70104. // It was 'last', make 'last' point to last.prev
  70105. this.last = this.last.prev;
  70106. }
  70107. if (item.prev)
  70108. {
  70109. // make item.prev.next point to childs.next instead of item
  70110. item.prev.next = item.next;
  70111. }
  70112. if (item.next)
  70113. {
  70114. // make item.next.prev point to item.prev instead of item
  70115. item.next.prev = item.prev;
  70116. }
  70117. item.next = item.prev = null;
  70118. if (this.first === null )
  70119. {
  70120. this.last = null;
  70121. }
  70122. this.total--;
  70123. },
  70124. /**
  70125. * Calls a function on all members of this list, using the member as the context for the callback.
  70126. * The function must exist on the member.
  70127. *
  70128. * @method Phaser.LinkedList#callAll
  70129. * @param {function} callback - The function to call.
  70130. */
  70131. callAll: function (callback) {
  70132. if (!this.first || !this.last)
  70133. {
  70134. return;
  70135. }
  70136. var entity = this.first;
  70137. do
  70138. {
  70139. if (entity && entity[callback])
  70140. {
  70141. entity[callback].call(entity);
  70142. }
  70143. entity = entity.next;
  70144. }
  70145. while (entity !== this.last.next);
  70146. }
  70147. };
  70148. Phaser.LinkedList.prototype.constructor = Phaser.LinkedList;
  70149. /**
  70150. * @author Richard Davey <rich@photonstorm.com>
  70151. * @copyright 2016 Photon Storm Ltd.
  70152. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  70153. */
  70154. /**
  70155. * The Phaser.Create class is a collection of smaller helper methods that allow you to generate game content
  70156. * quickly and easily, without the need for any external files. You can create textures for sprites and in
  70157. * coming releases we'll add dynamic sound effect generation support as well (like sfxr).
  70158. *
  70159. * Access this via `Game.create` (`this.game.create` from within a State object).
  70160. *
  70161. * @class Phaser.Create
  70162. * @constructor
  70163. * @param {Phaser.Game} game - Game reference to the currently running game.
  70164. */
  70165. Phaser.Create = function (game) {
  70166. /**
  70167. * @property {Phaser.Game} game - A reference to the currently running Game.
  70168. */
  70169. this.game = game;
  70170. /**
  70171. * @property {Phaser.BitmapData} bmd - The internal BitmapData Create uses to generate textures from.
  70172. */
  70173. this.bmd = null;
  70174. /**
  70175. * @property {HTMLCanvasElement} canvas - The canvas the BitmapData uses.
  70176. */
  70177. this.canvas = null;
  70178. /**
  70179. * @property {CanvasRenderingContext2D} context - The 2d context of the canvas.
  70180. */
  70181. this.ctx = null;
  70182. /**
  70183. * @property {array} palettes - A range of 16 color palettes for use with sprite generation.
  70184. */
  70185. this.palettes = [
  70186. { 0: '#000', 1: '#9D9D9D', 2: '#FFF', 3: '#BE2633', 4: '#E06F8B', 5: '#493C2B', 6: '#A46422', 7: '#EB8931', 8: '#F7E26B', 9: '#2F484E', A: '#44891A', B: '#A3CE27', C: '#1B2632', D: '#005784', E: '#31A2F2', F: '#B2DCEF' },
  70187. { 0: '#000', 1: '#191028', 2: '#46af45', 3: '#a1d685', 4: '#453e78', 5: '#7664fe', 6: '#833129', 7: '#9ec2e8', 8: '#dc534b', 9: '#e18d79', A: '#d6b97b', B: '#e9d8a1', C: '#216c4b', D: '#d365c8', E: '#afaab9', F: '#f5f4eb' },
  70188. { 0: '#000', 1: '#2234d1', 2: '#0c7e45', 3: '#44aacc', 4: '#8a3622', 5: '#5c2e78', 6: '#aa5c3d', 7: '#b5b5b5', 8: '#5e606e', 9: '#4c81fb', A: '#6cd947', B: '#7be2f9', C: '#eb8a60', D: '#e23d69', E: '#ffd93f', F: '#fff' },
  70189. { 0: '#000', 1: '#fff', 2: '#8b4131', 3: '#7bbdc5', 4: '#8b41ac', 5: '#6aac41', 6: '#3931a4', 7: '#d5de73', 8: '#945a20', 9: '#5a4100', A: '#bd736a', B: '#525252', C: '#838383', D: '#acee8b', E: '#7b73de', F: '#acacac' },
  70190. { 0: '#000', 1: '#191028', 2: '#46af45', 3: '#a1d685', 4: '#453e78', 5: '#7664fe', 6: '#833129', 7: '#9ec2e8', 8: '#dc534b', 9: '#e18d79', A: '#d6b97b', B: '#e9d8a1', C: '#216c4b', D: '#d365c8', E: '#afaab9', F: '#fff' }
  70191. ];
  70192. };
  70193. /**
  70194. * A 16 color palette by [Arne](http://androidarts.com/palette/16pal.htm)
  70195. * @constant
  70196. * @type {number}
  70197. */
  70198. Phaser.Create.PALETTE_ARNE = 0;
  70199. /**
  70200. * A 16 color JMP inspired palette.
  70201. * @constant
  70202. * @type {number}
  70203. */
  70204. Phaser.Create.PALETTE_JMP = 1;
  70205. /**
  70206. * A 16 color CGA inspired palette.
  70207. * @constant
  70208. * @type {number}
  70209. */
  70210. Phaser.Create.PALETTE_CGA = 2;
  70211. /**
  70212. * A 16 color C64 inspired palette.
  70213. * @constant
  70214. * @type {number}
  70215. */
  70216. Phaser.Create.PALETTE_C64 = 3;
  70217. /**
  70218. * A 16 color palette inspired by Japanese computers like the MSX.
  70219. * @constant
  70220. * @type {number}
  70221. */
  70222. Phaser.Create.PALETTE_JAPANESE_MACHINE = 4;
  70223. Phaser.Create.prototype = {
  70224. /**
  70225. * Generates a new PIXI.Texture from the given data, which can be applied to a Sprite.
  70226. *
  70227. * This allows you to create game graphics quickly and easily, with no external files but that use actual proper images
  70228. * rather than Phaser.Graphics objects, which are expensive to render and limited in scope.
  70229. *
  70230. * Each element of the array is a string holding the pixel color values, as mapped to one of the Phaser.Create PALETTE consts.
  70231. *
  70232. * For example:
  70233. *
  70234. * `var data = [
  70235. * ' 333 ',
  70236. * ' 777 ',
  70237. * 'E333E',
  70238. * ' 333 ',
  70239. * ' 3 3 '
  70240. * ];`
  70241. *
  70242. * `game.create.texture('bob', data);`
  70243. *
  70244. * The above will create a new texture called `bob`, which will look like a little man wearing a hat. You can then use it
  70245. * for sprites the same way you use any other texture: `game.add.sprite(0, 0, 'bob');`
  70246. *
  70247. * @method Phaser.Create#texture
  70248. * @param {string} key - The key used to store this texture in the Phaser Cache.
  70249. * @param {array} data - An array of pixel data.
  70250. * @param {integer} [pixelWidth=8] - The width of each pixel.
  70251. * @param {integer} [pixelHeight=8] - The height of each pixel.
  70252. * @param {integer} [palette=0] - The palette to use when rendering the texture. One of the Phaser.Create.PALETTE consts.
  70253. * @param {boolean} [generateTexture=true] - When false, a new BitmapData object is returned instead.
  70254. * @param {function} [callback] - A function to execute once the texture is generated. It will be passed the newly generated texture.
  70255. * @param {any} [callbackContext] - The context in which to invoke the callback.
  70256. * @return {?PIXI.Texture|Phaser.BitmapData} The newly generated texture, or a new BitmapData object if `generateTexture` is false, or `null` if a callback was passed and the texture isn't available yet.
  70257. */
  70258. texture: function (key, data, pixelWidth, pixelHeight, palette, generateTexture, callback, callbackContext) {
  70259. if (pixelWidth === undefined) { pixelWidth = 8; }
  70260. if (pixelHeight === undefined) { pixelHeight = pixelWidth; }
  70261. if (palette === undefined) { palette = 0; }
  70262. if (generateTexture === undefined) { generateTexture = true; }
  70263. var w = data[0].length * pixelWidth;
  70264. var h = data.length * pixelHeight;
  70265. // No bmd? Let's make one
  70266. if (this.bmd === null)
  70267. {
  70268. this.bmd = this.game.make.bitmapData();
  70269. this.canvas = this.bmd.canvas;
  70270. this.ctx = this.bmd.context;
  70271. }
  70272. this.bmd.resize(w, h);
  70273. this.bmd.clear();
  70274. // Draw it
  70275. for (var y = 0; y < data.length; y++)
  70276. {
  70277. var row = data[y];
  70278. for (var x = 0; x < row.length; x++)
  70279. {
  70280. var d = row[x];
  70281. if (d !== '.' && d !== ' ')
  70282. {
  70283. this.ctx.fillStyle = this.palettes[palette][d];
  70284. this.ctx.fillRect(x * pixelWidth, y * pixelHeight, pixelWidth, pixelHeight);
  70285. }
  70286. }
  70287. }
  70288. return generateTexture ?
  70289. this.bmd.generateTexture(key, callback, callbackContext) :
  70290. this.copy();
  70291. },
  70292. /**
  70293. * Creates a grid texture based on the given dimensions.
  70294. *
  70295. * @method Phaser.Create#grid
  70296. * @param {string} key - The key used to store this texture in the Phaser Cache.
  70297. * @param {integer} width - The width of the grid in pixels.
  70298. * @param {integer} height - The height of the grid in pixels.
  70299. * @param {integer} cellWidth - The width of the grid cells in pixels.
  70300. * @param {integer} cellHeight - The height of the grid cells in pixels.
  70301. * @param {string} color - The color to draw the grid lines in. Should be a Canvas supported color string like `#ff5500` or `rgba(200,50,3,0.5)`.
  70302. * @param {boolean} [generateTexture=true] - When false, a new BitmapData object is returned instead.
  70303. * @param {function} [callback] - A function to execute once the texture is generated. It will be passed the newly generated texture.
  70304. * @param {any} [callbackContext] - The context in which to invoke the callback.
  70305. * @return {?PIXI.Texture|Phaser.BitmapData} The newly generated texture, or a new BitmapData object if `generateTexture` is false, or `null` if a callback was passed and the texture isn't available yet.
  70306. */
  70307. grid: function (key, width, height, cellWidth, cellHeight, color, generateTexture, callback, callbackContext) {
  70308. if (generateTexture === undefined) { generateTexture = true; }
  70309. // No bmd? Let's make one
  70310. if (this.bmd === null)
  70311. {
  70312. this.bmd = this.game.make.bitmapData();
  70313. this.canvas = this.bmd.canvas;
  70314. this.ctx = this.bmd.context;
  70315. }
  70316. this.bmd.resize(width, height);
  70317. this.ctx.fillStyle = color;
  70318. for (var y = 0; y < height; y += cellHeight)
  70319. {
  70320. this.ctx.fillRect(0, y, width, 1);
  70321. }
  70322. for (var x = 0; x < width; x += cellWidth)
  70323. {
  70324. this.ctx.fillRect(x, 0, 1, height);
  70325. }
  70326. return generateTexture ?
  70327. this.bmd.generateTexture(key, callback, callbackContext) :
  70328. this.copy();
  70329. },
  70330. /**
  70331. * Copies the contents of {@link bmd Create's canvas} to the given BitmapData object, or a new BitmapData object.
  70332. *
  70333. * @param {Phaser.BitmapData} [dest] - The BitmapData receiving the copied image.
  70334. * @param {number} [x=0] - The x coordinate to translate to before drawing.
  70335. * @param {number} [y=0] - The y coordinate to translate to before drawing.
  70336. * @param {number} [width] - The new width of the Sprite being copied.
  70337. * @param {number} [height] - The new height of the Sprite being copied.
  70338. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  70339. * @param {boolean} [roundPx=false] - Should the x and y values be rounded to integers before drawing? This prevents anti-aliasing in some instances.
  70340. * @return {Phaser.BitmapData} - The `dest` argument (if passed), or a new BitmapData object
  70341. */
  70342. copy: function (dest, x, y, width, height, blendMode, roundPx) {
  70343. if (dest == null) { dest = this.game.make.bitmapData(); }
  70344. dest.resize(this.bmd.width, this.bmd.height);
  70345. return dest.draw(this.bmd, x, y, width, height, blendMode, roundPx);
  70346. }
  70347. };
  70348. Phaser.Create.prototype.constructor = Phaser.Create;
  70349. /**
  70350. * @author Richard Davey <rich@photonstorm.com>
  70351. * @copyright 2016 Photon Storm Ltd.
  70352. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  70353. */
  70354. /**
  70355. * WARNING: This is an EXPERIMENTAL class. The API will change significantly in the coming versions and is incomplete.
  70356. * Please try to avoid using in production games with a long time to build.
  70357. * This is also why the documentation is incomplete.
  70358. *
  70359. * FlexGrid is a a responsive grid manager that works in conjunction with the ScaleManager RESIZE scaling mode and FlexLayers
  70360. * to provide for game object positioning in a responsive manner.
  70361. *
  70362. * @class Phaser.FlexGrid
  70363. * @constructor
  70364. * @param {Phaser.ScaleManager} manager - The ScaleManager.
  70365. * @param {number} width - The width of the game.
  70366. * @param {number} height - The height of the game.
  70367. */
  70368. Phaser.FlexGrid = function (manager, width, height) {
  70369. /**
  70370. * @property {Phaser.Game} game - A reference to the currently running Game.
  70371. */
  70372. this.game = manager.game;
  70373. /**
  70374. * @property {Phaser.ScaleManager} manager - A reference to the ScaleManager.
  70375. */
  70376. this.manager = manager;
  70377. // The perfect dimensions on which everything else is based
  70378. this.width = width;
  70379. this.height = height;
  70380. this.boundsCustom = new Phaser.Rectangle(0, 0, width, height);
  70381. this.boundsFluid = new Phaser.Rectangle(0, 0, width, height);
  70382. this.boundsFull = new Phaser.Rectangle(0, 0, width, height);
  70383. this.boundsNone = new Phaser.Rectangle(0, 0, width, height);
  70384. /**
  70385. * @property {Phaser.Point} position -
  70386. * @readonly
  70387. */
  70388. this.positionCustom = new Phaser.Point(0, 0);
  70389. this.positionFluid = new Phaser.Point(0, 0);
  70390. this.positionFull = new Phaser.Point(0, 0);
  70391. this.positionNone = new Phaser.Point(0, 0);
  70392. /**
  70393. * @property {Phaser.Point} scaleFactor - The scale factor based on the game dimensions vs. the scaled dimensions.
  70394. * @readonly
  70395. */
  70396. this.scaleCustom = new Phaser.Point(1, 1);
  70397. this.scaleFluid = new Phaser.Point(1, 1);
  70398. this.scaleFluidInversed = new Phaser.Point(1, 1);
  70399. this.scaleFull = new Phaser.Point(1, 1);
  70400. this.scaleNone = new Phaser.Point(1, 1);
  70401. this.customWidth = 0;
  70402. this.customHeight = 0;
  70403. this.customOffsetX = 0;
  70404. this.customOffsetY = 0;
  70405. this.ratioH = width / height;
  70406. this.ratioV = height / width;
  70407. this.multiplier = 0;
  70408. this.layers = [];
  70409. };
  70410. Phaser.FlexGrid.prototype = {
  70411. /**
  70412. * Sets the core game size. This resets the w/h parameters and bounds.
  70413. *
  70414. * @method Phaser.FlexGrid#setSize
  70415. * @param {number} width - The new dimensions.
  70416. * @param {number} height - The new dimensions.
  70417. */
  70418. setSize: function (width, height) {
  70419. // These are locked and don't change until setSize is called again
  70420. this.width = width;
  70421. this.height = height;
  70422. this.ratioH = width / height;
  70423. this.ratioV = height / width;
  70424. this.scaleNone = new Phaser.Point(1, 1);
  70425. this.boundsNone.width = this.width;
  70426. this.boundsNone.height = this.height;
  70427. this.refresh();
  70428. },
  70429. // Need ability to create your own layers with custom scaling, etc.
  70430. /**
  70431. * A custom layer is centered on the game and maintains its aspect ratio as it scales up and down.
  70432. *
  70433. * @method Phaser.FlexGrid#createCustomLayer
  70434. * @param {number} width - Width of this layer in pixels.
  70435. * @param {number} height - Height of this layer in pixels.
  70436. * @param {PIXI.DisplayObject[]} [children] - An array of children that are used to populate the FlexLayer.
  70437. * @return {Phaser.FlexLayer} The Layer object.
  70438. */
  70439. createCustomLayer: function (width, height, children, addToWorld) {
  70440. if (addToWorld === undefined) { addToWorld = true; }
  70441. this.customWidth = width;
  70442. this.customHeight = height;
  70443. this.boundsCustom.width = width;
  70444. this.boundsCustom.height = height;
  70445. var layer = new Phaser.FlexLayer(this, this.positionCustom, this.boundsCustom, this.scaleCustom);
  70446. if (addToWorld)
  70447. {
  70448. this.game.world.add(layer);
  70449. }
  70450. this.layers.push(layer);
  70451. if (typeof children !== 'undefined' && typeof children !== null)
  70452. {
  70453. layer.addMultiple(children);
  70454. }
  70455. return layer;
  70456. },
  70457. /**
  70458. * A fluid layer is centered on the game and maintains its aspect ratio as it scales up and down.
  70459. *
  70460. * @method Phaser.FlexGrid#createFluidLayer
  70461. * @param {array} [children] - An array of children that are used to populate the FlexLayer.
  70462. * @return {Phaser.FlexLayer} The Layer object.
  70463. */
  70464. createFluidLayer: function (children, addToWorld) {
  70465. if (addToWorld === undefined) { addToWorld = true; }
  70466. var layer = new Phaser.FlexLayer(this, this.positionFluid, this.boundsFluid, this.scaleFluid);
  70467. if (addToWorld)
  70468. {
  70469. this.game.world.add(layer);
  70470. }
  70471. this.layers.push(layer);
  70472. if (typeof children !== 'undefined' && typeof children !== null)
  70473. {
  70474. layer.addMultiple(children);
  70475. }
  70476. return layer;
  70477. },
  70478. /**
  70479. * A full layer is placed at 0,0 and extends to the full size of the game. Children are scaled according to the fluid ratios.
  70480. *
  70481. * @method Phaser.FlexGrid#createFullLayer
  70482. * @param {array} [children] - An array of children that are used to populate the FlexLayer.
  70483. * @return {Phaser.FlexLayer} The Layer object.
  70484. */
  70485. createFullLayer: function (children) {
  70486. var layer = new Phaser.FlexLayer(this, this.positionFull, this.boundsFull, this.scaleFluid);
  70487. this.game.world.add(layer);
  70488. this.layers.push(layer);
  70489. if (typeof children !== 'undefined')
  70490. {
  70491. layer.addMultiple(children);
  70492. }
  70493. return layer;
  70494. },
  70495. /**
  70496. * A fixed layer is centered on the game and is the size of the required dimensions and is never scaled.
  70497. *
  70498. * @method Phaser.FlexGrid#createFixedLayer
  70499. * @param {PIXI.DisplayObject[]} [children] - An array of children that are used to populate the FlexLayer.
  70500. * @return {Phaser.FlexLayer} The Layer object.
  70501. */
  70502. createFixedLayer: function (children) {
  70503. var layer = new Phaser.FlexLayer(this, this.positionNone, this.boundsNone, this.scaleNone);
  70504. this.game.world.add(layer);
  70505. this.layers.push(layer);
  70506. if (typeof children !== 'undefined')
  70507. {
  70508. layer.addMultiple(children);
  70509. }
  70510. return layer;
  70511. },
  70512. /**
  70513. * Resets the layer children references
  70514. *
  70515. * @method Phaser.FlexGrid#reset
  70516. */
  70517. reset: function () {
  70518. var i = this.layers.length;
  70519. while (i--)
  70520. {
  70521. if (!this.layers[i].persist)
  70522. {
  70523. // Remove references to this class
  70524. this.layers[i].position = null;
  70525. this.layers[i].scale = null;
  70526. this.layers.slice(i, 1);
  70527. }
  70528. }
  70529. },
  70530. /**
  70531. * Called when the game container changes dimensions.
  70532. *
  70533. * @method Phaser.FlexGrid#onResize
  70534. * @param {number} width - The new width of the game container.
  70535. * @param {number} height - The new height of the game container.
  70536. */
  70537. onResize: function (width, height) {
  70538. this.ratioH = width / height;
  70539. this.ratioV = height / width;
  70540. this.refresh(width, height);
  70541. },
  70542. /**
  70543. * Updates all internal vars such as the bounds and scale values.
  70544. *
  70545. * @method Phaser.FlexGrid#refresh
  70546. */
  70547. refresh: function () {
  70548. this.multiplier = Math.min((this.manager.height / this.height), (this.manager.width / this.width));
  70549. this.boundsFluid.width = Math.round(this.width * this.multiplier);
  70550. this.boundsFluid.height = Math.round(this.height * this.multiplier);
  70551. this.scaleFluid.set(this.boundsFluid.width / this.width, this.boundsFluid.height / this.height);
  70552. this.scaleFluidInversed.set(this.width / this.boundsFluid.width, this.height / this.boundsFluid.height);
  70553. this.scaleFull.set(this.boundsFull.width / this.width, this.boundsFull.height / this.height);
  70554. this.boundsFull.width = Math.round(this.manager.width * this.scaleFluidInversed.x);
  70555. this.boundsFull.height = Math.round(this.manager.height * this.scaleFluidInversed.y);
  70556. this.boundsFluid.centerOn(this.manager.bounds.centerX, this.manager.bounds.centerY);
  70557. this.boundsNone.centerOn(this.manager.bounds.centerX, this.manager.bounds.centerY);
  70558. this.positionFluid.set(this.boundsFluid.x, this.boundsFluid.y);
  70559. this.positionNone.set(this.boundsNone.x, this.boundsNone.y);
  70560. },
  70561. /**
  70562. * Fits a sprites width to the bounds.
  70563. *
  70564. * @method Phaser.FlexGrid#fitSprite
  70565. * @param {Phaser.Sprite} sprite - The Sprite to fit.
  70566. */
  70567. fitSprite: function (sprite) {
  70568. this.manager.scaleSprite(sprite);
  70569. sprite.x = this.manager.bounds.centerX;
  70570. sprite.y = this.manager.bounds.centerY;
  70571. },
  70572. /**
  70573. * Call in the render function to output the bounds rects.
  70574. *
  70575. * @method Phaser.FlexGrid#debug
  70576. */
  70577. debug: function () {
  70578. // for (var i = 0; i < this.layers.length; i++)
  70579. // {
  70580. // this.layers[i].debug();
  70581. // }
  70582. // this.game.debug.text(this.boundsFull.width + ' x ' + this.boundsFull.height, this.boundsFull.x + 4, this.boundsFull.y + 16);
  70583. // this.game.debug.geom(this.boundsFull, 'rgba(0,0,255,0.9', false);
  70584. this.game.debug.text(this.boundsFluid.width + ' x ' + this.boundsFluid.height, this.boundsFluid.x + 4, this.boundsFluid.y + 16);
  70585. this.game.debug.geom(this.boundsFluid, 'rgba(255,0,0,0.9', false);
  70586. // this.game.debug.text(this.boundsNone.width + ' x ' + this.boundsNone.height, this.boundsNone.x + 4, this.boundsNone.y + 16);
  70587. // this.game.debug.geom(this.boundsNone, 'rgba(0,255,0,0.9', false);
  70588. // this.game.debug.text(this.boundsCustom.width + ' x ' + this.boundsCustom.height, this.boundsCustom.x + 4, this.boundsCustom.y + 16);
  70589. // this.game.debug.geom(this.boundsCustom, 'rgba(255,255,0,0.9', false);
  70590. }
  70591. };
  70592. Phaser.FlexGrid.prototype.constructor = Phaser.FlexGrid;
  70593. /**
  70594. * @author Richard Davey <rich@photonstorm.com>
  70595. * @copyright 2016 Photon Storm Ltd.
  70596. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  70597. */
  70598. /**
  70599. * WARNING: This is an EXPERIMENTAL class. The API will change significantly in the coming versions and is incomplete.
  70600. * Please try to avoid using in production games with a long time to build.
  70601. * This is also why the documentation is incomplete.
  70602. *
  70603. * A responsive grid layer.
  70604. *
  70605. * @class Phaser.FlexLayer
  70606. * @extends Phaser.Group
  70607. * @constructor
  70608. * @param {Phaser.FlexGrid} manager - The FlexGrid that owns this FlexLayer.
  70609. * @param {Phaser.Point} position - A reference to the Point object used for positioning.
  70610. * @param {Phaser.Rectangle} bounds - A reference to the Rectangle used for the layer bounds.
  70611. * @param {Phaser.Point} scale - A reference to the Point object used for layer scaling.
  70612. */
  70613. Phaser.FlexLayer = function (manager, position, bounds, scale) {
  70614. Phaser.Group.call(this, manager.game, null, '__flexLayer' + manager.game.rnd.uuid(), false);
  70615. /**
  70616. * @property {Phaser.ScaleManager} scale - A reference to the ScaleManager.
  70617. */
  70618. this.manager = manager.manager;
  70619. /**
  70620. * @property {Phaser.FlexGrid} grid - A reference to the FlexGrid that owns this layer.
  70621. */
  70622. this.grid = manager;
  70623. /**
  70624. * Should the FlexLayer remain through a State swap?
  70625. *
  70626. * @type {boolean}
  70627. */
  70628. this.persist = false;
  70629. /**
  70630. * @property {Phaser.Point} position
  70631. */
  70632. this.position = position;
  70633. /**
  70634. * @property {Phaser.Rectangle} bounds
  70635. */
  70636. this.bounds = bounds;
  70637. /**
  70638. * @property {Phaser.Point} scale
  70639. */
  70640. this.scale = scale;
  70641. /**
  70642. * @property {Phaser.Point} topLeft
  70643. */
  70644. this.topLeft = bounds.topLeft;
  70645. /**
  70646. * @property {Phaser.Point} topMiddle
  70647. */
  70648. this.topMiddle = new Phaser.Point(bounds.halfWidth, 0);
  70649. /**
  70650. * @property {Phaser.Point} topRight
  70651. */
  70652. this.topRight = bounds.topRight;
  70653. /**
  70654. * @property {Phaser.Point} bottomLeft
  70655. */
  70656. this.bottomLeft = bounds.bottomLeft;
  70657. /**
  70658. * @property {Phaser.Point} bottomMiddle
  70659. */
  70660. this.bottomMiddle = new Phaser.Point(bounds.halfWidth, bounds.bottom);
  70661. /**
  70662. * @property {Phaser.Point} bottomRight
  70663. */
  70664. this.bottomRight = bounds.bottomRight;
  70665. };
  70666. Phaser.FlexLayer.prototype = Object.create(Phaser.Group.prototype);
  70667. Phaser.FlexLayer.prototype.constructor = Phaser.FlexLayer;
  70668. /**
  70669. * Resize.
  70670. *
  70671. * @method Phaser.FlexLayer#resize
  70672. */
  70673. Phaser.FlexLayer.prototype.resize = function () {
  70674. };
  70675. /**
  70676. * Debug.
  70677. *
  70678. * @method Phaser.FlexLayer#debug
  70679. */
  70680. Phaser.FlexLayer.prototype.debug = function () {
  70681. this.game.debug.text(this.bounds.width + ' x ' + this.bounds.height, this.bounds.x + 4, this.bounds.y + 16);
  70682. this.game.debug.geom(this.bounds, 'rgba(0,0,255,0.9', false);
  70683. this.game.debug.geom(this.topLeft, 'rgba(255,255,255,0.9');
  70684. this.game.debug.geom(this.topMiddle, 'rgba(255,255,255,0.9');
  70685. this.game.debug.geom(this.topRight, 'rgba(255,255,255,0.9');
  70686. };
  70687. /**
  70688. * @author Richard Davey <rich@photonstorm.com>
  70689. * @copyright 2016 Photon Storm Ltd.
  70690. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  70691. */
  70692. /**
  70693. * The Phaser.Color class is a set of static methods that assist in color manipulation and conversion.
  70694. *
  70695. * @class Phaser.Color
  70696. */
  70697. Phaser.Color = {
  70698. /**
  70699. * Packs the r, g, b, a components into a single integer, for use with Int32Array.
  70700. * If device is little endian then ABGR order is used. Otherwise RGBA order is used.
  70701. *
  70702. * @author Matt DesLauriers (@mattdesl)
  70703. * @method Phaser.Color.packPixel
  70704. * @static
  70705. * @param {number} r - The red color component, in the range 0 - 255.
  70706. * @param {number} g - The green color component, in the range 0 - 255.
  70707. * @param {number} b - The blue color component, in the range 0 - 255.
  70708. * @param {number} a - The alpha color component, in the range 0 - 255.
  70709. * @return {number} The packed color as uint32
  70710. */
  70711. packPixel: function (r, g, b, a) {
  70712. if (Phaser.Device.LITTLE_ENDIAN)
  70713. {
  70714. return ( (a << 24) | (b << 16) | (g << 8) | r ) >>> 0;
  70715. }
  70716. else
  70717. {
  70718. return ( (r << 24) | (g << 16) | (b << 8) | a ) >>> 0;
  70719. }
  70720. },
  70721. /**
  70722. * Unpacks the r, g, b, a components into the specified color object, or a new
  70723. * object, for use with Int32Array. If little endian, then ABGR order is used when
  70724. * unpacking, otherwise, RGBA order is used. The resulting color object has the
  70725. * `r, g, b, a` properties which are unrelated to endianness.
  70726. *
  70727. * Note that the integer is assumed to be packed in the correct endianness. On little-endian
  70728. * the format is 0xAABBGGRR and on big-endian the format is 0xRRGGBBAA. If you want a
  70729. * endian-independent method, use fromRGBA(rgba) and toRGBA(r, g, b, a).
  70730. *
  70731. * @author Matt DesLauriers (@mattdesl)
  70732. * @method Phaser.Color.unpackPixel
  70733. * @static
  70734. * @param {number} rgba - The integer, packed in endian order by packPixel.
  70735. * @param {object} [out] - An object into which 3 properties will be created: r, g and b. If not provided a new object will be created.
  70736. * @param {boolean} [hsl=false] - Also convert the rgb values into hsl?
  70737. * @param {boolean} [hsv=false] - Also convert the rgb values into hsv?
  70738. * @return {object} An object with the red, green and blue values set in the r, g and b properties.
  70739. */
  70740. unpackPixel: function (rgba, out, hsl, hsv) {
  70741. if (out === undefined || out === null) { out = Phaser.Color.createColor(); }
  70742. if (hsl === undefined || hsl === null) { hsl = false; }
  70743. if (hsv === undefined || hsv === null) { hsv = false; }
  70744. if (Phaser.Device.LITTLE_ENDIAN)
  70745. {
  70746. out.a = ((rgba & 0xff000000) >>> 24);
  70747. out.b = ((rgba & 0x00ff0000) >>> 16);
  70748. out.g = ((rgba & 0x0000ff00) >>> 8);
  70749. out.r = ((rgba & 0x000000ff));
  70750. }
  70751. else
  70752. {
  70753. out.r = ((rgba & 0xff000000) >>> 24);
  70754. out.g = ((rgba & 0x00ff0000) >>> 16);
  70755. out.b = ((rgba & 0x0000ff00) >>> 8);
  70756. out.a = ((rgba & 0x000000ff));
  70757. }
  70758. out.color = rgba;
  70759. out.rgba = 'rgba(' + out.r + ',' + out.g + ',' + out.b + ',' + (out.a / 255) + ')';
  70760. if (hsl)
  70761. {
  70762. Phaser.Color.RGBtoHSL(out.r, out.g, out.b, out);
  70763. }
  70764. if (hsv)
  70765. {
  70766. Phaser.Color.RGBtoHSV(out.r, out.g, out.b, out);
  70767. }
  70768. return out;
  70769. },
  70770. /**
  70771. * A utility to convert an integer in 0xRRGGBBAA format to a color object.
  70772. * This does not rely on endianness.
  70773. *
  70774. * @author Matt DesLauriers (@mattdesl)
  70775. * @method Phaser.Color.fromRGBA
  70776. * @static
  70777. * @param {number} rgba - An RGBA hex
  70778. * @param {object} [out] - The object to use, optional.
  70779. * @return {object} A color object.
  70780. */
  70781. fromRGBA: function (rgba, out) {
  70782. if (!out)
  70783. {
  70784. out = Phaser.Color.createColor();
  70785. }
  70786. out.r = ((rgba & 0xff000000) >>> 24);
  70787. out.g = ((rgba & 0x00ff0000) >>> 16);
  70788. out.b = ((rgba & 0x0000ff00) >>> 8);
  70789. out.a = ((rgba & 0x000000ff));
  70790. out.rgba = 'rgba(' + out.r + ',' + out.g + ',' + out.b + ',' + out.a + ')';
  70791. return out;
  70792. },
  70793. /**
  70794. * A utility to convert RGBA components to a 32 bit integer in RRGGBBAA format.
  70795. *
  70796. * @author Matt DesLauriers (@mattdesl)
  70797. * @method Phaser.Color.toRGBA
  70798. * @static
  70799. * @param {number} r - The red color component, in the range 0 - 255.
  70800. * @param {number} g - The green color component, in the range 0 - 255.
  70801. * @param {number} b - The blue color component, in the range 0 - 255.
  70802. * @param {number} a - The alpha color component, in the range 0 - 255.
  70803. * @return {number} A RGBA-packed 32 bit integer
  70804. */
  70805. toRGBA: function (r, g, b, a) {
  70806. return (r << 24) | (g << 16) | (b << 8) | a;
  70807. },
  70808. /**
  70809. * Converts RGBA components to a 32 bit integer in AABBGGRR format.
  70810. *
  70811. * @method Phaser.Color.toABGR
  70812. * @static
  70813. * @param {number} r - The red color component, in the range 0 - 255.
  70814. * @param {number} g - The green color component, in the range 0 - 255.
  70815. * @param {number} b - The blue color component, in the range 0 - 255.
  70816. * @param {number} a - The alpha color component, in the range 0 - 255.
  70817. * @return {number} A RGBA-packed 32 bit integer
  70818. */
  70819. toABGR: function (r, g, b, a) {
  70820. return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0;
  70821. },
  70822. /**
  70823. * Converts a hex color value to an [R, G, B] array.
  70824. *
  70825. * @static
  70826. * @method Phaser.Color.hexToRGBArray
  70827. * @param {number} color - The color to convert to an RGB array. In the format 0xRRGGBB.
  70828. * @return {array} An array with element 0 containing the Red value, 1 containing Green, and 2 containing Blue.
  70829. */
  70830. hexToRGBArray: function (color) {
  70831. return [
  70832. (color >> 16 & 0xFF) / 255,
  70833. (color >> 8 & 0xFF) / 255,
  70834. (color & 0xFF) / 255
  70835. ];
  70836. },
  70837. /**
  70838. * Converts an RGB color array, in the format: [R, G, B], to a hex color value.
  70839. *
  70840. * @static
  70841. * @method Phaser.Color.RGBArrayToHex
  70842. * @param {array} rgb - An array with element 0 containing the Red value, 1 containing Green, and 2 containing Blue.
  70843. * @return {number} The color value, in the format 0xRRGGBB.
  70844. */
  70845. RGBArrayToHex: function (rgb) {
  70846. return ((rgb[0] * 255 << 16) + (rgb[1] * 255 << 8) + rgb[2] * 255);
  70847. },
  70848. /**
  70849. * Converts an RGB color value to HSL (hue, saturation and lightness).
  70850. * Conversion forumla from http://en.wikipedia.org/wiki/HSL_color_space.
  70851. * Assumes RGB values are contained in the set [0, 255] and returns h, s and l in the set [0, 1].
  70852. * Based on code by Michael Jackson (https://github.com/mjijackson)
  70853. *
  70854. * @method Phaser.Color.RGBtoHSL
  70855. * @static
  70856. * @param {number} r - The red color component, in the range 0 - 255.
  70857. * @param {number} g - The green color component, in the range 0 - 255.
  70858. * @param {number} b - The blue color component, in the range 0 - 255.
  70859. * @param {object} [out] - An object into which 3 properties will be created, h, s and l. If not provided a new object will be created.
  70860. * @return {object} An object with the hue, saturation and lightness values set in the h, s and l properties.
  70861. */
  70862. RGBtoHSL: function (r, g, b, out) {
  70863. if (!out)
  70864. {
  70865. out = Phaser.Color.createColor(r, g, b, 1);
  70866. }
  70867. r /= 255;
  70868. g /= 255;
  70869. b /= 255;
  70870. var min = Math.min(r, g, b);
  70871. var max = Math.max(r, g, b);
  70872. // achromatic by default
  70873. out.h = 0;
  70874. out.s = 0;
  70875. out.l = (max + min) / 2;
  70876. if (max !== min)
  70877. {
  70878. var d = max - min;
  70879. out.s = out.l > 0.5 ? d / (2 - max - min) : d / (max + min);
  70880. if (max === r)
  70881. {
  70882. out.h = (g - b) / d + (g < b ? 6 : 0);
  70883. }
  70884. else if (max === g)
  70885. {
  70886. out.h = (b - r) / d + 2;
  70887. }
  70888. else if (max === b)
  70889. {
  70890. out.h = (r - g) / d + 4;
  70891. }
  70892. out.h /= 6;
  70893. }
  70894. return out;
  70895. },
  70896. /**
  70897. * Converts an HSL (hue, saturation and lightness) color value to RGB.
  70898. * Conversion forumla from http://en.wikipedia.org/wiki/HSL_color_space.
  70899. * Assumes HSL values are contained in the set [0, 1] and returns r, g and b values in the set [0, 255].
  70900. * Based on code by Michael Jackson (https://github.com/mjijackson)
  70901. *
  70902. * @method Phaser.Color.HSLtoRGB
  70903. * @static
  70904. * @param {number} h - The hue, in the range 0 - 1.
  70905. * @param {number} s - The saturation, in the range 0 - 1.
  70906. * @param {number} l - The lightness, in the range 0 - 1.
  70907. * @param {object} [out] - An object into which 3 properties will be created: r, g and b. If not provided a new object will be created.
  70908. * @return {object} An object with the red, green and blue values set in the r, g and b properties.
  70909. */
  70910. HSLtoRGB: function (h, s, l, out) {
  70911. if (!out)
  70912. {
  70913. out = Phaser.Color.createColor(l, l, l);
  70914. }
  70915. else
  70916. {
  70917. // achromatic by default
  70918. out.r = l;
  70919. out.g = l;
  70920. out.b = l;
  70921. }
  70922. if (s !== 0)
  70923. {
  70924. var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  70925. var p = 2 * l - q;
  70926. out.r = Phaser.Color.hueToColor(p, q, h + 1 / 3);
  70927. out.g = Phaser.Color.hueToColor(p, q, h);
  70928. out.b = Phaser.Color.hueToColor(p, q, h - 1 / 3);
  70929. }
  70930. // out.r = (out.r * 255 | 0);
  70931. // out.g = (out.g * 255 | 0);
  70932. // out.b = (out.b * 255 | 0);
  70933. out.r = Math.floor((out.r * 255 | 0));
  70934. out.g = Math.floor((out.g * 255 | 0));
  70935. out.b = Math.floor((out.b * 255 | 0));
  70936. Phaser.Color.updateColor(out);
  70937. return out;
  70938. },
  70939. /**
  70940. * Converts an RGB color value to HSV (hue, saturation and value).
  70941. * Conversion forumla from http://en.wikipedia.org/wiki/HSL_color_space.
  70942. * Assumes RGB values are contained in the set [0, 255] and returns h, s and v in the set [0, 1].
  70943. * Based on code by Michael Jackson (https://github.com/mjijackson)
  70944. *
  70945. * @method Phaser.Color.RGBtoHSV
  70946. * @static
  70947. * @param {number} r - The red color component, in the range 0 - 255.
  70948. * @param {number} g - The green color component, in the range 0 - 255.
  70949. * @param {number} b - The blue color component, in the range 0 - 255.
  70950. * @param {object} [out] - An object into which 3 properties will be created, h, s and v. If not provided a new object will be created.
  70951. * @return {object} An object with the hue, saturation and value set in the h, s and v properties.
  70952. */
  70953. RGBtoHSV: function (r, g, b, out) {
  70954. if (!out)
  70955. {
  70956. out = Phaser.Color.createColor(r, g, b, 255);
  70957. }
  70958. r /= 255;
  70959. g /= 255;
  70960. b /= 255;
  70961. var min = Math.min(r, g, b);
  70962. var max = Math.max(r, g, b);
  70963. var d = max - min;
  70964. // achromatic by default
  70965. out.h = 0;
  70966. out.s = max === 0 ? 0 : d / max;
  70967. out.v = max;
  70968. if (max !== min)
  70969. {
  70970. if (max === r)
  70971. {
  70972. out.h = (g - b) / d + (g < b ? 6 : 0);
  70973. }
  70974. else if (max === g)
  70975. {
  70976. out.h = (b - r) / d + 2;
  70977. }
  70978. else if (max === b)
  70979. {
  70980. out.h = (r - g) / d + 4;
  70981. }
  70982. out.h /= 6;
  70983. }
  70984. return out;
  70985. },
  70986. /**
  70987. * Converts an HSV (hue, saturation and value) color value to RGB.
  70988. * Conversion forumla from http://en.wikipedia.org/wiki/HSL_color_space.
  70989. * Assumes HSV values are contained in the set [0, 1] and returns r, g and b values in the set [0, 255].
  70990. * Based on code by Michael Jackson (https://github.com/mjijackson)
  70991. *
  70992. * @method Phaser.Color.HSVtoRGB
  70993. * @static
  70994. * @param {number} h - The hue, in the range 0 - 1.
  70995. * @param {number} s - The saturation, in the range 0 - 1.
  70996. * @param {number} v - The value, in the range 0 - 1.
  70997. * @param {object} [out] - An object into which 3 properties will be created: r, g and b. If not provided a new object will be created.
  70998. * @return {object} An object with the red, green and blue values set in the r, g and b properties.
  70999. */
  71000. HSVtoRGB: function (h, s, v, out) {
  71001. if (out === undefined) { out = Phaser.Color.createColor(0, 0, 0, 1, h, s, 0, v); }
  71002. var r, g, b;
  71003. var i = Math.floor(h * 6);
  71004. var f = h * 6 - i;
  71005. var p = v * (1 - s);
  71006. var q = v * (1 - f * s);
  71007. var t = v * (1 - (1 - f) * s);
  71008. switch (i % 6)
  71009. {
  71010. case 0:
  71011. r = v;
  71012. g = t;
  71013. b = p;
  71014. break;
  71015. case 1:
  71016. r = q;
  71017. g = v;
  71018. b = p;
  71019. break;
  71020. case 2:
  71021. r = p;
  71022. g = v;
  71023. b = t;
  71024. break;
  71025. case 3:
  71026. r = p;
  71027. g = q;
  71028. b = v;
  71029. break;
  71030. case 4:
  71031. r = t;
  71032. g = p;
  71033. b = v;
  71034. break;
  71035. case 5:
  71036. r = v;
  71037. g = p;
  71038. b = q;
  71039. break;
  71040. }
  71041. out.r = Math.floor(r * 255);
  71042. out.g = Math.floor(g * 255);
  71043. out.b = Math.floor(b * 255);
  71044. Phaser.Color.updateColor(out);
  71045. return out;
  71046. },
  71047. /**
  71048. * Converts a hue to an RGB color.
  71049. * Based on code by Michael Jackson (https://github.com/mjijackson)
  71050. *
  71051. * @method Phaser.Color.hueToColor
  71052. * @static
  71053. * @param {number} p
  71054. * @param {number} q
  71055. * @param {number} t
  71056. * @return {number} The color component value.
  71057. */
  71058. hueToColor: function (p, q, t) {
  71059. if (t < 0)
  71060. {
  71061. t += 1;
  71062. }
  71063. if (t > 1)
  71064. {
  71065. t -= 1;
  71066. }
  71067. if (t < 1 / 6)
  71068. {
  71069. return p + (q - p) * 6 * t;
  71070. }
  71071. if (t < 1 / 2)
  71072. {
  71073. return q;
  71074. }
  71075. if (t < 2 / 3)
  71076. {
  71077. return p + (q - p) * (2 / 3 - t) * 6;
  71078. }
  71079. return p;
  71080. },
  71081. /**
  71082. * A utility function to create a lightweight 'color' object with the default components.
  71083. * Any components that are not specified will default to zero.
  71084. *
  71085. * This is useful when you want to use a shared color object for the getPixel and getPixelAt methods.
  71086. *
  71087. * @author Matt DesLauriers (@mattdesl)
  71088. * @method Phaser.Color.createColor
  71089. * @static
  71090. * @param {number} [r=0] - The red color component, in the range 0 - 255.
  71091. * @param {number} [g=0] - The green color component, in the range 0 - 255.
  71092. * @param {number} [b=0] - The blue color component, in the range 0 - 255.
  71093. * @param {number} [a=1] - The alpha color component, in the range 0 - 1.
  71094. * @param {number} [h=0] - The hue, in the range 0 - 1.
  71095. * @param {number} [s=0] - The saturation, in the range 0 - 1.
  71096. * @param {number} [l=0] - The lightness, in the range 0 - 1.
  71097. * @param {number} [v=0] - The value, in the range 0 - 1.
  71098. * @return {object} The resulting object with r, g, b, a properties and h, s, l and v.
  71099. */
  71100. createColor: function (r, g, b, a, h, s, l, v) {
  71101. var out = { r: r || 0, g: g || 0, b: b || 0, a: a || 1, h: h || 0, s: s || 0, l: l || 0, v: v || 0, color: 0, color32: 0, rgba: '' };
  71102. return Phaser.Color.updateColor(out);
  71103. },
  71104. /**
  71105. * Takes a color object and updates the rgba, color and color32 properties.
  71106. *
  71107. * @method Phaser.Color.updateColor
  71108. * @static
  71109. * @param {object} out - The color object to update.
  71110. * @returns {number} A native color value integer (format: 0xAARRGGBB).
  71111. */
  71112. updateColor: function (out) {
  71113. out.rgba = 'rgba(' + out.r.toFixed() + ',' + out.g.toFixed() + ',' + out.b.toFixed() + ',' + out.a.toString() + ')';
  71114. out.color = Phaser.Color.getColor(out.r, out.g, out.b);
  71115. out.color32 = Phaser.Color.getColor32(out.a * 255, out.r, out.g, out.b);
  71116. return out;
  71117. },
  71118. /**
  71119. * Given an alpha and 3 color values this will return an integer representation of it.
  71120. *
  71121. * @method Phaser.Color.getColor32
  71122. * @static
  71123. * @param {number} a - The alpha color component, in the range 0 - 255.
  71124. * @param {number} r - The red color component, in the range 0 - 255.
  71125. * @param {number} g - The green color component, in the range 0 - 255.
  71126. * @param {number} b - The blue color component, in the range 0 - 255.
  71127. * @returns {number} A native color value integer (format: 0xAARRGGBB).
  71128. */
  71129. getColor32: function (a, r, g, b) {
  71130. return a << 24 | r << 16 | g << 8 | b;
  71131. },
  71132. /**
  71133. * Given 3 color values this will return an integer representation of it.
  71134. *
  71135. * @method Phaser.Color.getColor
  71136. * @static
  71137. * @param {number} r - The red color component, in the range 0 - 255.
  71138. * @param {number} g - The green color component, in the range 0 - 255.
  71139. * @param {number} b - The blue color component, in the range 0 - 255.
  71140. * @returns {number} A native color value integer (format: 0xRRGGBB).
  71141. */
  71142. getColor: function (r, g, b) {
  71143. return r << 16 | g << 8 | b;
  71144. },
  71145. /**
  71146. * Converts the given color values into a string.
  71147. * If prefix was '#' it will be in the format `#RRGGBB` otherwise `0xAARRGGBB`.
  71148. *
  71149. * @method Phaser.Color.RGBtoString
  71150. * @static
  71151. * @param {number} r - The red color component, in the range 0 - 255.
  71152. * @param {number} g - The green color component, in the range 0 - 255.
  71153. * @param {number} b - The blue color component, in the range 0 - 255.
  71154. * @param {number} [a=255] - The alpha color component, in the range 0 - 255.
  71155. * @param {string} [prefix='#'] - The prefix used in the return string. If '#' it will return `#RRGGBB`, else `0xAARRGGBB`.
  71156. * @return {string} A string containing the color values. If prefix was '#' it will be in the format `#RRGGBB` otherwise `0xAARRGGBB`.
  71157. */
  71158. RGBtoString: function (r, g, b, a, prefix) {
  71159. if (a === undefined) { a = 255; }
  71160. if (prefix === undefined) { prefix = '#'; }
  71161. if (prefix === '#')
  71162. {
  71163. return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
  71164. }
  71165. else
  71166. {
  71167. return '0x' + Phaser.Color.componentToHex(a) + Phaser.Color.componentToHex(r) + Phaser.Color.componentToHex(g) + Phaser.Color.componentToHex(b);
  71168. }
  71169. },
  71170. /**
  71171. * Converts a hex string into an integer color value.
  71172. *
  71173. * @method Phaser.Color.hexToRGB
  71174. * @static
  71175. * @param {string} hex - The hex string to convert. Can be in the short-hand format `#03f` or `#0033ff`.
  71176. * @return {number} The rgb color value in the format 0xAARRGGBB.
  71177. */
  71178. hexToRGB: function (hex) {
  71179. var rgb = Phaser.Color.hexToColor(hex);
  71180. if (rgb)
  71181. {
  71182. return Phaser.Color.getColor32(rgb.a, rgb.r, rgb.g, rgb.b);
  71183. }
  71184. },
  71185. /**
  71186. * Converts a hex string into a Phaser Color object.
  71187. *
  71188. * The hex string can supplied as `'#0033ff'` or the short-hand format of `'#03f'`; it can begin with an optional "#" or "0x", or be unprefixed.
  71189. *
  71190. * An alpha channel is _not_ supported.
  71191. *
  71192. * @method Phaser.Color.hexToColor
  71193. * @static
  71194. * @param {string} hex - The color string in a hex format.
  71195. * @param {object} [out] - An object into which 3 properties will be created or set: r, g and b. If not provided a new object will be created.
  71196. * @return {object} An object with the red, green and blue values set in the r, g and b properties.
  71197. */
  71198. hexToColor: function (hex, out) {
  71199. // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
  71200. hex = hex.replace(/^(?:#|0x)?([a-f\d])([a-f\d])([a-f\d])$/i, function(m, r, g, b) {
  71201. return r + r + g + g + b + b;
  71202. });
  71203. var result = /^(?:#|0x)?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  71204. if (result)
  71205. {
  71206. var r = parseInt(result[1], 16);
  71207. var g = parseInt(result[2], 16);
  71208. var b = parseInt(result[3], 16);
  71209. if (!out)
  71210. {
  71211. out = Phaser.Color.createColor(r, g, b);
  71212. }
  71213. else
  71214. {
  71215. out.r = r;
  71216. out.g = g;
  71217. out.b = b;
  71218. }
  71219. }
  71220. return out;
  71221. },
  71222. /**
  71223. * Converts a CSS 'web' string into a Phaser Color object.
  71224. *
  71225. * The web string can be in the format `'rgb(r,g,b)'` or `'rgba(r,g,b,a)'` where r/g/b are in the range [0..255] and a is in the range [0..1].
  71226. *
  71227. * @method Phaser.Color.webToColor
  71228. * @static
  71229. * @param {string} web - The color string in CSS 'web' format.
  71230. * @param {object} [out] - An object into which 4 properties will be created: r, g, b and a. If not provided a new object will be created.
  71231. * @return {object} An object with the red, green, blue and alpha values set in the r, g, b and a properties.
  71232. */
  71233. webToColor: function (web, out) {
  71234. if (!out)
  71235. {
  71236. out = Phaser.Color.createColor();
  71237. }
  71238. var result = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d+(?:\.\d+)?))?\s*\)$/.exec(web);
  71239. if (result)
  71240. {
  71241. out.r = parseInt(result[1], 10);
  71242. out.g = parseInt(result[2], 10);
  71243. out.b = parseInt(result[3], 10);
  71244. out.a = result[4] !== undefined ? parseFloat(result[4]) : 1;
  71245. Phaser.Color.updateColor(out);
  71246. }
  71247. return out;
  71248. },
  71249. /**
  71250. * Converts a value - a "hex" string, a "CSS 'web' string", or a number - into red, green, blue, and alpha components.
  71251. *
  71252. * The value can be a string (see `hexToColor` and `webToColor` for the supported formats) or a packed integer (see `getRGB`).
  71253. *
  71254. * An alpha channel is _not_ supported when specifying a hex string.
  71255. *
  71256. * @method Phaser.Color.valueToColor
  71257. * @static
  71258. * @param {string|number} value - The color expressed as a recognized string format or a packed integer.
  71259. * @param {object} [out] - The object to use for the output. If not provided a new object will be created.
  71260. * @return {object} The (`out`) object with the red, green, blue, and alpha values set as the r/g/b/a properties.
  71261. */
  71262. valueToColor: function (value, out) {
  71263. // The behavior is not consistent between hexToColor/webToColor on invalid input.
  71264. // This unifies both by returning a new object, but returning null may be better.
  71265. if (!out)
  71266. {
  71267. out = Phaser.Color.createColor();
  71268. }
  71269. if (typeof value === 'string')
  71270. {
  71271. if (value.indexOf('rgb') === 0)
  71272. {
  71273. return Phaser.Color.webToColor(value, out);
  71274. }
  71275. else
  71276. {
  71277. // `hexToColor` does not support alpha; match `createColor`.
  71278. out.a = 1;
  71279. return Phaser.Color.hexToColor(value, out);
  71280. }
  71281. }
  71282. else if (typeof value === 'number')
  71283. {
  71284. // `getRGB` does not take optional object to modify;
  71285. // alpha is also adjusted to match `createColor`.
  71286. var tempColor = Phaser.Color.getRGB(value);
  71287. out.r = tempColor.r;
  71288. out.g = tempColor.g;
  71289. out.b = tempColor.b;
  71290. out.a = tempColor.a / 255;
  71291. return out;
  71292. }
  71293. else
  71294. {
  71295. return out;
  71296. }
  71297. },
  71298. /**
  71299. * Return a string containing a hex representation of the given color component.
  71300. *
  71301. * @method Phaser.Color.componentToHex
  71302. * @static
  71303. * @param {number} color - The color channel to get the hex value for, must be a value between 0 and 255.
  71304. * @returns {string} A string of length 2 characters, i.e. 255 = ff, 100 = 64.
  71305. */
  71306. componentToHex: function (color) {
  71307. var hex = color.toString(16);
  71308. return (hex.length === 1) ? '0' + hex : hex;
  71309. },
  71310. /**
  71311. * Get HSV color wheel values in an array which will be 360 elements in size.
  71312. *
  71313. * @method Phaser.Color.HSVColorWheel
  71314. * @static
  71315. * @param {number} [s=1] - The saturation, in the range 0 - 1.
  71316. * @param {number} [v=1] - The value, in the range 0 - 1.
  71317. * @return {array} An array containing 360 elements corresponding to the HSV color wheel.
  71318. */
  71319. HSVColorWheel: function (s, v) {
  71320. if (s === undefined) { s = 1.0; }
  71321. if (v === undefined) { v = 1.0; }
  71322. var colors = [];
  71323. for (var c = 0; c <= 359; c++)
  71324. {
  71325. colors.push(Phaser.Color.HSVtoRGB(c / 359, s, v));
  71326. }
  71327. return colors;
  71328. },
  71329. /**
  71330. * Get HSL color wheel values in an array which will be 360 elements in size.
  71331. *
  71332. * @method Phaser.Color.HSLColorWheel
  71333. * @static
  71334. * @param {number} [s=0.5] - The saturation, in the range 0 - 1.
  71335. * @param {number} [l=0.5] - The lightness, in the range 0 - 1.
  71336. * @return {array} An array containing 360 elements corresponding to the HSL color wheel.
  71337. */
  71338. HSLColorWheel: function (s, l) {
  71339. if (s === undefined) { s = 0.5; }
  71340. if (l === undefined) { l = 0.5; }
  71341. var colors = [];
  71342. for (var c = 0; c <= 359; c++)
  71343. {
  71344. colors.push(Phaser.Color.HSLtoRGB(c / 359, s, l));
  71345. }
  71346. return colors;
  71347. },
  71348. /**
  71349. * Interpolates the two given colours based on the supplied step and currentStep properties.
  71350. *
  71351. * @method Phaser.Color.interpolateColor
  71352. * @static
  71353. * @param {number} color1 - The first color value.
  71354. * @param {number} color2 - The second color value.
  71355. * @param {number} steps - The number of steps to run the interpolation over.
  71356. * @param {number} currentStep - The currentStep value. If the interpolation will take 100 steps, a currentStep value of 50 would be half-way between the two.
  71357. * @param {number} [alpha] - The alpha of the returned color.
  71358. * @param {number} [colorSpace=0] - The color space to interpolate in. 0 = RGB, 1 = HSV.
  71359. * @returns {number} The interpolated color value.
  71360. */
  71361. interpolateColor: function (color1, color2, steps, currentStep, alpha, colorSpace) {
  71362. if (alpha === undefined) { alpha = 255; }
  71363. if (colorSpace === undefined) { colorSpace = 0; }
  71364. var src1 = Phaser.Color.getRGB(color1);
  71365. var src2 = Phaser.Color.getRGB(color2);
  71366. if (colorSpace === 0)
  71367. {
  71368. var r = (((src2.red - src1.red) * currentStep) / steps) + src1.red;
  71369. var g = (((src2.green - src1.green) * currentStep) / steps) + src1.green;
  71370. var b = (((src2.blue - src1.blue) * currentStep) / steps) + src1.blue;
  71371. }
  71372. if (colorSpace === 1)
  71373. {
  71374. var hsv1 = Phaser.Color.RGBtoHSV(src1.r, src1.g, src1.b);
  71375. var hsv2 = Phaser.Color.RGBtoHSV(src2.r, src2.g, src2.b);
  71376. var dh = hsv2.h - hsv1.h;
  71377. var h;
  71378. if (hsv1.h > hsv2.h)
  71379. {
  71380. var h3 = hsv2.h;
  71381. hsv2.h = hsv1.h;
  71382. hsv1.h = h3;
  71383. dh = -dh;
  71384. currentStep = steps - currentStep;
  71385. }
  71386. if (dh > 0.5)
  71387. {
  71388. hsv1.h = hsv1.h + 1;
  71389. h = (((hsv2.h - hsv1.h) * currentStep / steps) + hsv1.h) % 1;
  71390. }
  71391. if (dh <= 0.5)
  71392. {
  71393. h = ((hsv2.h - hsv1.h) * currentStep / steps) + hsv1.h;
  71394. }
  71395. var s = (((hsv2.s - hsv1.s) * currentStep) / steps) + hsv1.s;
  71396. var v = (((hsv2.v - hsv1.v) * currentStep) / steps) + hsv1.v;
  71397. var rgb = Phaser.Color.HSVtoRGB(h, s, v, rgb);
  71398. var r = rgb.r;
  71399. var g = rgb.g;
  71400. var b = rgb.b;
  71401. }
  71402. return Phaser.Color.getColor32(alpha, r, g, b);
  71403. },
  71404. /**
  71405. * Interpolates the two given colours based on the supplied step and currentStep properties.
  71406. *
  71407. * @method Phaser.Color.interpolateColorWithRGB
  71408. * @static
  71409. * @param {number} color - The first color value.
  71410. * @param {number} r - The red color value, between 0 and 0xFF (255).
  71411. * @param {number} g - The green color value, between 0 and 0xFF (255).
  71412. * @param {number} b - The blue color value, between 0 and 0xFF (255).
  71413. * @param {number} steps - The number of steps to run the interpolation over.
  71414. * @param {number} currentStep - The currentStep value. If the interpolation will take 100 steps, a currentStep value of 50 would be half-way between the two.
  71415. * @returns {number} The interpolated color value.
  71416. */
  71417. interpolateColorWithRGB: function (color, r, g, b, steps, currentStep) {
  71418. var src = Phaser.Color.getRGB(color);
  71419. var or = (((r - src.red) * currentStep) / steps) + src.red;
  71420. var og = (((g - src.green) * currentStep) / steps) + src.green;
  71421. var ob = (((b - src.blue) * currentStep) / steps) + src.blue;
  71422. return Phaser.Color.getColor(or, og, ob);
  71423. },
  71424. /**
  71425. * Interpolates the two given colours based on the supplied step and currentStep properties.
  71426. * @method Phaser.Color.interpolateRGB
  71427. * @static
  71428. * @param {number} r1 - The red color value, between 0 and 0xFF (255).
  71429. * @param {number} g1 - The green color value, between 0 and 0xFF (255).
  71430. * @param {number} b1 - The blue color value, between 0 and 0xFF (255).
  71431. * @param {number} r2 - The red color value, between 0 and 0xFF (255).
  71432. * @param {number} g2 - The green color value, between 0 and 0xFF (255).
  71433. * @param {number} b2 - The blue color value, between 0 and 0xFF (255).
  71434. * @param {number} steps - The number of steps to run the interpolation over.
  71435. * @param {number} currentStep - The currentStep value. If the interpolation will take 100 steps, a currentStep value of 50 would be half-way between the two.
  71436. * @returns {number} The interpolated color value.
  71437. */
  71438. interpolateRGB: function (r1, g1, b1, r2, g2, b2, steps, currentStep) {
  71439. var r = (((r2 - r1) * currentStep) / steps) + r1;
  71440. var g = (((g2 - g1) * currentStep) / steps) + g1;
  71441. var b = (((b2 - b1) * currentStep) / steps) + b1;
  71442. return Phaser.Color.getColor(r, g, b);
  71443. },
  71444. /**
  71445. * Calculates a linear (interpolation) value of two colors over t.
  71446. *
  71447. * This is a slightly simpler interface to {@link Phaser.Color.interpolateColor}.
  71448. *
  71449. * The arguments are similar to {@link Phaser.Math.linear}.
  71450. *
  71451. * @method Phaser.Color.linear
  71452. * @param {number} color1 - The first color value.
  71453. * @param {number} color2 - The second color value.
  71454. * @param {number} t - A value between 0 and 1.
  71455. * @return {number} The interpolated color value.
  71456. */
  71457. linear: function (color1, color2, t) {
  71458. return this.interpolateColor(color1, color2, 1, t);
  71459. },
  71460. /**
  71461. * Calculates a linear (interpolation) value of an array of colors over t.
  71462. *
  71463. * The arguments are similar to {@link Phaser.Math.linearInterpolation}.
  71464. *
  71465. * This can be used as a {@link Phaser.TweenData#interpolationFunction}.
  71466. *
  71467. * @method Phaser.Color.linearInterpolation
  71468. * @param {number[]} colors - The input array of color values to interpolate between.
  71469. * @param {number} t - A value between 0 and 1.
  71470. * @return {number} The interpolated color value.
  71471. */
  71472. linearInterpolation: function (colors, t) {
  71473. var k = Phaser.Math.linear(0, colors.length - 1, t);
  71474. var color1 = colors[ Math.floor(k) ];
  71475. var color2 = colors[ Math.ceil(k)] ;
  71476. return this.linear(color1, color2, k % 1);
  71477. },
  71478. /**
  71479. * Returns a random color value between black and white
  71480. * Set the min value to start each channel from the given offset.
  71481. * Set the max value to restrict the maximum color used per channel.
  71482. *
  71483. * @method Phaser.Color.getRandomColor
  71484. * @static
  71485. * @param {number} [min=0] - The lowest value to use for the color.
  71486. * @param {number} [max=255] - The highest value to use for the color.
  71487. * @param {number} [alpha=255] - The alpha value of the returning color (default 255 = fully opaque).
  71488. * @returns {number} 32-bit color value with alpha.
  71489. */
  71490. getRandomColor: function (min, max, alpha) {
  71491. if (min === undefined) { min = 0; }
  71492. if (max === undefined) { max = 255; }
  71493. if (alpha === undefined) { alpha = 255; }
  71494. // Sanity checks
  71495. if (max > 255 || min > max)
  71496. {
  71497. return Phaser.Color.getColor(255, 255, 255);
  71498. }
  71499. var red = min + Math.round(Math.random() * (max - min));
  71500. var green = min + Math.round(Math.random() * (max - min));
  71501. var blue = min + Math.round(Math.random() * (max - min));
  71502. return Phaser.Color.getColor32(alpha, red, green, blue);
  71503. },
  71504. /**
  71505. * Return the component parts of a color as an Object with the properties alpha, red, green, blue.
  71506. *
  71507. * Alpha will only be set if it exist in the given color (0xAARRGGBB)
  71508. *
  71509. * @method Phaser.Color.getRGB
  71510. * @static
  71511. * @param {number} color - Color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB).
  71512. * @returns {object} An Object with properties: alpha, red, green, blue (also r, g, b and a). Alpha will only be present if a color value > 16777215 was given.
  71513. */
  71514. getRGB: function (color) {
  71515. if (color > 16777215)
  71516. {
  71517. // The color value has an alpha component
  71518. return {
  71519. alpha: color >>> 24,
  71520. red: color >> 16 & 0xFF,
  71521. green: color >> 8 & 0xFF,
  71522. blue: color & 0xFF,
  71523. a: color >>> 24,
  71524. r: color >> 16 & 0xFF,
  71525. g: color >> 8 & 0xFF,
  71526. b: color & 0xFF
  71527. };
  71528. }
  71529. else
  71530. {
  71531. return {
  71532. alpha: 255,
  71533. red: color >> 16 & 0xFF,
  71534. green: color >> 8 & 0xFF,
  71535. blue: color & 0xFF,
  71536. a: 255,
  71537. r: color >> 16 & 0xFF,
  71538. g: color >> 8 & 0xFF,
  71539. b: color & 0xFF
  71540. };
  71541. }
  71542. },
  71543. /**
  71544. * Returns a CSS friendly string value from the given color.
  71545. *
  71546. * @method Phaser.Color.getWebRGB
  71547. * @static
  71548. * @param {number|Object} color - Color in RGB (0xRRGGBB), ARGB format (0xAARRGGBB) or an Object with r, g, b, a properties.
  71549. * @returns {string} A string in the format: 'rgba(r,g,b,a)'
  71550. */
  71551. getWebRGB: function (color) {
  71552. if (typeof color === 'object')
  71553. {
  71554. return 'rgba(' + color.r.toString() + ',' + color.g.toString() + ',' + color.b.toString() + ',' + (color.a / 255).toString() + ')';
  71555. }
  71556. else
  71557. {
  71558. var rgb = Phaser.Color.getRGB(color);
  71559. return 'rgba(' + rgb.r.toString() + ',' + rgb.g.toString() + ',' + rgb.b.toString() + ',' + (rgb.a / 255).toString() + ')';
  71560. }
  71561. },
  71562. /**
  71563. * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255.
  71564. *
  71565. * @method Phaser.Color.getAlpha
  71566. * @static
  71567. * @param {number} color - In the format 0xAARRGGBB.
  71568. * @returns {number} The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)).
  71569. */
  71570. getAlpha: function (color) {
  71571. return color >>> 24;
  71572. },
  71573. /**
  71574. * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1.
  71575. *
  71576. * @method Phaser.Color.getAlphaFloat
  71577. * @static
  71578. * @param {number} color - In the format 0xAARRGGBB.
  71579. * @returns {number} The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)).
  71580. */
  71581. getAlphaFloat: function (color) {
  71582. return (color >>> 24) / 255;
  71583. },
  71584. /**
  71585. * Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255.
  71586. *
  71587. * @method Phaser.Color.getRed
  71588. * @static
  71589. * @param {number} color In the format 0xAARRGGBB.
  71590. * @returns {number} The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red).
  71591. */
  71592. getRed: function (color) {
  71593. return color >> 16 & 0xFF;
  71594. },
  71595. /**
  71596. * Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255.
  71597. *
  71598. * @method Phaser.Color.getGreen
  71599. * @static
  71600. * @param {number} color - In the format 0xAARRGGBB.
  71601. * @returns {number} The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green).
  71602. */
  71603. getGreen: function (color) {
  71604. return color >> 8 & 0xFF;
  71605. },
  71606. /**
  71607. * Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255.
  71608. *
  71609. * @method Phaser.Color.getBlue
  71610. * @static
  71611. * @param {number} color - In the format 0xAARRGGBB.
  71612. * @returns {number} The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue).
  71613. */
  71614. getBlue: function (color) {
  71615. return color & 0xFF;
  71616. },
  71617. /**
  71618. * Blends the source color, ignoring the backdrop.
  71619. *
  71620. * @method Phaser.Color.blendNormal
  71621. * @static
  71622. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71623. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71624. * @returns {integer} The blended color value, in the range 1 to 255.
  71625. */
  71626. blendNormal: function (a) {
  71627. return a;
  71628. },
  71629. /**
  71630. * Selects the lighter of the backdrop and source colors.
  71631. *
  71632. * @method Phaser.Color.blendLighten
  71633. * @static
  71634. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71635. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71636. * @returns {integer} The blended color value, in the range 1 to 255.
  71637. */
  71638. blendLighten: function (a, b) {
  71639. return (b > a) ? b : a;
  71640. },
  71641. /**
  71642. * Selects the darker of the backdrop and source colors.
  71643. *
  71644. * @method Phaser.Color.blendDarken
  71645. * @static
  71646. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71647. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71648. * @returns {integer} The blended color value, in the range 1 to 255.
  71649. */
  71650. blendDarken: function (a, b) {
  71651. return (b > a) ? a : b;
  71652. },
  71653. /**
  71654. * Multiplies the backdrop and source color values.
  71655. * The result color is always at least as dark as either of the two constituent
  71656. * colors. Multiplying any color with black produces black;
  71657. * multiplying with white leaves the original color unchanged.
  71658. *
  71659. * @method Phaser.Color.blendMultiply
  71660. * @static
  71661. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71662. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71663. * @returns {integer} The blended color value, in the range 1 to 255.
  71664. */
  71665. blendMultiply: function (a, b) {
  71666. return (a * b) / 255;
  71667. },
  71668. /**
  71669. * Takes the average of the source and backdrop colors.
  71670. *
  71671. * @method Phaser.Color.blendAverage
  71672. * @static
  71673. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71674. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71675. * @returns {integer} The blended color value, in the range 1 to 255.
  71676. */
  71677. blendAverage: function (a, b) {
  71678. return (a + b) / 2;
  71679. },
  71680. /**
  71681. * Adds the source and backdrop colors together and returns the value, up to a maximum of 255.
  71682. *
  71683. * @method Phaser.Color.blendAdd
  71684. * @static
  71685. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71686. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71687. * @returns {integer} The blended color value, in the range 1 to 255.
  71688. */
  71689. blendAdd: function (a, b) {
  71690. return Math.min(255, a + b);
  71691. },
  71692. /**
  71693. * Combines the source and backdrop colors and returns their value minus 255.
  71694. *
  71695. * @method Phaser.Color.blendSubtract
  71696. * @static
  71697. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71698. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71699. * @returns {integer} The blended color value, in the range 1 to 255.
  71700. */
  71701. blendSubtract: function (a, b) {
  71702. return Math.max(0, a + b - 255);
  71703. },
  71704. /**
  71705. * Subtracts the darker of the two constituent colors from the lighter.
  71706. *
  71707. * Painting with white inverts the backdrop color; painting with black produces no change.
  71708. *
  71709. * @method Phaser.Color.blendDifference
  71710. * @static
  71711. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71712. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71713. * @returns {integer} The blended color value, in the range 1 to 255.
  71714. */
  71715. blendDifference: function (a, b) {
  71716. return Math.abs(a - b);
  71717. },
  71718. /**
  71719. * Negation blend mode.
  71720. *
  71721. * @method Phaser.Color.blendNegation
  71722. * @static
  71723. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71724. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71725. * @returns {integer} The blended color value, in the range 1 to 255.
  71726. */
  71727. blendNegation: function (a, b) {
  71728. return 255 - Math.abs(255 - a - b);
  71729. },
  71730. /**
  71731. * Multiplies the complements of the backdrop and source color values, then complements the result.
  71732. * The result color is always at least as light as either of the two constituent colors.
  71733. * Screening any color with white produces white; screening with black leaves the original color unchanged.
  71734. *
  71735. * @method Phaser.Color.blendScreen
  71736. * @static
  71737. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71738. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71739. * @returns {integer} The blended color value, in the range 1 to 255.
  71740. */
  71741. blendScreen: function (a, b) {
  71742. return 255 - (((255 - a) * (255 - b)) >> 8);
  71743. },
  71744. /**
  71745. * Produces an effect similar to that of the Difference mode, but lower in contrast.
  71746. * Painting with white inverts the backdrop color; painting with black produces no change.
  71747. *
  71748. * @method Phaser.Color.blendExclusion
  71749. * @static
  71750. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71751. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71752. * @returns {integer} The blended color value, in the range 1 to 255.
  71753. */
  71754. blendExclusion: function (a, b) {
  71755. return a + b - 2 * a * b / 255;
  71756. },
  71757. /**
  71758. * Multiplies or screens the colors, depending on the backdrop color.
  71759. * Source colors overlay the backdrop while preserving its highlights and shadows.
  71760. * The backdrop color is not replaced, but is mixed with the source color to reflect the lightness or darkness of the backdrop.
  71761. *
  71762. * @method Phaser.Color.blendOverlay
  71763. * @static
  71764. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71765. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71766. * @returns {integer} The blended color value, in the range 1 to 255.
  71767. */
  71768. blendOverlay: function (a, b) {
  71769. return b < 128 ? (2 * a * b / 255) : (255 - 2 * (255 - a) * (255 - b) / 255);
  71770. },
  71771. /**
  71772. * Darkens or lightens the colors, depending on the source color value.
  71773. *
  71774. * If the source color is lighter than 0.5, the backdrop is lightened, as if it were dodged;
  71775. * this is useful for adding highlights to a scene.
  71776. *
  71777. * If the source color is darker than 0.5, the backdrop is darkened, as if it were burned in.
  71778. * The degree of lightening or darkening is proportional to the difference between the source color and 0.5;
  71779. * if it is equal to 0.5, the backdrop is unchanged.
  71780. *
  71781. * Painting with pure black or white produces a distinctly darker or lighter area, but does not result in pure black or white.
  71782. * The effect is similar to shining a diffused spotlight on the backdrop.
  71783. *
  71784. * @method Phaser.Color.blendSoftLight
  71785. * @static
  71786. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71787. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71788. * @returns {integer} The blended color value, in the range 1 to 255.
  71789. */
  71790. blendSoftLight: function (a, b) {
  71791. return b < 128 ? (2 * ((a >> 1) + 64)) * (b / 255) : 255 - (2 * (255 - ((a >> 1) + 64)) * (255 - b) / 255);
  71792. },
  71793. /**
  71794. * Multiplies or screens the colors, depending on the source color value.
  71795. *
  71796. * If the source color is lighter than 0.5, the backdrop is lightened, as if it were screened;
  71797. * this is useful for adding highlights to a scene.
  71798. *
  71799. * If the source color is darker than 0.5, the backdrop is darkened, as if it were multiplied;
  71800. * this is useful for adding shadows to a scene.
  71801. *
  71802. * The degree of lightening or darkening is proportional to the difference between the source color and 0.5;
  71803. * if it is equal to 0.5, the backdrop is unchanged.
  71804. *
  71805. * Painting with pure black or white produces pure black or white. The effect is similar to shining a harsh spotlight on the backdrop.
  71806. *
  71807. * @method Phaser.Color.blendHardLight
  71808. * @static
  71809. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71810. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71811. * @returns {integer} The blended color value, in the range 1 to 255.
  71812. */
  71813. blendHardLight: function (a, b) {
  71814. return Phaser.Color.blendOverlay(b, a);
  71815. },
  71816. /**
  71817. * Brightens the backdrop color to reflect the source color.
  71818. * Painting with black produces no change.
  71819. *
  71820. * @method Phaser.Color.blendColorDodge
  71821. * @static
  71822. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71823. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71824. * @returns {integer} The blended color value, in the range 1 to 255.
  71825. */
  71826. blendColorDodge: function (a, b) {
  71827. return b === 255 ? b : Math.min(255, ((a << 8) / (255 - b)));
  71828. },
  71829. /**
  71830. * Darkens the backdrop color to reflect the source color.
  71831. * Painting with white produces no change.
  71832. *
  71833. * @method Phaser.Color.blendColorBurn
  71834. * @static
  71835. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71836. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71837. * @returns {integer} The blended color value, in the range 1 to 255.
  71838. */
  71839. blendColorBurn: function (a, b) {
  71840. return b === 0 ? b : Math.max(0, (255 - ((255 - a) << 8) / b));
  71841. },
  71842. /**
  71843. * An alias for blendAdd, it simply sums the values of the two colors.
  71844. *
  71845. * @method Phaser.Color.blendLinearDodge
  71846. * @static
  71847. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71848. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71849. * @returns {integer} The blended color value, in the range 1 to 255.
  71850. */
  71851. blendLinearDodge: function (a, b) {
  71852. return Phaser.Color.blendAdd(a, b);
  71853. },
  71854. /**
  71855. * An alias for blendSubtract, it simply sums the values of the two colors and subtracts 255.
  71856. *
  71857. * @method Phaser.Color.blendLinearBurn
  71858. * @static
  71859. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71860. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71861. * @returns {integer} The blended color value, in the range 1 to 255.
  71862. */
  71863. blendLinearBurn: function (a, b) {
  71864. return Phaser.Color.blendSubtract(a, b);
  71865. },
  71866. /**
  71867. * This blend mode combines Linear Dodge and Linear Burn (rescaled so that neutral colors become middle gray).
  71868. * Dodge applies to values of top layer lighter than middle gray, and burn to darker values.
  71869. * The calculation simplifies to the sum of bottom layer and twice the top layer, subtract 128. The contrast decreases.
  71870. *
  71871. * @method Phaser.Color.blendLinearLight
  71872. * @static
  71873. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71874. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71875. * @returns {integer} The blended color value, in the range 1 to 255.
  71876. */
  71877. blendLinearLight: function (a, b) {
  71878. return b < 128 ? Phaser.Color.blendLinearBurn(a, 2 * b) : Phaser.Color.blendLinearDodge(a, (2 * (b - 128)));
  71879. },
  71880. /**
  71881. * This blend mode combines Color Dodge and Color Burn (rescaled so that neutral colors become middle gray).
  71882. * Dodge applies when values in the top layer are lighter than middle gray, and burn to darker values.
  71883. * The middle gray is the neutral color. When color is lighter than this, this effectively moves the white point of the bottom
  71884. * layer down by twice the difference; when it is darker, the black point is moved up by twice the difference. The perceived contrast increases.
  71885. *
  71886. * @method Phaser.Color.blendVividLight
  71887. * @static
  71888. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71889. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71890. * @returns {integer} The blended color value, in the range 1 to 255.
  71891. */
  71892. blendVividLight: function (a, b) {
  71893. return b < 128 ? Phaser.Color.blendColorBurn(a, 2 * b) : Phaser.Color.blendColorDodge(a, (2 * (b - 128)));
  71894. },
  71895. /**
  71896. * If the backdrop color (light source) is lighter than 50%, the blendDarken mode is used, and colors lighter than the backdrop color do not change.
  71897. * If the backdrop color is darker than 50% gray, colors lighter than the blend color are replaced, and colors darker than the blend color do not change.
  71898. *
  71899. * @method Phaser.Color.blendPinLight
  71900. * @static
  71901. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71902. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71903. * @returns {integer} The blended color value, in the range 1 to 255.
  71904. */
  71905. blendPinLight: function (a, b) {
  71906. return b < 128 ? Phaser.Color.blendDarken(a, 2 * b) : Phaser.Color.blendLighten(a, (2 * (b - 128)));
  71907. },
  71908. /**
  71909. * Runs blendVividLight on the source and backdrop colors.
  71910. * If the resulting color is 128 or more, it receives a value of 255; if less than 128, a value of 0.
  71911. * Therefore, all blended pixels have red, green, and blue channel values of either 0 or 255.
  71912. * This changes all pixels to primary additive colors (red, green, or blue), white, or black.
  71913. *
  71914. * @method Phaser.Color.blendHardMix
  71915. * @static
  71916. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71917. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71918. * @returns {integer} The blended color value, in the range 1 to 255.
  71919. */
  71920. blendHardMix: function (a, b) {
  71921. return Phaser.Color.blendVividLight(a, b) < 128 ? 0 : 255;
  71922. },
  71923. /**
  71924. * Reflect blend mode. This mode is useful when adding shining objects or light zones to images.
  71925. *
  71926. * @method Phaser.Color.blendReflect
  71927. * @static
  71928. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71929. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71930. * @returns {integer} The blended color value, in the range 1 to 255.
  71931. */
  71932. blendReflect: function (a, b) {
  71933. return b === 255 ? b : Math.min(255, (a * a / (255 - b)));
  71934. },
  71935. /**
  71936. * Glow blend mode. This mode is a variation of reflect mode with the source and backdrop colors swapped.
  71937. *
  71938. * @method Phaser.Color.blendGlow
  71939. * @static
  71940. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71941. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71942. * @returns {integer} The blended color value, in the range 1 to 255.
  71943. */
  71944. blendGlow: function (a, b) {
  71945. return Phaser.Color.blendReflect(b, a);
  71946. },
  71947. /**
  71948. * Phoenix blend mode. This subtracts the lighter color from the darker color, and adds 255, giving a bright result.
  71949. *
  71950. * @method Phaser.Color.blendPhoenix
  71951. * @static
  71952. * @param {integer} a - The source color to blend, in the range 1 to 255.
  71953. * @param {integer} b - The backdrop color to blend, in the range 1 to 255.
  71954. * @returns {integer} The blended color value, in the range 1 to 255.
  71955. */
  71956. blendPhoenix: function (a, b) {
  71957. return Math.min(a, b) - Math.max(a, b) + 255;
  71958. }
  71959. };
  71960. /**
  71961. * @author Richard Davey <rich@photonstorm.com>
  71962. * @copyright 2016 Photon Storm Ltd.
  71963. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  71964. */
  71965. /**
  71966. * The Physics Manager is responsible for looking after all of the running physics systems.
  71967. * Phaser supports 4 physics systems: Arcade Physics, P2, Ninja Physics and Box2D via a commercial plugin.
  71968. *
  71969. * Game Objects (such as Sprites) can only belong to 1 physics system, but you can have multiple systems active in a single game.
  71970. *
  71971. * For example you could have P2 managing a polygon-built terrain landscape that an vehicle drives over, while it could be firing bullets that use the
  71972. * faster (due to being much simpler) Arcade Physics system.
  71973. *
  71974. * @class Phaser.Physics
  71975. * @constructor
  71976. * @param {Phaser.Game} game - A reference to the currently running game.
  71977. * @param {object} [physicsConfig=null] - A physics configuration object to pass to the Physics world on creation.
  71978. */
  71979. Phaser.Physics = function (game, config) {
  71980. config = config || {};
  71981. /**
  71982. * @property {Phaser.Game} game - Local reference to game.
  71983. */
  71984. this.game = game;
  71985. /**
  71986. * @property {object} config - The physics configuration object as passed to the game on creation.
  71987. */
  71988. this.config = config;
  71989. /**
  71990. * @property {Phaser.Physics.Arcade} arcade - The Arcade Physics system.
  71991. */
  71992. this.arcade = null;
  71993. /**
  71994. * @property {Phaser.Physics.P2} p2 - The P2.JS Physics system.
  71995. */
  71996. this.p2 = null;
  71997. /**
  71998. * @property {Phaser.Physics.Ninja} ninja - The N+ Ninja Physics system.
  71999. */
  72000. this.ninja = null;
  72001. /**
  72002. * @property {Phaser.Physics.Box2D} box2d - The Box2D Physics system.
  72003. */
  72004. this.box2d = null;
  72005. /**
  72006. * @property {Phaser.Physics.Chipmunk} chipmunk - The Chipmunk Physics system (to be done).
  72007. */
  72008. this.chipmunk = null;
  72009. /**
  72010. * @property {Phaser.Physics.Matter} matter - The MatterJS Physics system (coming soon).
  72011. */
  72012. this.matter = null;
  72013. this.parseConfig();
  72014. };
  72015. /**
  72016. * @const
  72017. * @type {number}
  72018. */
  72019. Phaser.Physics.ARCADE = 0;
  72020. /**
  72021. * @const
  72022. * @type {number}
  72023. */
  72024. Phaser.Physics.P2JS = 1;
  72025. /**
  72026. * @const
  72027. * @type {number}
  72028. */
  72029. Phaser.Physics.NINJA = 2;
  72030. /**
  72031. * @const
  72032. * @type {number}
  72033. */
  72034. Phaser.Physics.BOX2D = 3;
  72035. /**
  72036. * @const
  72037. * @type {number}
  72038. */
  72039. Phaser.Physics.CHIPMUNK = 4;
  72040. /**
  72041. * @const
  72042. * @type {number}
  72043. */
  72044. Phaser.Physics.MATTERJS = 5;
  72045. Phaser.Physics.prototype = {
  72046. /**
  72047. * Parses the Physics Configuration object passed to the Game constructor and starts any physics systems specified within.
  72048. *
  72049. * @method Phaser.Physics#parseConfig
  72050. */
  72051. parseConfig: function () {
  72052. if ((!this.config.hasOwnProperty('arcade') || this.config['arcade'] === true) && Phaser.Physics.hasOwnProperty('Arcade'))
  72053. {
  72054. // If Arcade isn't specified, we create it automatically if we can
  72055. this.arcade = new Phaser.Physics.Arcade(this.game);
  72056. }
  72057. if (this.config.hasOwnProperty('ninja') && this.config['ninja'] === true && Phaser.Physics.hasOwnProperty('Ninja'))
  72058. {
  72059. this.ninja = new Phaser.Physics.Ninja(this.game);
  72060. }
  72061. if (this.config.hasOwnProperty('p2') && this.config['p2'] === true && Phaser.Physics.hasOwnProperty('P2'))
  72062. {
  72063. this.p2 = new Phaser.Physics.P2(this.game, this.config);
  72064. }
  72065. if (this.config.hasOwnProperty('box2d') && this.config['box2d'] === true && Phaser.Physics.hasOwnProperty('BOX2D'))
  72066. {
  72067. this.box2d = new Phaser.Physics.BOX2D(this.game, this.config);
  72068. }
  72069. if (this.config.hasOwnProperty('matter') && this.config['matter'] === true && Phaser.Physics.hasOwnProperty('Matter'))
  72070. {
  72071. this.matter = new Phaser.Physics.Matter(this.game, this.config);
  72072. }
  72073. },
  72074. /**
  72075. * This will create an instance of the requested physics simulation.
  72076. * Phaser.Physics.Arcade is running by default, but all others need activating directly.
  72077. *
  72078. * You can start the following physics systems:
  72079. *
  72080. * Phaser.Physics.P2JS - A full-body advanced physics system by Stefan Hedman.
  72081. * Phaser.Physics.NINJA - A port of Metanet Softwares N+ physics system.
  72082. * Phaser.Physics.BOX2D - A commercial Phaser Plugin (see http://phaser.io)
  72083. *
  72084. * Both Ninja Physics and Box2D require their respective plugins to be loaded before you can start them.
  72085. * They are not bundled into the core Phaser library.
  72086. *
  72087. * If the physics world has already been created (i.e. in another state in your game) then
  72088. * calling startSystem will reset the physics world, not re-create it. If you need to start them again from their constructors
  72089. * then set Phaser.Physics.p2 (or whichever system you want to recreate) to `null` before calling `startSystem`.
  72090. *
  72091. * @method Phaser.Physics#startSystem
  72092. * @param {number} system - The physics system to start: Phaser.Physics.ARCADE, Phaser.Physics.P2JS, Phaser.Physics.NINJA or Phaser.Physics.BOX2D.
  72093. */
  72094. startSystem: function (system) {
  72095. if (system === Phaser.Physics.ARCADE)
  72096. {
  72097. this.arcade = new Phaser.Physics.Arcade(this.game);
  72098. }
  72099. else if (system === Phaser.Physics.P2JS)
  72100. {
  72101. if (this.p2 === null)
  72102. {
  72103. this.p2 = new Phaser.Physics.P2(this.game, this.config);
  72104. }
  72105. else
  72106. {
  72107. this.p2.reset();
  72108. }
  72109. }
  72110. else if (system === Phaser.Physics.NINJA)
  72111. {
  72112. this.ninja = new Phaser.Physics.Ninja(this.game);
  72113. }
  72114. else if (system === Phaser.Physics.BOX2D)
  72115. {
  72116. if (this.box2d === null)
  72117. {
  72118. this.box2d = new Phaser.Physics.Box2D(this.game, this.config);
  72119. }
  72120. else
  72121. {
  72122. this.box2d.reset();
  72123. }
  72124. }
  72125. else if (system === Phaser.Physics.MATTERJS)
  72126. {
  72127. if (this.matter === null)
  72128. {
  72129. this.matter = new Phaser.Physics.Matter(this.game, this.config);
  72130. }
  72131. else
  72132. {
  72133. this.matter.reset();
  72134. }
  72135. }
  72136. },
  72137. /**
  72138. * This will create a default physics body on the given game object or array of objects.
  72139. * A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
  72140. * It can be for any of the physics systems that have been started:
  72141. *
  72142. * Phaser.Physics.Arcade - A light weight AABB based collision system with basic separation.
  72143. * Phaser.Physics.P2JS - A full-body advanced physics system supporting multiple object shapes, polygon loading, contact materials, springs and constraints.
  72144. * Phaser.Physics.NINJA - A port of Metanet Softwares N+ physics system. Advanced AABB and Circle vs. Tile collision.
  72145. * Phaser.Physics.BOX2D - A port of https://code.google.com/p/box2d-html5
  72146. * Phaser.Physics.MATTER - A full-body and light-weight advanced physics system (still in development)
  72147. * Phaser.Physics.CHIPMUNK is still in development.
  72148. *
  72149. * If you require more control over what type of body is created, for example to create a Ninja Physics Circle instead of the default AABB, then see the
  72150. * individual physics systems `enable` methods instead of using this generic one.
  72151. *
  72152. * @method Phaser.Physics#enable
  72153. * @param {object|array} object - The game object to create the physics body on. Can also be an array of objects, a body will be created on every object in the array.
  72154. * @param {number} [system=Phaser.Physics.ARCADE] - The physics system that will be used to create the body. Defaults to Arcade Physics.
  72155. * @param {boolean} [debug=false] - Enable the debug drawing for this body. Defaults to false.
  72156. */
  72157. enable: function (object, system, debug) {
  72158. if (system === undefined) { system = Phaser.Physics.ARCADE; }
  72159. if (debug === undefined) { debug = false; }
  72160. if (system === Phaser.Physics.ARCADE)
  72161. {
  72162. this.arcade.enable(object);
  72163. }
  72164. else if (system === Phaser.Physics.P2JS && this.p2)
  72165. {
  72166. this.p2.enable(object, debug);
  72167. }
  72168. else if (system === Phaser.Physics.NINJA && this.ninja)
  72169. {
  72170. this.ninja.enableAABB(object);
  72171. }
  72172. else if (system === Phaser.Physics.BOX2D && this.box2d)
  72173. {
  72174. this.box2d.enable(object);
  72175. }
  72176. else if (system === Phaser.Physics.MATTERJS && this.matter)
  72177. {
  72178. this.matter.enable(object);
  72179. }
  72180. else
  72181. {
  72182. console.warn(object.key + ' is attempting to enable a physics body using an unknown physics system.');
  72183. }
  72184. },
  72185. /**
  72186. * preUpdate checks.
  72187. *
  72188. * @method Phaser.Physics#preUpdate
  72189. * @protected
  72190. */
  72191. preUpdate: function () {
  72192. // ArcadePhysics / Ninja don't have a core to preUpdate
  72193. if (this.p2)
  72194. {
  72195. this.p2.preUpdate();
  72196. }
  72197. if (this.box2d)
  72198. {
  72199. this.box2d.preUpdate();
  72200. }
  72201. if (this.matter)
  72202. {
  72203. this.matter.preUpdate();
  72204. }
  72205. },
  72206. /**
  72207. * Updates all running physics systems.
  72208. *
  72209. * @method Phaser.Physics#update
  72210. * @protected
  72211. */
  72212. update: function () {
  72213. // ArcadePhysics / Ninja don't have a core to update
  72214. if (this.p2)
  72215. {
  72216. this.p2.update();
  72217. }
  72218. if (this.box2d)
  72219. {
  72220. this.box2d.update();
  72221. }
  72222. if (this.matter)
  72223. {
  72224. this.matter.update();
  72225. }
  72226. },
  72227. /**
  72228. * Updates the physics bounds to match the world dimensions.
  72229. *
  72230. * @method Phaser.Physics#setBoundsToWorld
  72231. * @protected
  72232. */
  72233. setBoundsToWorld: function () {
  72234. if (this.arcade)
  72235. {
  72236. this.arcade.setBoundsToWorld();
  72237. }
  72238. if (this.ninja)
  72239. {
  72240. this.ninja.setBoundsToWorld();
  72241. }
  72242. if (this.p2)
  72243. {
  72244. this.p2.setBoundsToWorld();
  72245. }
  72246. if (this.box2d)
  72247. {
  72248. this.box2d.setBoundsToWorld();
  72249. }
  72250. if (this.matter)
  72251. {
  72252. this.matter.setBoundsToWorld();
  72253. }
  72254. },
  72255. /**
  72256. * Clears down all active physics systems. This doesn't destroy them, it just clears them of objects and is called when the State changes.
  72257. *
  72258. * @method Phaser.Physics#clear
  72259. * @protected
  72260. */
  72261. clear: function () {
  72262. if (this.p2)
  72263. {
  72264. this.p2.clear();
  72265. }
  72266. if (this.box2d)
  72267. {
  72268. this.box2d.clear();
  72269. }
  72270. if (this.matter)
  72271. {
  72272. this.matter.clear();
  72273. }
  72274. },
  72275. /**
  72276. * Resets the active physics system. Called automatically on a Phaser.State swap.
  72277. *
  72278. * @method Phaser.Physics#reset
  72279. * @protected
  72280. */
  72281. reset: function () {
  72282. if (this.p2)
  72283. {
  72284. this.p2.reset();
  72285. }
  72286. if (this.box2d)
  72287. {
  72288. this.box2d.reset();
  72289. }
  72290. if (this.matter)
  72291. {
  72292. this.matter.reset();
  72293. }
  72294. },
  72295. /**
  72296. * Destroys all active physics systems. Usually only called on a Game Shutdown, not on a State swap.
  72297. *
  72298. * @method Phaser.Physics#destroy
  72299. */
  72300. destroy: function () {
  72301. if (this.p2)
  72302. {
  72303. this.p2.destroy();
  72304. }
  72305. if (this.box2d)
  72306. {
  72307. this.box2d.destroy();
  72308. }
  72309. if (this.matter)
  72310. {
  72311. this.matter.destroy();
  72312. }
  72313. this.arcade = null;
  72314. this.ninja = null;
  72315. this.p2 = null;
  72316. this.box2d = null;
  72317. this.matter = null;
  72318. }
  72319. };
  72320. Phaser.Physics.prototype.constructor = Phaser.Physics;
  72321. /**
  72322. * @author Richard Davey <rich@photonstorm.com>
  72323. * @copyright 2016 Photon Storm Ltd.
  72324. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  72325. */
  72326. /**
  72327. * The Arcade Physics world. Contains Arcade Physics related collision, overlap and motion methods.
  72328. *
  72329. * @class Phaser.Physics.Arcade
  72330. * @constructor
  72331. * @param {Phaser.Game} game - reference to the current game instance.
  72332. */
  72333. Phaser.Physics.Arcade = function (game) {
  72334. /**
  72335. * @property {Phaser.Game} game - Local reference to game.
  72336. */
  72337. this.game = game;
  72338. /**
  72339. * @property {Phaser.Point} gravity - The World gravity setting. Defaults to x: 0, y: 0, or no gravity.
  72340. */
  72341. this.gravity = new Phaser.Point();
  72342. /**
  72343. * @property {Phaser.Rectangle} bounds - The bounds inside of which the physics world exists. Defaults to match the world bounds.
  72344. */
  72345. this.bounds = new Phaser.Rectangle(0, 0, game.world.width, game.world.height);
  72346. /**
  72347. * Which edges of the World bounds Bodies can collide against when `collideWorldBounds` is `true`.
  72348. * For example checkCollision.down = false means Bodies cannot collide with the World.bounds.bottom.
  72349. * @property {object} checkCollision - An object containing allowed collision flags (up, down, left, right).
  72350. */
  72351. this.checkCollision = { up: true, down: true, left: true, right: true };
  72352. /**
  72353. * @property {number} maxObjects - Used by the QuadTree to set the maximum number of objects per quad.
  72354. */
  72355. this.maxObjects = 10;
  72356. /**
  72357. * @property {number} maxLevels - Used by the QuadTree to set the maximum number of iteration levels.
  72358. */
  72359. this.maxLevels = 4;
  72360. /**
  72361. * @property {number} OVERLAP_BIAS - A value added to the delta values during collision checks.
  72362. */
  72363. this.OVERLAP_BIAS = 4;
  72364. /**
  72365. * @property {boolean} forceX - If true World.separate will always separate on the X axis before Y. Otherwise it will check gravity totals first.
  72366. */
  72367. this.forceX = false;
  72368. /**
  72369. * @property {number} sortDirection - Used when colliding a Sprite vs. a Group, or a Group vs. a Group, this defines the direction the sort is based on. Default is Phaser.Physics.Arcade.LEFT_RIGHT.
  72370. * @default
  72371. */
  72372. this.sortDirection = Phaser.Physics.Arcade.LEFT_RIGHT;
  72373. /**
  72374. * @property {boolean} skipQuadTree - If true the QuadTree will not be used for any collision. QuadTrees are great if objects are well spread out in your game, otherwise they are a performance hit. If you enable this you can disable on a per body basis via `Body.skipQuadTree`.
  72375. */
  72376. this.skipQuadTree = true;
  72377. /**
  72378. * @property {boolean} isPaused - If `true` the `Body.preUpdate` method will be skipped, halting all motion for all bodies. Note that other methods such as `collide` will still work, so be careful not to call them on paused bodies.
  72379. */
  72380. this.isPaused = false;
  72381. /**
  72382. * @property {Phaser.QuadTree} quadTree - The world QuadTree.
  72383. */
  72384. this.quadTree = new Phaser.QuadTree(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels);
  72385. /**
  72386. * @property {number} _total - Internal cache var.
  72387. * @private
  72388. */
  72389. this._total = 0;
  72390. // By default we want the bounds the same size as the world bounds
  72391. this.setBoundsToWorld();
  72392. };
  72393. Phaser.Physics.Arcade.prototype.constructor = Phaser.Physics.Arcade;
  72394. /**
  72395. * A constant used for the sortDirection value.
  72396. * Use this if you don't wish to perform any pre-collision sorting at all, or will manually sort your Groups.
  72397. * @constant
  72398. * @type {number}
  72399. */
  72400. Phaser.Physics.Arcade.SORT_NONE = 0;
  72401. /**
  72402. * A constant used for the sortDirection value.
  72403. * Use this if your game world is wide but short and scrolls from the left to the right (i.e. Mario)
  72404. * @constant
  72405. * @type {number}
  72406. */
  72407. Phaser.Physics.Arcade.LEFT_RIGHT = 1;
  72408. /**
  72409. * A constant used for the sortDirection value.
  72410. * Use this if your game world is wide but short and scrolls from the right to the left (i.e. Mario backwards)
  72411. * @constant
  72412. * @type {number}
  72413. */
  72414. Phaser.Physics.Arcade.RIGHT_LEFT = 2;
  72415. /**
  72416. * A constant used for the sortDirection value.
  72417. * Use this if your game world is narrow but tall and scrolls from the top to the bottom (i.e. Dig Dug)
  72418. * @constant
  72419. * @type {number}
  72420. */
  72421. Phaser.Physics.Arcade.TOP_BOTTOM = 3;
  72422. /**
  72423. * A constant used for the sortDirection value.
  72424. * Use this if your game world is narrow but tall and scrolls from the bottom to the top (i.e. Commando or a vertically scrolling shoot-em-up)
  72425. * @constant
  72426. * @type {number}
  72427. */
  72428. Phaser.Physics.Arcade.BOTTOM_TOP = 4;
  72429. Phaser.Physics.Arcade.prototype = {
  72430. /**
  72431. * Updates the size of this physics world.
  72432. *
  72433. * @method Phaser.Physics.Arcade#setBounds
  72434. * @param {number} x - Top left most corner of the world.
  72435. * @param {number} y - Top left most corner of the world.
  72436. * @param {number} width - New width of the world. Can never be smaller than the Game.width.
  72437. * @param {number} height - New height of the world. Can never be smaller than the Game.height.
  72438. */
  72439. setBounds: function (x, y, width, height) {
  72440. this.bounds.setTo(x, y, width, height);
  72441. },
  72442. /**
  72443. * Updates the size of this physics world to match the size of the game world.
  72444. *
  72445. * @method Phaser.Physics.Arcade#setBoundsToWorld
  72446. */
  72447. setBoundsToWorld: function () {
  72448. this.bounds.copyFrom(this.game.world.bounds);
  72449. },
  72450. /**
  72451. * This will create an Arcade Physics body on the given game object or array of game objects.
  72452. * A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
  72453. *
  72454. * @method Phaser.Physics.Arcade#enable
  72455. * @param {object|array|Phaser.Group} object - The game object to create the physics body on. Can also be an array or Group of objects, a body will be created on every child that has a `body` property.
  72456. * @param {boolean} [children=true] - Should a body be created on all children of this object? If true it will recurse down the display list as far as it can go.
  72457. */
  72458. enable: function (object, children) {
  72459. if (children === undefined) { children = true; }
  72460. var i = 1;
  72461. if (Array.isArray(object))
  72462. {
  72463. i = object.length;
  72464. while (i--)
  72465. {
  72466. if (object[i] instanceof Phaser.Group)
  72467. {
  72468. // If it's a Group then we do it on the children regardless
  72469. this.enable(object[i].children, children);
  72470. }
  72471. else
  72472. {
  72473. this.enableBody(object[i]);
  72474. if (children && object[i].hasOwnProperty('children') && object[i].children.length > 0)
  72475. {
  72476. this.enable(object[i], true);
  72477. }
  72478. }
  72479. }
  72480. }
  72481. else
  72482. {
  72483. if (object instanceof Phaser.Group)
  72484. {
  72485. // If it's a Group then we do it on the children regardless
  72486. this.enable(object.children, children);
  72487. }
  72488. else
  72489. {
  72490. this.enableBody(object);
  72491. if (children && object.hasOwnProperty('children') && object.children.length > 0)
  72492. {
  72493. this.enable(object.children, true);
  72494. }
  72495. }
  72496. }
  72497. },
  72498. /**
  72499. * Creates an Arcade Physics body on the given game object.
  72500. *
  72501. * A game object can only have 1 physics body active at any one time, and it can't be changed until the body is nulled.
  72502. *
  72503. * When you add an Arcade Physics body to an object it will automatically add the object into its parent Groups hash array.
  72504. *
  72505. * @method Phaser.Physics.Arcade#enableBody
  72506. * @param {object} object - The game object to create the physics body on. A body will only be created if this object has a null `body` property.
  72507. */
  72508. enableBody: function (object) {
  72509. if (object.hasOwnProperty('body') && object.body === null)
  72510. {
  72511. object.body = new Phaser.Physics.Arcade.Body(object);
  72512. if (object.parent && object.parent instanceof Phaser.Group)
  72513. {
  72514. object.parent.addToHash(object);
  72515. }
  72516. }
  72517. },
  72518. /**
  72519. * Called automatically by a Physics body, it updates all motion related values on the Body unless `World.isPaused` is `true`.
  72520. *
  72521. * @method Phaser.Physics.Arcade#updateMotion
  72522. * @param {Phaser.Physics.Arcade.Body} The Body object to be updated.
  72523. */
  72524. updateMotion: function (body) {
  72525. if (body.allowRotation)
  72526. {
  72527. var velocityDelta = this.computeVelocity(0, body, body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity;
  72528. body.angularVelocity += velocityDelta;
  72529. body.rotation += (body.angularVelocity * this.game.time.physicsElapsed);
  72530. }
  72531. body.velocity.x = this.computeVelocity(1, body, body.velocity.x, body.acceleration.x, body.drag.x, body.maxVelocity.x);
  72532. body.velocity.y = this.computeVelocity(2, body, body.velocity.y, body.acceleration.y, body.drag.y, body.maxVelocity.y);
  72533. },
  72534. /**
  72535. * A tween-like function that takes a starting velocity and some other factors and returns an altered velocity.
  72536. * Based on a function in Flixel by @ADAMATOMIC
  72537. *
  72538. * @method Phaser.Physics.Arcade#computeVelocity
  72539. * @param {number} axis - 0 for nothing, 1 for horizontal, 2 for vertical.
  72540. * @param {Phaser.Physics.Arcade.Body} body - The Body object to be updated.
  72541. * @param {number} velocity - Any component of velocity (e.g. 20).
  72542. * @param {number} acceleration - Rate at which the velocity is changing.
  72543. * @param {number} drag - Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set.
  72544. * @param {number} [max=10000] - An absolute value cap for the velocity.
  72545. * @return {number} The altered Velocity value.
  72546. */
  72547. computeVelocity: function (axis, body, velocity, acceleration, drag, max) {
  72548. if (max === undefined) { max = 10000; }
  72549. if (axis === 1 && body.allowGravity)
  72550. {
  72551. velocity += (this.gravity.x + body.gravity.x) * this.game.time.physicsElapsed;
  72552. }
  72553. else if (axis === 2 && body.allowGravity)
  72554. {
  72555. velocity += (this.gravity.y + body.gravity.y) * this.game.time.physicsElapsed;
  72556. }
  72557. if (acceleration)
  72558. {
  72559. velocity += acceleration * this.game.time.physicsElapsed;
  72560. }
  72561. else if (drag && body.allowDrag)
  72562. {
  72563. drag *= this.game.time.physicsElapsed;
  72564. if (velocity - drag > 0)
  72565. {
  72566. velocity -= drag;
  72567. }
  72568. else if (velocity + drag < 0)
  72569. {
  72570. velocity += drag;
  72571. }
  72572. else
  72573. {
  72574. velocity = 0;
  72575. }
  72576. }
  72577. if (velocity > max)
  72578. {
  72579. velocity = max;
  72580. }
  72581. else if (velocity < -max)
  72582. {
  72583. velocity = -max;
  72584. }
  72585. return velocity;
  72586. },
  72587. /**
  72588. * Checks for overlaps between two game objects. The objects can be Sprites, Groups or Emitters.
  72589. *
  72590. * Unlike {@link #collide} the objects are NOT automatically separated or have any physics applied, they merely test for overlap results.
  72591. *
  72592. * You can perform Sprite vs. Sprite, Sprite vs. Group and Group vs. Group overlap checks.
  72593. * Both the first and second parameter can be arrays of objects, of differing types.
  72594. * If two arrays are passed, the contents of the first parameter will be tested against all contents of the 2nd parameter.
  72595. *
  72596. * **This function is not recursive**, and will not test against children of objects passed (i.e. Groups within Groups).
  72597. *
  72598. * ##### Tilemaps
  72599. *
  72600. * Any overlapping tiles, including blank/null tiles, will give a positive result. Tiles marked via {@link Phaser.Tilemap#setCollision} (and similar methods) have no special status, and callbacks added via {@link Phaser.Tilemap#setTileIndexCallback} or {@link Phaser.Tilemap#setTileLocationCallback} are not invoked. So calling this method without any callbacks isn't very useful.
  72601. *
  72602. * If you're interested only in whether an object overlaps a certain tile or class of tiles, filter the tiles with `processCallback` and then use the result returned by this method. Blank/null tiles can be excluded by their {@link Phaser.Tile#index index} (-1).
  72603. *
  72604. * If you want to take action on certain overlaps, examine the tiles in `collideCallback` and then handle as you like.
  72605. *
  72606. * @method Phaser.Physics.Arcade#overlap
  72607. * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|array} object1 - The first object or array of objects to check. Can be Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter.
  72608. * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|array} object2 - The second object or array of objects to check. Can be Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter.
  72609. * @param {function} [overlapCallback=null] - An optional callback function that is called if the objects overlap. The two objects will be passed to this function in the same order in which you specified them, unless you are checking Group vs. Sprite, in which case Sprite will always be the first parameter.
  72610. * @param {function} [processCallback=null] - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then `overlapCallback` will only be called if this callback returns `true`.
  72611. * @param {object} [callbackContext] - The context in which to run the callbacks.
  72612. * @return {boolean} True if an overlap occurred otherwise false.
  72613. */
  72614. overlap: function (object1, object2, overlapCallback, processCallback, callbackContext) {
  72615. overlapCallback = overlapCallback || null;
  72616. processCallback = processCallback || null;
  72617. callbackContext = callbackContext || overlapCallback;
  72618. this._total = 0;
  72619. this.collideObjects(object1, object2, overlapCallback, processCallback, callbackContext, true);
  72620. return (this._total > 0);
  72621. },
  72622. /**
  72623. * Checks for collision between two game objects and separates them if colliding ({@link https://gist.github.com/samme/cbb81dd19f564dcfe2232761e575063d details}). If you don't require separation then use {@link #overlap} instead.
  72624. *
  72625. * You can perform Sprite vs. Sprite, Sprite vs. Group, Group vs. Group, Sprite vs. Tilemap Layer or Group vs. Tilemap Layer collisions.
  72626. * Both the `object1` and `object2` can be arrays of objects, of differing types.
  72627. *
  72628. * If two Groups or arrays are passed, each member of one will be tested against each member of the other.
  72629. *
  72630. * If one Group **only** is passed (as `object1`), each member of the Group will be collided against the other members.
  72631. *
  72632. * If either object is `null` the collision test will fail.
  72633. *
  72634. * Bodies with `enable = false` and Sprites with `exists = false` are skipped (ignored).
  72635. *
  72636. * An optional processCallback can be provided. If given this function will be called when two sprites are found to be colliding. It is called before any separation takes place, giving you the chance to perform additional checks. If the function returns true then the collision and separation is carried out. If it returns false it is skipped.
  72637. *
  72638. * The collideCallback is an optional function that is only called if two sprites collide. If a processCallback has been set then it needs to return true for collideCallback to be called.
  72639. *
  72640. * **This function is not recursive**, and will not test against children of objects passed (i.e. Groups or Tilemaps within other Groups).
  72641. *
  72642. * ##### Examples
  72643. *
  72644. * ```javascript
  72645. * collide(group);
  72646. * collide(group, undefined); // equivalent
  72647. *
  72648. * collide(sprite1, sprite2);
  72649. *
  72650. * collide(sprite, group);
  72651. *
  72652. * collide(group1, group2);
  72653. *
  72654. * collide([sprite1, sprite2], [sprite3, sprite4]); // 1 vs. 3, 1 vs. 4, 2 vs. 3, 2 vs. 4
  72655. * ```
  72656. *
  72657. * ##### Tilemaps
  72658. *
  72659. * Tiles marked via {@link Phaser.Tilemap#setCollision} (and similar methods) are "solid". If a Sprite collides with one of these tiles, the two are separated by moving the Sprite outside the tile's edges. Enable {@link Phaser.TilemapLayer#debug} to see the colliding edges of the Tilemap.
  72660. *
  72661. * Tiles with a callback attached via {@link Phaser.Tilemap#setTileIndexCallback} or {@link Phaser.Tilemap#setTileLocationCallback} invoke the callback if a Sprite collides with them. If a tile has a callback attached via both methods, only the location callback is invoked. The colliding Sprite is separated from the tile only if the callback returns `true`.
  72662. *
  72663. * @method Phaser.Physics.Arcade#collide
  72664. * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.TilemapLayer|array} object1 - The first object or array of objects to check. Can be Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter, or Phaser.TilemapLayer.
  72665. * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.TilemapLayer|array} object2 - The second object or array of objects to check. Can be Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter or Phaser.TilemapLayer.
  72666. * @param {function} [collideCallback=null] - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them, unless you are colliding Group vs. Sprite, in which case Sprite will always be the first parameter.
  72667. * @param {function} [processCallback=null] - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them, unless you are colliding Group vs. Sprite, in which case Sprite will always be the first parameter.
  72668. * @param {object} [callbackContext] - The context in which to run the callbacks.
  72669. * @return {boolean} True if a collision occurred otherwise false.
  72670. */
  72671. collide: function (object1, object2, collideCallback, processCallback, callbackContext) {
  72672. collideCallback = collideCallback || null;
  72673. processCallback = processCallback || null;
  72674. callbackContext = callbackContext || collideCallback;
  72675. this._total = 0;
  72676. this.collideObjects(object1, object2, collideCallback, processCallback, callbackContext, false);
  72677. return (this._total > 0);
  72678. },
  72679. /**
  72680. * A Sort function for sorting two bodies based on a LEFT to RIGHT sort direction.
  72681. *
  72682. * This is called automatically by World.sort
  72683. *
  72684. * @method Phaser.Physics.Arcade#sortLeftRight
  72685. * @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
  72686. * @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
  72687. * @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
  72688. */
  72689. sortLeftRight: function (a, b) {
  72690. if (!a.body || !b.body)
  72691. {
  72692. return 0;
  72693. }
  72694. return a.body.x - b.body.x;
  72695. },
  72696. /**
  72697. * A Sort function for sorting two bodies based on a RIGHT to LEFT sort direction.
  72698. *
  72699. * This is called automatically by World.sort
  72700. *
  72701. * @method Phaser.Physics.Arcade#sortRightLeft
  72702. * @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
  72703. * @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
  72704. * @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
  72705. */
  72706. sortRightLeft: function (a, b) {
  72707. if (!a.body || !b.body)
  72708. {
  72709. return 0;
  72710. }
  72711. return b.body.x - a.body.x;
  72712. },
  72713. /**
  72714. * A Sort function for sorting two bodies based on a TOP to BOTTOM sort direction.
  72715. *
  72716. * This is called automatically by World.sort
  72717. *
  72718. * @method Phaser.Physics.Arcade#sortTopBottom
  72719. * @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
  72720. * @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
  72721. * @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
  72722. */
  72723. sortTopBottom: function (a, b) {
  72724. if (!a.body || !b.body)
  72725. {
  72726. return 0;
  72727. }
  72728. return a.body.y - b.body.y;
  72729. },
  72730. /**
  72731. * A Sort function for sorting two bodies based on a BOTTOM to TOP sort direction.
  72732. *
  72733. * This is called automatically by World.sort
  72734. *
  72735. * @method Phaser.Physics.Arcade#sortBottomTop
  72736. * @param {Phaser.Sprite} a - The first Sprite to test. The Sprite must have an Arcade Physics Body.
  72737. * @param {Phaser.Sprite} b - The second Sprite to test. The Sprite must have an Arcade Physics Body.
  72738. * @return {integer} A negative value if `a > b`, a positive value if `a < b` or 0 if `a === b` or the bodies are invalid.
  72739. */
  72740. sortBottomTop: function (a, b) {
  72741. if (!a.body || !b.body)
  72742. {
  72743. return 0;
  72744. }
  72745. return b.body.y - a.body.y;
  72746. },
  72747. /**
  72748. * This method will sort a Groups hash array.
  72749. *
  72750. * If the Group has `physicsSortDirection` set it will use the sort direction defined.
  72751. *
  72752. * Otherwise if the sortDirection parameter is undefined, or Group.physicsSortDirection is null, it will use Phaser.Physics.Arcade.sortDirection.
  72753. *
  72754. * By changing Group.physicsSortDirection you can customise each Group to sort in a different order.
  72755. *
  72756. * @method Phaser.Physics.Arcade#sort
  72757. * @param {Phaser.Group} group - The Group to sort.
  72758. * @param {integer} [sortDirection] - The sort direction used to sort this Group.
  72759. */
  72760. sort: function (group, sortDirection) {
  72761. if (group.physicsSortDirection !== null)
  72762. {
  72763. sortDirection = group.physicsSortDirection;
  72764. }
  72765. else
  72766. {
  72767. if (sortDirection === undefined) { sortDirection = this.sortDirection; }
  72768. }
  72769. if (sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
  72770. {
  72771. // Game world is say 2000x600 and you start at 0
  72772. group.hash.sort(this.sortLeftRight);
  72773. }
  72774. else if (sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
  72775. {
  72776. // Game world is say 2000x600 and you start at 2000
  72777. group.hash.sort(this.sortRightLeft);
  72778. }
  72779. else if (sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
  72780. {
  72781. // Game world is say 800x2000 and you start at 0
  72782. group.hash.sort(this.sortTopBottom);
  72783. }
  72784. else if (sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
  72785. {
  72786. // Game world is say 800x2000 and you start at 2000
  72787. group.hash.sort(this.sortBottomTop);
  72788. }
  72789. },
  72790. /**
  72791. * Internal collision handler. Extracts objects for {@link #collideHandler}.
  72792. *
  72793. * @method Phaser.Physics.Arcade#collideObjects
  72794. * @private
  72795. */
  72796. collideObjects: function (object1, object2, collideCallback, processCallback, callbackContext, overlapOnly) {
  72797. if (!Array.isArray(object1) && Array.isArray(object2))
  72798. {
  72799. for (var i = 0; i < object2.length; i++)
  72800. {
  72801. if (!object2[i]) { continue; }
  72802. this.collideHandler(object1, object2[i], collideCallback, processCallback, callbackContext, overlapOnly);
  72803. }
  72804. }
  72805. else if (Array.isArray(object1) && !Array.isArray(object2))
  72806. {
  72807. for (var i = 0; i < object1.length; i++)
  72808. {
  72809. if (!object1[i]) { continue; }
  72810. this.collideHandler(object1[i], object2, collideCallback, processCallback, callbackContext, overlapOnly);
  72811. }
  72812. }
  72813. else if (Array.isArray(object1) && Array.isArray(object2))
  72814. {
  72815. for (var i = 0; i < object1.length; i++)
  72816. {
  72817. if (!object1[i]) { continue; }
  72818. for (var j = 0; j < object2.length; j++)
  72819. {
  72820. if (!object2[j]) { continue; }
  72821. this.collideHandler(object1[i], object2[j], collideCallback, processCallback, callbackContext, overlapOnly);
  72822. }
  72823. }
  72824. }
  72825. else
  72826. {
  72827. this.collideHandler(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
  72828. }
  72829. },
  72830. /**
  72831. * Internal collision handler. Matches arguments to other handlers.
  72832. *
  72833. * @method Phaser.Physics.Arcade#collideHandler
  72834. * @private
  72835. * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.TilemapLayer} object1 - The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter, or Phaser.TilemapLayer.
  72836. * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.TilemapLayer} object2 - The second object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter or Phaser.TilemapLayer. Can also be an array of objects to check.
  72837. * @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
  72838. * @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
  72839. * @param {object} callbackContext - The context in which to run the callbacks.
  72840. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  72841. */
  72842. collideHandler: function (object1, object2, collideCallback, processCallback, callbackContext, overlapOnly) {
  72843. // Only collide valid objects
  72844. if (object2 === undefined && object1.physicsType === Phaser.GROUP)
  72845. {
  72846. this.sort(object1);
  72847. this.collideGroupVsSelf(object1, collideCallback, processCallback, callbackContext, overlapOnly);
  72848. return;
  72849. }
  72850. // If neither of the objects are set or exist then bail out
  72851. if (!object1 || !object2 || !object1.exists || !object2.exists)
  72852. {
  72853. return;
  72854. }
  72855. // Groups? Sort them
  72856. if (this.sortDirection !== Phaser.Physics.Arcade.SORT_NONE)
  72857. {
  72858. if (object1.physicsType === Phaser.GROUP)
  72859. {
  72860. this.sort(object1);
  72861. }
  72862. if (object2.physicsType === Phaser.GROUP)
  72863. {
  72864. this.sort(object2);
  72865. }
  72866. }
  72867. // SPRITES
  72868. if (object1.physicsType === Phaser.SPRITE)
  72869. {
  72870. if (object2.physicsType === Phaser.SPRITE)
  72871. {
  72872. this.collideSpriteVsSprite(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
  72873. }
  72874. else if (object2.physicsType === Phaser.GROUP)
  72875. {
  72876. this.collideSpriteVsGroup(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
  72877. }
  72878. else if (object2.physicsType === Phaser.TILEMAPLAYER)
  72879. {
  72880. this.collideSpriteVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
  72881. }
  72882. }
  72883. // GROUPS
  72884. else if (object1.physicsType === Phaser.GROUP)
  72885. {
  72886. if (object2.physicsType === Phaser.SPRITE)
  72887. {
  72888. this.collideSpriteVsGroup(object2, object1, collideCallback, processCallback, callbackContext, overlapOnly);
  72889. }
  72890. else if (object2.physicsType === Phaser.GROUP)
  72891. {
  72892. this.collideGroupVsGroup(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
  72893. }
  72894. else if (object2.physicsType === Phaser.TILEMAPLAYER)
  72895. {
  72896. this.collideGroupVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
  72897. }
  72898. }
  72899. // TILEMAP LAYERS
  72900. else if (object1.physicsType === Phaser.TILEMAPLAYER)
  72901. {
  72902. if (object2.physicsType === Phaser.SPRITE)
  72903. {
  72904. this.collideSpriteVsTilemapLayer(object2, object1, collideCallback, processCallback, callbackContext, overlapOnly);
  72905. }
  72906. else if (object2.physicsType === Phaser.GROUP)
  72907. {
  72908. this.collideGroupVsTilemapLayer(object2, object1, collideCallback, processCallback, callbackContext, overlapOnly);
  72909. }
  72910. }
  72911. },
  72912. /**
  72913. * An internal function. Use Phaser.Physics.Arcade.collide instead.
  72914. *
  72915. * @method Phaser.Physics.Arcade#collideSpriteVsSprite
  72916. * @private
  72917. * @param {Phaser.Sprite} sprite1 - The first sprite to check.
  72918. * @param {Phaser.Sprite} sprite2 - The second sprite to check.
  72919. * @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
  72920. * @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
  72921. * @param {object} callbackContext - The context in which to run the callbacks.
  72922. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  72923. * @return {boolean} True if there was a collision, otherwise false.
  72924. */
  72925. collideSpriteVsSprite: function (sprite1, sprite2, collideCallback, processCallback, callbackContext, overlapOnly) {
  72926. if (!sprite1.body || !sprite2.body)
  72927. {
  72928. return false;
  72929. }
  72930. if (this.separate(sprite1.body, sprite2.body, processCallback, callbackContext, overlapOnly))
  72931. {
  72932. if (collideCallback)
  72933. {
  72934. collideCallback.call(callbackContext, sprite1, sprite2);
  72935. }
  72936. this._total++;
  72937. }
  72938. return true;
  72939. },
  72940. /**
  72941. * An internal function. Use Phaser.Physics.Arcade.collide instead.
  72942. *
  72943. * @method Phaser.Physics.Arcade#collideSpriteVsGroup
  72944. * @private
  72945. * @param {Phaser.Sprite} sprite - The sprite to check.
  72946. * @param {Phaser.Group} group - The Group to check.
  72947. * @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
  72948. * @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
  72949. * @param {object} callbackContext - The context in which to run the callbacks.
  72950. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  72951. */
  72952. collideSpriteVsGroup: function (sprite, group, collideCallback, processCallback, callbackContext, overlapOnly) {
  72953. if (group.length === 0 || !sprite.body)
  72954. {
  72955. return;
  72956. }
  72957. if (this.skipQuadTree || sprite.body.skipQuadTree)
  72958. {
  72959. var bounds = {};
  72960. for (var i = 0; i < group.hash.length; i++)
  72961. {
  72962. var object1 = group.hash[i];
  72963. // Skip duff entries - we can't check a non-existent sprite or one with no body
  72964. if (!object1 || !object1.exists || !object1.body)
  72965. {
  72966. continue;
  72967. }
  72968. // Inject the Body bounds data into the bounds object
  72969. bounds = object1.body.getBounds(bounds);
  72970. // Skip items either side of the sprite
  72971. if (this.sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
  72972. {
  72973. if (sprite.body.right < bounds.x)
  72974. {
  72975. break;
  72976. }
  72977. else if (bounds.right < sprite.body.x)
  72978. {
  72979. continue;
  72980. }
  72981. }
  72982. else if (this.sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
  72983. {
  72984. if (sprite.body.x > bounds.right)
  72985. {
  72986. break;
  72987. }
  72988. else if (bounds.x > sprite.body.right)
  72989. {
  72990. continue;
  72991. }
  72992. }
  72993. else if (this.sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
  72994. {
  72995. if (sprite.body.bottom < bounds.y)
  72996. {
  72997. break;
  72998. }
  72999. else if (bounds.bottom < sprite.body.y)
  73000. {
  73001. continue;
  73002. }
  73003. }
  73004. else if (this.sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
  73005. {
  73006. if (sprite.body.y > bounds.bottom)
  73007. {
  73008. break;
  73009. }
  73010. else if (bounds.y > sprite.body.bottom)
  73011. {
  73012. continue;
  73013. }
  73014. }
  73015. this.collideSpriteVsSprite(sprite, object1, collideCallback, processCallback, callbackContext, overlapOnly);
  73016. }
  73017. }
  73018. else
  73019. {
  73020. // What is the sprite colliding with in the quadtree?
  73021. this.quadTree.clear();
  73022. this.quadTree.reset(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels);
  73023. this.quadTree.populate(group);
  73024. var items = this.quadTree.retrieve(sprite);
  73025. for (var i = 0; i < items.length; i++)
  73026. {
  73027. // We have our potential suspects, are they in this group?
  73028. if (this.separate(sprite.body, items[i], processCallback, callbackContext, overlapOnly))
  73029. {
  73030. if (collideCallback)
  73031. {
  73032. collideCallback.call(callbackContext, sprite, items[i].sprite);
  73033. }
  73034. this._total++;
  73035. }
  73036. }
  73037. }
  73038. },
  73039. /**
  73040. * An internal function. Use Phaser.Physics.Arcade.collide instead.
  73041. *
  73042. * @method Phaser.Physics.Arcade#collideGroupVsSelf
  73043. * @private
  73044. * @param {Phaser.Group} group - The Group to check.
  73045. * @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
  73046. * @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
  73047. * @param {object} callbackContext - The context in which to run the callbacks.
  73048. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  73049. * @return {boolean} True if there was a collision, otherwise false.
  73050. */
  73051. collideGroupVsSelf: function (group, collideCallback, processCallback, callbackContext, overlapOnly) {
  73052. if (group.length === 0)
  73053. {
  73054. return;
  73055. }
  73056. for (var i = 0; i < group.hash.length; i++)
  73057. {
  73058. var bounds1 = {};
  73059. var object1 = group.hash[i];
  73060. // Skip duff entries - we can't check a non-existent sprite or one with no body
  73061. if (!object1 || !object1.exists || !object1.body)
  73062. {
  73063. continue;
  73064. }
  73065. // Inject the Body bounds data into the bounds1 object
  73066. bounds1 = object1.body.getBounds(bounds1);
  73067. for (var j = i + 1; j < group.hash.length; j++)
  73068. {
  73069. var bounds2 = {};
  73070. var object2 = group.hash[j];
  73071. // Skip duff entries - we can't check a non-existent sprite or one with no body
  73072. if (!object2 || !object2.exists || !object2.body)
  73073. {
  73074. continue;
  73075. }
  73076. // Inject the Body bounds data into the bounds2 object
  73077. bounds2 = object2.body.getBounds(bounds2);
  73078. // Skip items either side of the sprite
  73079. if (this.sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
  73080. {
  73081. if (bounds1.right < bounds2.x)
  73082. {
  73083. break;
  73084. }
  73085. else if (bounds2.right < bounds1.x)
  73086. {
  73087. continue;
  73088. }
  73089. }
  73090. else if (this.sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
  73091. {
  73092. if (bounds1.x > bounds2.right)
  73093. {
  73094. continue;
  73095. }
  73096. else if (bounds2.x > bounds1.right)
  73097. {
  73098. break;
  73099. }
  73100. }
  73101. else if (this.sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
  73102. {
  73103. if (bounds1.bottom < bounds2.y)
  73104. {
  73105. continue;
  73106. }
  73107. else if (bounds2.bottom < bounds1.y)
  73108. {
  73109. break;
  73110. }
  73111. }
  73112. else if (this.sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
  73113. {
  73114. if (bounds1.y > bounds2.bottom)
  73115. {
  73116. continue;
  73117. }
  73118. else if (bounds2.y > object1.body.bottom)
  73119. {
  73120. break;
  73121. }
  73122. }
  73123. this.collideSpriteVsSprite(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
  73124. }
  73125. }
  73126. },
  73127. /**
  73128. * An internal function. Use Phaser.Physics.Arcade.collide instead.
  73129. *
  73130. * @method Phaser.Physics.Arcade#collideGroupVsGroup
  73131. * @private
  73132. * @param {Phaser.Group} group1 - The first Group to check.
  73133. * @param {Phaser.Group} group2 - The second Group to check.
  73134. * @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
  73135. * @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
  73136. * @param {object} callbackContext - The context in which to run the callbacks.
  73137. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  73138. */
  73139. collideGroupVsGroup: function (group1, group2, collideCallback, processCallback, callbackContext, overlapOnly) {
  73140. if (group1.length === 0 || group2.length === 0)
  73141. {
  73142. return;
  73143. }
  73144. for (var i = 0; i < group1.children.length; i++)
  73145. {
  73146. if (group1.children[i].exists)
  73147. {
  73148. if (group1.children[i].physicsType === Phaser.GROUP)
  73149. {
  73150. this.collideGroupVsGroup(group1.children[i], group2, collideCallback, processCallback, callbackContext, overlapOnly);
  73151. }
  73152. else
  73153. {
  73154. this.collideSpriteVsGroup(group1.children[i], group2, collideCallback, processCallback, callbackContext, overlapOnly);
  73155. }
  73156. }
  73157. }
  73158. },
  73159. /**
  73160. * The core separation function to separate two physics bodies.
  73161. *
  73162. * @private
  73163. * @method Phaser.Physics.Arcade#separate
  73164. * @param {Phaser.Physics.Arcade.Body} body1 - The first Body object to separate.
  73165. * @param {Phaser.Physics.Arcade.Body} body2 - The second Body object to separate.
  73166. * @param {function} [processCallback=null] - A callback function that lets you perform additional checks against the two objects if they overlap. If this function is set then the sprites will only be collided if it returns true.
  73167. * @param {object} [callbackContext] - The context in which to run the process callback.
  73168. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  73169. * @return {boolean} Returns true if the bodies collided, otherwise false.
  73170. */
  73171. separate: function (body1, body2, processCallback, callbackContext, overlapOnly) {
  73172. if (
  73173. !body1.enable ||
  73174. !body2.enable ||
  73175. body1.checkCollision.none ||
  73176. body2.checkCollision.none ||
  73177. !this.intersects(body1, body2))
  73178. {
  73179. return false;
  73180. }
  73181. // They overlap. Is there a custom process callback? If it returns true then we can carry on, otherwise we should abort.
  73182. if (processCallback && processCallback.call(callbackContext, body1.sprite, body2.sprite) === false)
  73183. {
  73184. return false;
  73185. }
  73186. // Circle vs. Circle quick bail out
  73187. if (body1.isCircle && body2.isCircle)
  73188. {
  73189. return this.separateCircle(body1, body2, overlapOnly);
  73190. }
  73191. // We define the behavior of bodies in a collision circle and rectangle
  73192. // If a collision occurs in the corner points of the rectangle, the body behave like circles
  73193. // Either body1 or body2 is a circle
  73194. if (body1.isCircle !== body2.isCircle)
  73195. {
  73196. var bodyRect = (body1.isCircle) ? body2 : body1;
  73197. var bodyCircle = (body1.isCircle) ? body1 : body2;
  73198. var rect = {
  73199. x: bodyRect.x,
  73200. y: bodyRect.y,
  73201. right: bodyRect.right,
  73202. bottom: bodyRect.bottom
  73203. };
  73204. var circle = bodyCircle.center;
  73205. if (circle.y < rect.y || circle.y > rect.bottom)
  73206. {
  73207. if (circle.x < rect.x || circle.x > rect.right)
  73208. {
  73209. return this.separateCircle(body1, body2, overlapOnly);
  73210. }
  73211. }
  73212. }
  73213. var resultX = false;
  73214. var resultY = false;
  73215. // Do we separate on x or y first?
  73216. if (this.forceX || Math.abs(this.gravity.y + body1.gravity.y) < Math.abs(this.gravity.x + body1.gravity.x))
  73217. {
  73218. resultX = this.separateX(body1, body2, overlapOnly);
  73219. // Are they still intersecting? Let's do the other axis then
  73220. if (this.intersects(body1, body2))
  73221. {
  73222. resultY = this.separateY(body1, body2, overlapOnly);
  73223. }
  73224. }
  73225. else
  73226. {
  73227. resultY = this.separateY(body1, body2, overlapOnly);
  73228. // Are they still intersecting? Let's do the other axis then
  73229. if (this.intersects(body1, body2))
  73230. {
  73231. resultX = this.separateX(body1, body2, overlapOnly);
  73232. }
  73233. }
  73234. var result = (resultX || resultY);
  73235. if (result)
  73236. {
  73237. if (overlapOnly)
  73238. {
  73239. if (body1.onOverlap)
  73240. {
  73241. body1.onOverlap.dispatch(body1.sprite, body2.sprite);
  73242. }
  73243. if (body2.onOverlap)
  73244. {
  73245. body2.onOverlap.dispatch(body2.sprite, body1.sprite);
  73246. }
  73247. }
  73248. else
  73249. {
  73250. if (body1.onCollide)
  73251. {
  73252. body1.onCollide.dispatch(body1.sprite, body2.sprite);
  73253. }
  73254. if (body2.onCollide)
  73255. {
  73256. body2.onCollide.dispatch(body2.sprite, body1.sprite);
  73257. }
  73258. }
  73259. }
  73260. return result;
  73261. },
  73262. /**
  73263. * Check for intersection against two bodies.
  73264. *
  73265. * @method Phaser.Physics.Arcade#intersects
  73266. * @param {Phaser.Physics.Arcade.Body} body1 - The first Body object to check.
  73267. * @param {Phaser.Physics.Arcade.Body} body2 - The second Body object to check.
  73268. * @return {boolean} True if they intersect, otherwise false.
  73269. */
  73270. intersects: function (body1, body2) {
  73271. if (body1 === body2)
  73272. {
  73273. return false;
  73274. }
  73275. if (body1.isCircle)
  73276. {
  73277. if (body2.isCircle)
  73278. {
  73279. // Circle vs. Circle
  73280. return Phaser.Math.distance(body1.center.x, body1.center.y, body2.center.x, body2.center.y) <= (body1.halfWidth + body2.halfWidth);
  73281. }
  73282. else
  73283. {
  73284. // Circle vs. Rect
  73285. return this.circleBodyIntersects(body1, body2);
  73286. }
  73287. }
  73288. else
  73289. {
  73290. if (body2.isCircle)
  73291. {
  73292. // Rect vs. Circle
  73293. return this.circleBodyIntersects(body2, body1);
  73294. }
  73295. else
  73296. {
  73297. // Rect vs. Rect
  73298. if (body1.right <= body2.position.x)
  73299. {
  73300. return false;
  73301. }
  73302. if (body1.bottom <= body2.position.y)
  73303. {
  73304. return false;
  73305. }
  73306. if (body1.position.x >= body2.right)
  73307. {
  73308. return false;
  73309. }
  73310. if (body1.position.y >= body2.bottom)
  73311. {
  73312. return false;
  73313. }
  73314. return true;
  73315. }
  73316. }
  73317. },
  73318. /**
  73319. * Checks to see if a circular Body intersects with a Rectangular Body.
  73320. *
  73321. * @method Phaser.Physics.Arcade#circleBodyIntersects
  73322. * @param {Phaser.Physics.Arcade.Body} circle - The Body with `isCircle` set.
  73323. * @param {Phaser.Physics.Arcade.Body} body - The Body with `isCircle` not set (i.e. uses Rectangle shape)
  73324. * @return {boolean} Returns true if the bodies intersect, otherwise false.
  73325. */
  73326. circleBodyIntersects: function (circle, body) {
  73327. var x = Phaser.Math.clamp(circle.center.x, body.left, body.right);
  73328. var y = Phaser.Math.clamp(circle.center.y, body.top, body.bottom);
  73329. var dx = (circle.center.x - x) * (circle.center.x - x);
  73330. var dy = (circle.center.y - y) * (circle.center.y - y);
  73331. return (dx + dy) <= (circle.halfWidth * circle.halfWidth);
  73332. },
  73333. /**
  73334. * The core separation function to separate two circular physics bodies.
  73335. *
  73336. * @method Phaser.Physics.Arcade#separateCircle
  73337. * @private
  73338. * @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate. Must have `Body.isCircle` true and a positive `radius`.
  73339. * @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate. Must have `Body.isCircle` true and a positive `radius`.
  73340. * @param {boolean} overlapOnly - If true the bodies will only have their overlap data set, no separation or exchange of velocity will take place.
  73341. * @return {boolean} Returns true if the bodies were separated or overlap, otherwise false.
  73342. */
  73343. separateCircle: function (body1, body2, overlapOnly) {
  73344. // Set the bounding box overlap values
  73345. this.getOverlapX(body1, body2);
  73346. this.getOverlapY(body1, body2);
  73347. var dx = body2.center.x - body1.center.x;
  73348. var dy = body2.center.y - body1.center.y;
  73349. var angleCollision = Math.atan2(dy, dx);
  73350. var overlap = 0;
  73351. if (body1.isCircle !== body2.isCircle)
  73352. {
  73353. var rect = {
  73354. x: (body2.isCircle) ? body1.position.x : body2.position.x,
  73355. y: (body2.isCircle) ? body1.position.y : body2.position.y,
  73356. right: (body2.isCircle) ? body1.right : body2.right,
  73357. bottom: (body2.isCircle) ? body1.bottom : body2.bottom
  73358. };
  73359. var circle = {
  73360. x: (body1.isCircle) ? body1.center.x : body2.center.x,
  73361. y: (body1.isCircle) ? body1.center.y : body2.center.y,
  73362. radius: (body1.isCircle) ? body1.halfWidth : body2.halfWidth
  73363. };
  73364. if (circle.y < rect.y)
  73365. {
  73366. if (circle.x < rect.x)
  73367. {
  73368. overlap = Phaser.Math.distance(circle.x, circle.y, rect.x, rect.y) - circle.radius;
  73369. }
  73370. else if (circle.x > rect.right)
  73371. {
  73372. overlap = Phaser.Math.distance(circle.x, circle.y, rect.right, rect.y) - circle.radius;
  73373. }
  73374. }
  73375. else if (circle.y > rect.bottom)
  73376. {
  73377. if (circle.x < rect.x)
  73378. {
  73379. overlap = Phaser.Math.distance(circle.x, circle.y, rect.x, rect.bottom) - circle.radius;
  73380. }
  73381. else if (circle.x > rect.right)
  73382. {
  73383. overlap = Phaser.Math.distance(circle.x, circle.y, rect.right, rect.bottom) - circle.radius;
  73384. }
  73385. }
  73386. overlap *= -1;
  73387. }
  73388. else
  73389. {
  73390. overlap = (body1.halfWidth + body2.halfWidth) - Phaser.Math.distance(body1.center.x, body1.center.y, body2.center.x, body2.center.y);
  73391. }
  73392. // Can't separate two immovable bodies, or a body with its own custom separation logic
  73393. if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateX || body2.customSeparateX)
  73394. {
  73395. if (overlap !== 0)
  73396. {
  73397. if (body1.onOverlap)
  73398. {
  73399. body1.onOverlap.dispatch(body1.sprite, body2.sprite);
  73400. }
  73401. if (body2.onOverlap)
  73402. {
  73403. body2.onOverlap.dispatch(body2.sprite, body1.sprite);
  73404. }
  73405. }
  73406. // return true if there was some overlap, otherwise false
  73407. return (overlap !== 0);
  73408. }
  73409. // Transform the velocity vector to the coordinate system oriented along the direction of impact.
  73410. // This is done to eliminate the vertical component of the velocity
  73411. var v1 = {
  73412. x: body1.velocity.x * Math.cos(angleCollision) + body1.velocity.y * Math.sin(angleCollision),
  73413. y: body1.velocity.x * Math.sin(angleCollision) - body1.velocity.y * Math.cos(angleCollision)
  73414. };
  73415. var v2 = {
  73416. x: body2.velocity.x * Math.cos(angleCollision) + body2.velocity.y * Math.sin(angleCollision),
  73417. y: body2.velocity.x * Math.sin(angleCollision) - body2.velocity.y * Math.cos(angleCollision)
  73418. };
  73419. // We expect the new velocity after impact
  73420. var tempVel1 = ((body1.mass - body2.mass) * v1.x + 2 * body2.mass * v2.x) / (body1.mass + body2.mass);
  73421. var tempVel2 = (2 * body1.mass * v1.x + (body2.mass - body1.mass) * v2.x) / (body1.mass + body2.mass);
  73422. // We convert the vector to the original coordinate system and multiplied by factor of rebound
  73423. if (!body1.immovable)
  73424. {
  73425. body1.velocity.x = (tempVel1 * Math.cos(angleCollision) - v1.y * Math.sin(angleCollision)) * body1.bounce.x;
  73426. body1.velocity.y = (v1.y * Math.cos(angleCollision) + tempVel1 * Math.sin(angleCollision)) * body1.bounce.y;
  73427. }
  73428. if (!body2.immovable)
  73429. {
  73430. body2.velocity.x = (tempVel2 * Math.cos(angleCollision) - v2.y * Math.sin(angleCollision)) * body2.bounce.x;
  73431. body2.velocity.y = (v2.y * Math.cos(angleCollision) + tempVel2 * Math.sin(angleCollision)) * body2.bounce.y;
  73432. }
  73433. // When the collision angle is almost perpendicular to the total initial velocity vector
  73434. // (collision on a tangent) vector direction can be determined incorrectly.
  73435. // This code fixes the problem
  73436. if (Math.abs(angleCollision) < Math.PI / 2)
  73437. {
  73438. if ((body1.velocity.x > 0) && !body1.immovable && (body2.velocity.x > body1.velocity.x))
  73439. {
  73440. body1.velocity.x *= -1;
  73441. }
  73442. else if ((body2.velocity.x < 0) && !body2.immovable && (body1.velocity.x < body2.velocity.x))
  73443. {
  73444. body2.velocity.x *= -1;
  73445. }
  73446. else if ((body1.velocity.y > 0) && !body1.immovable && (body2.velocity.y > body1.velocity.y))
  73447. {
  73448. body1.velocity.y *= -1;
  73449. }
  73450. else if ((body2.velocity.y < 0) && !body2.immovable && (body1.velocity.y < body2.velocity.y))
  73451. {
  73452. body2.velocity.y *= -1;
  73453. }
  73454. }
  73455. else if (Math.abs(angleCollision) > Math.PI / 2)
  73456. {
  73457. if ((body1.velocity.x < 0) && !body1.immovable && (body2.velocity.x < body1.velocity.x))
  73458. {
  73459. body1.velocity.x *= -1;
  73460. }
  73461. else if ((body2.velocity.x > 0) && !body2.immovable && (body1.velocity.x > body2.velocity.x))
  73462. {
  73463. body2.velocity.x *= -1;
  73464. }
  73465. else if ((body1.velocity.y < 0) && !body1.immovable && (body2.velocity.y < body1.velocity.y))
  73466. {
  73467. body1.velocity.y *= -1;
  73468. }
  73469. else if ((body2.velocity.y > 0) && !body2.immovable && (body1.velocity.x > body2.velocity.y))
  73470. {
  73471. body2.velocity.y *= -1;
  73472. }
  73473. }
  73474. if (!body1.immovable)
  73475. {
  73476. body1.x += (body1.velocity.x * this.game.time.physicsElapsed) - overlap * Math.cos(angleCollision);
  73477. body1.y += (body1.velocity.y * this.game.time.physicsElapsed) - overlap * Math.sin(angleCollision);
  73478. }
  73479. if (!body2.immovable)
  73480. {
  73481. body2.x += (body2.velocity.x * this.game.time.physicsElapsed) + overlap * Math.cos(angleCollision);
  73482. body2.y += (body2.velocity.y * this.game.time.physicsElapsed) + overlap * Math.sin(angleCollision);
  73483. }
  73484. if (body1.onCollide)
  73485. {
  73486. body1.onCollide.dispatch(body1.sprite, body2.sprite);
  73487. }
  73488. if (body2.onCollide)
  73489. {
  73490. body2.onCollide.dispatch(body2.sprite, body1.sprite);
  73491. }
  73492. return true;
  73493. },
  73494. /**
  73495. * Calculates the horizontal overlap between two Bodies and sets their properties accordingly, including:
  73496. * `touching.left`, `touching.right` and `overlapX`.
  73497. *
  73498. * @method Phaser.Physics.Arcade#getOverlapX
  73499. * @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate.
  73500. * @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate.
  73501. * @param {boolean} overlapOnly - Is this an overlap only check, or part of separation?
  73502. * @return {float} Returns the amount of horizontal overlap between the two bodies.
  73503. */
  73504. getOverlapX: function (body1, body2, overlapOnly) {
  73505. var overlap = 0;
  73506. var maxOverlap = body1.deltaAbsX() + body2.deltaAbsX() + this.OVERLAP_BIAS;
  73507. if (body1.deltaX() === 0 && body2.deltaX() === 0)
  73508. {
  73509. // They overlap but neither of them are moving
  73510. body1.embedded = true;
  73511. body2.embedded = true;
  73512. }
  73513. else if (body1.deltaX() > body2.deltaX())
  73514. {
  73515. // Body1 is moving right and / or Body2 is moving left
  73516. overlap = body1.right - body2.x;
  73517. if ((overlap > maxOverlap && !overlapOnly) || body1.checkCollision.right === false || body2.checkCollision.left === false)
  73518. {
  73519. overlap = 0;
  73520. }
  73521. else
  73522. {
  73523. body1.touching.none = false;
  73524. body1.touching.right = true;
  73525. body2.touching.none = false;
  73526. body2.touching.left = true;
  73527. }
  73528. }
  73529. else if (body1.deltaX() < body2.deltaX())
  73530. {
  73531. // Body1 is moving left and/or Body2 is moving right
  73532. overlap = body1.x - body2.width - body2.x;
  73533. if ((-overlap > maxOverlap && !overlapOnly) || body1.checkCollision.left === false || body2.checkCollision.right === false)
  73534. {
  73535. overlap = 0;
  73536. }
  73537. else
  73538. {
  73539. body1.touching.none = false;
  73540. body1.touching.left = true;
  73541. body2.touching.none = false;
  73542. body2.touching.right = true;
  73543. }
  73544. }
  73545. // Resets the overlapX to zero if there is no overlap, or to the actual pixel value if there is
  73546. body1.overlapX = overlap;
  73547. body2.overlapX = overlap;
  73548. return overlap;
  73549. },
  73550. /**
  73551. * Calculates the vertical overlap between two Bodies and sets their properties accordingly, including:
  73552. * `touching.up`, `touching.down` and `overlapY`.
  73553. *
  73554. * @method Phaser.Physics.Arcade#getOverlapY
  73555. * @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate.
  73556. * @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate.
  73557. * @param {boolean} overlapOnly - Is this an overlap only check, or part of separation?
  73558. * @return {float} Returns the amount of vertical overlap between the two bodies.
  73559. */
  73560. getOverlapY: function (body1, body2, overlapOnly) {
  73561. var overlap = 0;
  73562. var maxOverlap = body1.deltaAbsY() + body2.deltaAbsY() + this.OVERLAP_BIAS;
  73563. if (body1.deltaY() === 0 && body2.deltaY() === 0)
  73564. {
  73565. // They overlap but neither of them are moving
  73566. body1.embedded = true;
  73567. body2.embedded = true;
  73568. }
  73569. else if (body1.deltaY() > body2.deltaY())
  73570. {
  73571. // Body1 is moving down and/or Body2 is moving up
  73572. overlap = body1.bottom - body2.y;
  73573. if ((overlap > maxOverlap && !overlapOnly) || body1.checkCollision.down === false || body2.checkCollision.up === false)
  73574. {
  73575. overlap = 0;
  73576. }
  73577. else
  73578. {
  73579. body1.touching.none = false;
  73580. body1.touching.down = true;
  73581. body2.touching.none = false;
  73582. body2.touching.up = true;
  73583. }
  73584. }
  73585. else if (body1.deltaY() < body2.deltaY())
  73586. {
  73587. // Body1 is moving up and/or Body2 is moving down
  73588. overlap = body1.y - body2.bottom;
  73589. if ((-overlap > maxOverlap && !overlapOnly) || body1.checkCollision.up === false || body2.checkCollision.down === false)
  73590. {
  73591. overlap = 0;
  73592. }
  73593. else
  73594. {
  73595. body1.touching.none = false;
  73596. body1.touching.up = true;
  73597. body2.touching.none = false;
  73598. body2.touching.down = true;
  73599. }
  73600. }
  73601. // Resets the overlapY to zero if there is no overlap, or to the actual pixel value if there is
  73602. body1.overlapY = overlap;
  73603. body2.overlapY = overlap;
  73604. return overlap;
  73605. },
  73606. /**
  73607. * The core separation function to separate two physics bodies on the x axis.
  73608. *
  73609. * @method Phaser.Physics.Arcade#separateX
  73610. * @private
  73611. * @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate.
  73612. * @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate.
  73613. * @param {boolean} overlapOnly - If true the bodies will only have their overlap data set, no separation or exchange of velocity will take place.
  73614. * @return {boolean} Returns true if the bodies were separated or overlap, otherwise false.
  73615. */
  73616. separateX: function (body1, body2, overlapOnly) {
  73617. var overlap = this.getOverlapX(body1, body2, overlapOnly);
  73618. // Can't separate two immovable bodies, or a body with its own custom separation logic
  73619. if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateX || body2.customSeparateX)
  73620. {
  73621. // return true if there was some overlap, otherwise false
  73622. return (overlap !== 0) || (body1.embedded && body2.embedded);
  73623. }
  73624. // Adjust their positions and velocities accordingly (if there was any overlap)
  73625. var v1 = body1.velocity.x;
  73626. var v2 = body2.velocity.x;
  73627. if (!body1.immovable && !body2.immovable)
  73628. {
  73629. overlap *= 0.5;
  73630. body1.x -= overlap;
  73631. body2.x += overlap;
  73632. var nv1 = Math.sqrt((v2 * v2 * body2.mass) / body1.mass) * ((v2 > 0) ? 1 : -1);
  73633. var nv2 = Math.sqrt((v1 * v1 * body1.mass) / body2.mass) * ((v1 > 0) ? 1 : -1);
  73634. var avg = (nv1 + nv2) * 0.5;
  73635. nv1 -= avg;
  73636. nv2 -= avg;
  73637. body1.velocity.x = avg + nv1 * body1.bounce.x;
  73638. body2.velocity.x = avg + nv2 * body2.bounce.x;
  73639. }
  73640. else if (!body1.immovable)
  73641. {
  73642. body1.x -= overlap;
  73643. body1.velocity.x = v2 - v1 * body1.bounce.x;
  73644. // This is special case code that handles things like vertically moving platforms you can ride
  73645. if (body2.moves)
  73646. {
  73647. body1.y += (body2.y - body2.prev.y) * body2.friction.y;
  73648. }
  73649. }
  73650. else
  73651. {
  73652. body2.x += overlap;
  73653. body2.velocity.x = v1 - v2 * body2.bounce.x;
  73654. // This is special case code that handles things like vertically moving platforms you can ride
  73655. if (body1.moves)
  73656. {
  73657. body2.y += (body1.y - body1.prev.y) * body1.friction.y;
  73658. }
  73659. }
  73660. // If we got this far then there WAS overlap, and separation is complete, so return true
  73661. return true;
  73662. },
  73663. /**
  73664. * The core separation function to separate two physics bodies on the y axis.
  73665. *
  73666. * @private
  73667. * @method Phaser.Physics.Arcade#separateY
  73668. * @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate.
  73669. * @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate.
  73670. * @param {boolean} overlapOnly - If true the bodies will only have their overlap data set, no separation or exchange of velocity will take place.
  73671. * @return {boolean} Returns true if the bodies were separated or overlap, otherwise false.
  73672. */
  73673. separateY: function (body1, body2, overlapOnly) {
  73674. var overlap = this.getOverlapY(body1, body2, overlapOnly);
  73675. // Can't separate two immovable bodies, or a body with its own custom separation logic
  73676. if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateY || body2.customSeparateY)
  73677. {
  73678. // return true if there was some overlap, otherwise false
  73679. return (overlap !== 0) || (body1.embedded && body2.embedded);
  73680. }
  73681. // Adjust their positions and velocities accordingly (if there was any overlap)
  73682. var v1 = body1.velocity.y;
  73683. var v2 = body2.velocity.y;
  73684. if (!body1.immovable && !body2.immovable)
  73685. {
  73686. overlap *= 0.5;
  73687. body1.y -= overlap;
  73688. body2.y += overlap;
  73689. var nv1 = Math.sqrt((v2 * v2 * body2.mass) / body1.mass) * ((v2 > 0) ? 1 : -1);
  73690. var nv2 = Math.sqrt((v1 * v1 * body1.mass) / body2.mass) * ((v1 > 0) ? 1 : -1);
  73691. var avg = (nv1 + nv2) * 0.5;
  73692. nv1 -= avg;
  73693. nv2 -= avg;
  73694. body1.velocity.y = avg + nv1 * body1.bounce.y;
  73695. body2.velocity.y = avg + nv2 * body2.bounce.y;
  73696. }
  73697. else if (!body1.immovable)
  73698. {
  73699. body1.y -= overlap;
  73700. body1.velocity.y = v2 - v1 * body1.bounce.y;
  73701. // This is special case code that handles things like horizontal moving platforms you can ride
  73702. if (body2.moves)
  73703. {
  73704. body1.x += (body2.x - body2.prev.x) * body2.friction.x;
  73705. }
  73706. }
  73707. else
  73708. {
  73709. body2.y += overlap;
  73710. body2.velocity.y = v1 - v2 * body2.bounce.y;
  73711. // This is special case code that handles things like horizontal moving platforms you can ride
  73712. if (body1.moves)
  73713. {
  73714. body2.x += (body1.x - body1.prev.x) * body1.friction.x;
  73715. }
  73716. }
  73717. // If we got this far then there WAS overlap, and separation is complete, so return true
  73718. return true;
  73719. },
  73720. /**
  73721. * Given a Group and a Pointer this will check to see which Group children overlap with the Pointer coordinates.
  73722. * Each child will be sent to the given callback for further processing.
  73723. * Note that the children are not checked for depth order, but simply if they overlap the Pointer or not.
  73724. *
  73725. * @method Phaser.Physics.Arcade#getObjectsUnderPointer
  73726. * @param {Phaser.Pointer} pointer - The Pointer to check.
  73727. * @param {Phaser.Group} group - The Group to check.
  73728. * @param {function} [callback] - A callback function that is called if the object overlaps with the Pointer. The callback will be sent two parameters: the Pointer and the Object that overlapped with it.
  73729. * @param {object} [callbackContext] - The context in which to run the callback.
  73730. * @return {PIXI.DisplayObject[]} An array of the Sprites from the Group that overlapped the Pointer coordinates.
  73731. */
  73732. getObjectsUnderPointer: function (pointer, group, callback, callbackContext) {
  73733. if (group.length === 0 || !pointer.exists)
  73734. {
  73735. return;
  73736. }
  73737. return this.getObjectsAtLocation(pointer.x, pointer.y, group, callback, callbackContext, pointer);
  73738. },
  73739. /**
  73740. * Given a Group and a location this will check to see which Group children overlap with the coordinates.
  73741. * Each child will be sent to the given callback for further processing.
  73742. * Note that the children are not checked for depth order, but simply if they overlap the coordinate or not.
  73743. *
  73744. * @method Phaser.Physics.Arcade#getObjectsAtLocation
  73745. * @param {number} x - The x coordinate to check.
  73746. * @param {number} y - The y coordinate to check.
  73747. * @param {Phaser.Group} group - The Group to check.
  73748. * @param {function} [callback] - A callback function that is called if the object overlaps the coordinates. The callback will be sent two parameters: the callbackArg and the Object that overlapped the location.
  73749. * @param {object} [callbackContext] - The context in which to run the callback.
  73750. * @param {object} [callbackArg] - An argument to pass to the callback.
  73751. * @return {PIXI.DisplayObject[]} An array of the Sprites from the Group that overlapped the coordinates.
  73752. */
  73753. getObjectsAtLocation: function (x, y, group, callback, callbackContext, callbackArg) {
  73754. this.quadTree.clear();
  73755. this.quadTree.reset(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels);
  73756. this.quadTree.populate(group);
  73757. var rect = new Phaser.Rectangle(x, y, 1, 1);
  73758. var output = [];
  73759. var items = this.quadTree.retrieve(rect);
  73760. for (var i = 0; i < items.length; i++)
  73761. {
  73762. if (items[i].hitTest(x, y))
  73763. {
  73764. if (callback)
  73765. {
  73766. callback.call(callbackContext, callbackArg, items[i].sprite);
  73767. }
  73768. output.push(items[i].sprite);
  73769. }
  73770. }
  73771. return output;
  73772. },
  73773. /**
  73774. * Move the given display object towards the destination object at a steady velocity.
  73775. * If you specify a maxTime then it will adjust the speed (overwriting what you set) so it arrives at the destination in that number of seconds.
  73776. * Timings are approximate due to the way browser timers work. Allow for a variance of +- 50ms.
  73777. * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course.
  73778. * Note: The display object doesn't stop moving once it reaches the destination coordinates.
  73779. * Note: Doesn't take into account acceleration, maxVelocity or drag (if you've set drag or acceleration too high this object may not move at all)
  73780. *
  73781. * @method Phaser.Physics.Arcade#moveToObject
  73782. * @param {any} displayObject - The display object to move.
  73783. * @param {any} destination - The display object to move towards. Can be any object but must have visible x/y properties.
  73784. * @param {number} [speed=60] - The speed it will move, in pixels per second (default is 60 pixels/sec)
  73785. * @param {number} [maxTime=0] - Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the object will arrive at destination in the given number of ms.
  73786. * @return {number} The angle (in radians) that the object should be visually set to in order to match its new velocity.
  73787. */
  73788. moveToObject: function (displayObject, destination, speed, maxTime) {
  73789. if (speed === undefined) { speed = 60; }
  73790. if (maxTime === undefined) { maxTime = 0; }
  73791. var angle = Math.atan2(destination.y - displayObject.y, destination.x - displayObject.x);
  73792. if (maxTime > 0)
  73793. {
  73794. // We know how many pixels we need to move, but how fast?
  73795. speed = this.distanceBetween(displayObject, destination) / (maxTime / 1000);
  73796. }
  73797. displayObject.body.velocity.setToPolar(angle, speed);
  73798. return angle;
  73799. },
  73800. /**
  73801. * Move the given display object towards the pointer at a steady velocity. If no pointer is given it will use Phaser.Input.activePointer.
  73802. * If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.
  73803. * Timings are approximate due to the way browser timers work. Allow for a variance of +- 50ms.
  73804. * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course.
  73805. * Note: The display object doesn't stop moving once it reaches the destination coordinates.
  73806. *
  73807. * @method Phaser.Physics.Arcade#moveToPointer
  73808. * @param {any} displayObject - The display object to move.
  73809. * @param {number} [speed=60] - The speed it will move, in pixels per second (default is 60 pixels/sec)
  73810. * @param {Phaser.Pointer} [pointer] - The pointer to move towards. Defaults to Phaser.Input.activePointer.
  73811. * @param {number} [maxTime=0] - Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the object will arrive at destination in the given number of ms.
  73812. * @return {number} The angle (in radians) that the object should be visually set to in order to match its new velocity.
  73813. */
  73814. moveToPointer: function (displayObject, speed, pointer, maxTime) {
  73815. if (speed === undefined) { speed = 60; }
  73816. pointer = pointer || this.game.input.activePointer;
  73817. if (maxTime === undefined) { maxTime = 0; }
  73818. var angle = this.angleToPointer(displayObject, pointer);
  73819. if (maxTime > 0)
  73820. {
  73821. // We know how many pixels we need to move, but how fast?
  73822. speed = this.distanceToPointer(displayObject, pointer) / (maxTime / 1000);
  73823. }
  73824. displayObject.body.velocity.setToPolar(angle, speed);
  73825. return angle;
  73826. },
  73827. /**
  73828. * Move the given display object towards the x/y coordinates at a steady velocity.
  73829. * If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.
  73830. * Timings are approximate due to the way browser timers work. Allow for a variance of +- 50ms.
  73831. * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course.
  73832. * Note: The display object doesn't stop moving once it reaches the destination coordinates.
  73833. * Note: Doesn't take into account acceleration, maxVelocity or drag (if you've set drag or acceleration too high this object may not move at all)
  73834. *
  73835. * @method Phaser.Physics.Arcade#moveToXY
  73836. * @param {any} displayObject - The display object to move.
  73837. * @param {number} x - The x coordinate to move towards.
  73838. * @param {number} y - The y coordinate to move towards.
  73839. * @param {number} [speed=60] - The speed it will move, in pixels per second (default is 60 pixels/sec)
  73840. * @param {number} [maxTime=0] - Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the object will arrive at destination in the given number of ms.
  73841. * @return {number} The angle (in radians) that the object should be visually set to in order to match its new velocity.
  73842. */
  73843. moveToXY: function (displayObject, x, y, speed, maxTime) {
  73844. if (speed === undefined) { speed = 60; }
  73845. if (maxTime === undefined) { maxTime = 0; }
  73846. var angle = Math.atan2(y - displayObject.y, x - displayObject.x);
  73847. if (maxTime > 0)
  73848. {
  73849. // We know how many pixels we need to move, but how fast?
  73850. speed = this.distanceToXY(displayObject, x, y) / (maxTime / 1000);
  73851. }
  73852. displayObject.body.velocity.setToPolar(angle, speed);
  73853. return angle;
  73854. },
  73855. /**
  73856. * Given the angle (in degrees) and speed calculate the velocity and return it as a Point object, or set it to the given point object.
  73857. * One way to use this is: velocityFromAngle(angle, 200, sprite.velocity) which will set the values directly to the sprites velocity and not create a new Point object.
  73858. *
  73859. * @method Phaser.Physics.Arcade#velocityFromAngle
  73860. * @param {number} angle - The angle in degrees calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
  73861. * @param {number} [speed=60] - The speed it will move, in pixels per second sq.
  73862. * @param {Phaser.Point|object} [point] - The Point object in which the x and y properties will be set to the calculated velocity.
  73863. * @return {Phaser.Point} - A Point where point.x contains the velocity x value and point.y contains the velocity y value.
  73864. */
  73865. velocityFromAngle: function (angle, speed, point) {
  73866. if (speed === undefined) { speed = 60; }
  73867. point = point || new Phaser.Point();
  73868. return point.setToPolar(angle, speed, true);
  73869. },
  73870. /**
  73871. * Given the rotation (in radians) and speed calculate the velocity and return it as a Point object, or set it to the given point object.
  73872. * One way to use this is: velocityFromRotation(rotation, 200, sprite.velocity) which will set the values directly to the sprites velocity and not create a new Point object.
  73873. *
  73874. * @method Phaser.Physics.Arcade#velocityFromRotation
  73875. * @param {number} rotation - The angle in radians.
  73876. * @param {number} [speed=60] - The speed it will move, in pixels per second sq.
  73877. * @param {Phaser.Point|object} [point] - The Point object in which the x and y properties will be set to the calculated velocity.
  73878. * @return {Phaser.Point} - A Point where point.x contains the velocity x value and point.y contains the velocity y value.
  73879. */
  73880. velocityFromRotation: function (rotation, speed, point) {
  73881. if (speed === undefined) { speed = 60; }
  73882. point = point || new Phaser.Point();
  73883. return point.setToPolar(rotation, speed);
  73884. },
  73885. /**
  73886. * Given the rotation (in radians) and speed calculate the acceleration and return it as a Point object, or set it to the given point object.
  73887. * One way to use this is: accelerationFromRotation(rotation, 200, sprite.acceleration) which will set the values directly to the sprites acceleration and not create a new Point object.
  73888. *
  73889. * @method Phaser.Physics.Arcade#accelerationFromRotation
  73890. * @param {number} rotation - The angle in radians.
  73891. * @param {number} [speed=60] - The speed it will move, in pixels per second sq.
  73892. * @param {Phaser.Point|object} [point] - The Point object in which the x and y properties will be set to the calculated acceleration.
  73893. * @return {Phaser.Point} - A Point where point.x contains the acceleration x value and point.y contains the acceleration y value.
  73894. */
  73895. accelerationFromRotation: function (rotation, speed, point) {
  73896. if (speed === undefined) { speed = 60; }
  73897. point = point || new Phaser.Point();
  73898. return point.setToPolar(rotation, speed);
  73899. },
  73900. /**
  73901. * Sets the acceleration.x/y property on the display object so it will move towards the target at the given speed (in pixels per second sq.)
  73902. * You must give a maximum speed value, beyond which the display object won't go any faster.
  73903. * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course.
  73904. * Note: The display object doesn't stop moving once it reaches the destination coordinates.
  73905. *
  73906. * @method Phaser.Physics.Arcade#accelerateToObject
  73907. * @param {any} displayObject - The display object to move.
  73908. * @param {any} destination - The display object to move towards. Can be any object but must have visible x/y properties.
  73909. * @param {number} [speed=60] - The speed it will accelerate in pixels per second.
  73910. * @param {number} [xSpeedMax=500] - The maximum x velocity the display object can reach.
  73911. * @param {number} [ySpeedMax=500] - The maximum y velocity the display object can reach.
  73912. * @return {number} The angle (in radians) that the object should be visually set to in order to match its new trajectory.
  73913. */
  73914. accelerateToObject: function (displayObject, destination, speed, xSpeedMax, ySpeedMax) {
  73915. if (speed === undefined) { speed = 60; }
  73916. if (xSpeedMax === undefined) { xSpeedMax = 1000; }
  73917. if (ySpeedMax === undefined) { ySpeedMax = 1000; }
  73918. var angle = this.angleBetween(displayObject, destination);
  73919. displayObject.body.acceleration.setToPolar(angle, speed);
  73920. displayObject.body.maxVelocity.setTo(xSpeedMax, ySpeedMax);
  73921. return angle;
  73922. },
  73923. /**
  73924. * Sets the acceleration.x/y property on the display object so it will move towards the target at the given speed (in pixels per second sq.)
  73925. * You must give a maximum speed value, beyond which the display object won't go any faster.
  73926. * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course.
  73927. * Note: The display object doesn't stop moving once it reaches the destination coordinates.
  73928. *
  73929. * @method Phaser.Physics.Arcade#accelerateToPointer
  73930. * @param {any} displayObject - The display object to move.
  73931. * @param {Phaser.Pointer} [pointer] - The pointer to move towards. Defaults to Phaser.Input.activePointer.
  73932. * @param {number} [speed=60] - The speed it will accelerate in pixels per second.
  73933. * @param {number} [xSpeedMax=500] - The maximum x velocity the display object can reach.
  73934. * @param {number} [ySpeedMax=500] - The maximum y velocity the display object can reach.
  73935. * @return {number} The angle (in radians) that the object should be visually set to in order to match its new trajectory.
  73936. */
  73937. accelerateToPointer: function (displayObject, pointer, speed, xSpeedMax, ySpeedMax) {
  73938. if (speed === undefined) { speed = 60; }
  73939. if (pointer === undefined) { pointer = this.game.input.activePointer; }
  73940. if (xSpeedMax === undefined) { xSpeedMax = 1000; }
  73941. if (ySpeedMax === undefined) { ySpeedMax = 1000; }
  73942. var angle = this.angleToPointer(displayObject, pointer);
  73943. displayObject.body.acceleration.setToPolar(angle, speed);
  73944. displayObject.body.maxVelocity.setTo(xSpeedMax, ySpeedMax);
  73945. return angle;
  73946. },
  73947. /**
  73948. * Sets the acceleration.x/y property on the display object so it will move towards the x/y coordinates at the given speed (in pixels per second sq.)
  73949. * You must give a maximum speed value, beyond which the display object won't go any faster.
  73950. * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course.
  73951. * Note: The display object doesn't stop moving once it reaches the destination coordinates.
  73952. *
  73953. * @method Phaser.Physics.Arcade#accelerateToXY
  73954. * @param {any} displayObject - The display object to move.
  73955. * @param {number} x - The x coordinate to accelerate towards.
  73956. * @param {number} y - The y coordinate to accelerate towards.
  73957. * @param {number} [speed=60] - The speed it will accelerate in pixels per second.
  73958. * @param {number} [xSpeedMax=500] - The maximum x velocity the display object can reach.
  73959. * @param {number} [ySpeedMax=500] - The maximum y velocity the display object can reach.
  73960. * @return {number} The angle (in radians) that the object should be visually set to in order to match its new trajectory.
  73961. */
  73962. accelerateToXY: function (displayObject, x, y, speed, xSpeedMax, ySpeedMax) {
  73963. if (speed === undefined) { speed = 60; }
  73964. if (xSpeedMax === undefined) { xSpeedMax = 1000; }
  73965. if (ySpeedMax === undefined) { ySpeedMax = 1000; }
  73966. var angle = this.angleToXY(displayObject, x, y);
  73967. displayObject.body.acceleration.setTo(angle, speed);
  73968. displayObject.body.maxVelocity.setTo(xSpeedMax, ySpeedMax);
  73969. return angle;
  73970. },
  73971. /**
  73972. * Find the distance between two display objects (like Sprites).
  73973. *
  73974. * The optional `world` argument allows you to return the result based on the Game Objects `world` property,
  73975. * instead of its `x` and `y` values. This is useful of the object has been nested inside an offset Group,
  73976. * or parent Game Object.
  73977. *
  73978. * @method Phaser.Physics.Arcade#distanceBetween
  73979. * @param {any} source - The Display Object to test from.
  73980. * @param {any} target - The Display Object to test to.
  73981. * @param {boolean} [world=false] - Calculate the distance using World coordinates (true), or Object coordinates (false, the default)
  73982. * @return {number} The distance between the source and target objects.
  73983. */
  73984. distanceBetween: function (source, target, world) {
  73985. if (world === undefined) { world = false; }
  73986. var dx = (world) ? source.world.x - target.world.x : source.x - target.x;
  73987. var dy = (world) ? source.world.y - target.world.y : source.y - target.y;
  73988. return Math.sqrt(dx * dx + dy * dy);
  73989. },
  73990. /**
  73991. * Find the distance between a display object (like a Sprite) and the given x/y coordinates.
  73992. * The calculation is made from the display objects x/y coordinate. This may be the top-left if its anchor hasn't been changed.
  73993. * If you need to calculate from the center of a display object instead use the method distanceBetweenCenters()
  73994. *
  73995. * The optional `world` argument allows you to return the result based on the Game Objects `world` property,
  73996. * instead of its `x` and `y` values. This is useful of the object has been nested inside an offset Group,
  73997. * or parent Game Object.
  73998. *
  73999. * @method Phaser.Physics.Arcade#distanceToXY
  74000. * @param {any} displayObject - The Display Object to test from.
  74001. * @param {number} x - The x coordinate to move towards.
  74002. * @param {number} y - The y coordinate to move towards.
  74003. * @param {boolean} [world=false] - Calculate the distance using World coordinates (true), or Object coordinates (false, the default)
  74004. * @return {number} The distance between the object and the x/y coordinates.
  74005. */
  74006. distanceToXY: function (displayObject, x, y, world) {
  74007. if (world === undefined) { world = false; }
  74008. var dx = (world) ? displayObject.world.x - x : displayObject.x - x;
  74009. var dy = (world) ? displayObject.world.y - y : displayObject.y - y;
  74010. return Math.sqrt(dx * dx + dy * dy);
  74011. },
  74012. /**
  74013. * Find the distance between a display object (like a Sprite) and a Pointer. If no Pointer is given the Input.activePointer is used.
  74014. * The calculation is made from the display objects x/y coordinate. This may be the top-left if its anchor hasn't been changed.
  74015. * If you need to calculate from the center of a display object instead use the method distanceBetweenCenters()
  74016. *
  74017. * The optional `world` argument allows you to return the result based on the Game Objects `world` property,
  74018. * instead of its `x` and `y` values. This is useful of the object has been nested inside an offset Group,
  74019. * or parent Game Object.
  74020. *
  74021. * @method Phaser.Physics.Arcade#distanceToPointer
  74022. * @param {any} displayObject - The Display Object to test from.
  74023. * @param {Phaser.Pointer} [pointer] - The Phaser.Pointer to test to. If none is given then Input.activePointer is used.
  74024. * @param {boolean} [world=false] - Calculate the distance using World coordinates (true), or Object coordinates (false, the default)
  74025. * @return {number} The distance between the object and the Pointer.
  74026. */
  74027. distanceToPointer: function (displayObject, pointer, world) {
  74028. if (pointer === undefined) { pointer = this.game.input.activePointer; }
  74029. if (world === undefined) { world = false; }
  74030. var dx = (world) ? displayObject.world.x - pointer.worldX : displayObject.x - pointer.worldX;
  74031. var dy = (world) ? displayObject.world.y - pointer.worldY : displayObject.y - pointer.worldY;
  74032. return Math.sqrt(dx * dx + dy * dy);
  74033. },
  74034. /**
  74035. * From a set of points or display objects, find the one closest to a source point or object.
  74036. *
  74037. * @method Phaser.Physics.Arcade#closest
  74038. * @param {any} source - The {@link Phaser.Point Point} or Display Object distances will be measured from.
  74039. * @param {any[]} targets - The {@link Phaser.Point Points} or Display Objects whose distances to the source will be compared.
  74040. * @param {boolean} [world=false] - Calculate the distance using World coordinates (true), or Object coordinates (false, the default).
  74041. * @return {any} - The first target closest to the origin.
  74042. */
  74043. closest: function (source, targets, world) {
  74044. var min = Infinity;
  74045. var closest = null;
  74046. for (var i = 0, len = targets.length; i < len; i++)
  74047. {
  74048. var target = targets[i];
  74049. var distance = this.distanceBetween(source, target, world);
  74050. if (distance < min)
  74051. {
  74052. closest = target;
  74053. min = distance;
  74054. }
  74055. }
  74056. return closest;
  74057. },
  74058. /**
  74059. * From a set of points or display objects, find the one farthest from a source point or object.
  74060. *
  74061. * @method Phaser.Physics.Arcade#farthest
  74062. * @param {any} source - The {@link Phaser.Point Point} or Display Object distances will be measured from.
  74063. * @param {any[]} targets - The {@link Phaser.Point Points} or Display Objects whose distances to the source will be compared.
  74064. * @param {boolean} [world=false] - Calculate the distance using World coordinates (true), or Object coordinates (false, the default).
  74065. * @return {any} - The target closest to the origin.
  74066. */
  74067. farthest: function (source, targets, world) {
  74068. var max = -1;
  74069. var farthest = null;
  74070. for (var i = 0, len = targets.length; i < len; i++)
  74071. {
  74072. var target = targets[i];
  74073. var distance = this.distanceBetween(source, target, world);
  74074. if (distance > max)
  74075. {
  74076. farthest = target;
  74077. max = distance;
  74078. }
  74079. }
  74080. return farthest;
  74081. },
  74082. /**
  74083. * Find the angle in radians between two display objects (like Sprites).
  74084. *
  74085. * The optional `world` argument allows you to return the result based on the Game Objects `world` property,
  74086. * instead of its `x` and `y` values. This is useful of the object has been nested inside an offset Group,
  74087. * or parent Game Object.
  74088. *
  74089. * @method Phaser.Physics.Arcade#angleBetween
  74090. * @param {any} source - The Display Object to test from.
  74091. * @param {any} target - The Display Object to test to.
  74092. * @param {boolean} [world=false] - Calculate the angle using World coordinates (true), or Object coordinates (false, the default)
  74093. * @return {number} The angle in radians between the source and target display objects.
  74094. */
  74095. angleBetween: function (source, target, world) {
  74096. if (world === undefined) { world = false; }
  74097. if (world)
  74098. {
  74099. return Math.atan2(target.world.y - source.world.y, target.world.x - source.world.x);
  74100. }
  74101. else
  74102. {
  74103. return Math.atan2(target.y - source.y, target.x - source.x);
  74104. }
  74105. },
  74106. /**
  74107. * Find the angle in radians between centers of two display objects (like Sprites).
  74108. *
  74109. * @method Phaser.Physics.Arcade#angleBetweenCenters
  74110. * @param {any} source - The Display Object to test from.
  74111. * @param {any} target - The Display Object to test to.
  74112. * @return {number} The angle in radians between the source and target display objects.
  74113. */
  74114. angleBetweenCenters: function (source, target) {
  74115. var dx = target.centerX - source.centerX;
  74116. var dy = target.centerY - source.centerY;
  74117. return Math.atan2(dy, dx);
  74118. },
  74119. /**
  74120. * Find the angle in radians between a display object (like a Sprite) and the given x/y coordinate.
  74121. *
  74122. * The optional `world` argument allows you to return the result based on the Game Objects `world` property,
  74123. * instead of its `x` and `y` values. This is useful of the object has been nested inside an offset Group,
  74124. * or parent Game Object.
  74125. *
  74126. * @method Phaser.Physics.Arcade#angleToXY
  74127. * @param {any} displayObject - The Display Object to test from.
  74128. * @param {number} x - The x coordinate to get the angle to.
  74129. * @param {number} y - The y coordinate to get the angle to.
  74130. * @param {boolean} [world=false] - Calculate the angle using World coordinates (true), or Object coordinates (false, the default)
  74131. * @return {number} The angle in radians between displayObject.x/y to Pointer.x/y
  74132. */
  74133. angleToXY: function (displayObject, x, y, world) {
  74134. if (world === undefined) { world = false; }
  74135. if (world)
  74136. {
  74137. return Math.atan2(y - displayObject.world.y, x - displayObject.world.x);
  74138. }
  74139. else
  74140. {
  74141. return Math.atan2(y - displayObject.y, x - displayObject.x);
  74142. }
  74143. },
  74144. /**
  74145. * Find the angle in radians between a display object (like a Sprite) and a Pointer, taking their x/y and center into account.
  74146. *
  74147. * The optional `world` argument allows you to return the result based on the Game Objects `world` property,
  74148. * instead of its `x` and `y` values. This is useful of the object has been nested inside an offset Group,
  74149. * or parent Game Object.
  74150. *
  74151. * @method Phaser.Physics.Arcade#angleToPointer
  74152. * @param {any} displayObject - The Display Object to test from.
  74153. * @param {Phaser.Pointer} [pointer] - The Phaser.Pointer to test to. If none is given then Input.activePointer is used.
  74154. * @param {boolean} [world=false] - Calculate the angle using World coordinates (true), or Object coordinates (false, the default)
  74155. * @return {number} The angle in radians between displayObject.x/y to Pointer.x/y
  74156. */
  74157. angleToPointer: function (displayObject, pointer, world) {
  74158. if (pointer === undefined) { pointer = this.game.input.activePointer; }
  74159. if (world === undefined) { world = false; }
  74160. if (world)
  74161. {
  74162. return Math.atan2(pointer.worldY - displayObject.world.y, pointer.worldX - displayObject.world.x);
  74163. }
  74164. else
  74165. {
  74166. return Math.atan2(pointer.worldY - displayObject.y, pointer.worldX - displayObject.x);
  74167. }
  74168. },
  74169. /**
  74170. * Find the angle in radians between a display object (like a Sprite) and a Pointer,
  74171. * taking their x/y and center into account relative to the world.
  74172. *
  74173. * @method Phaser.Physics.Arcade#worldAngleToPointer
  74174. * @param {any} displayObject - The DisplayObjerct to test from.
  74175. * @param {Phaser.Pointer} [pointer] - The Phaser.Pointer to test to. If none is given then Input.activePointer is used.
  74176. * @return {number} The angle in radians between displayObject.world.x/y to Pointer.worldX / worldY
  74177. */
  74178. worldAngleToPointer: function (displayObject, pointer) {
  74179. return this.angleToPointer(displayObject, pointer, true);
  74180. }
  74181. };
  74182. /**
  74183. * @author Richard Davey <rich@photonstorm.com>
  74184. * @copyright 2016 Photon Storm Ltd.
  74185. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  74186. */
  74187. /**
  74188. * The Physics Body is linked to a single Sprite. All physics operations should be performed against the body rather than
  74189. * the Sprite itself. For example you can set the velocity, acceleration, bounce values etc all on the Body.
  74190. *
  74191. * @class Phaser.Physics.Arcade.Body
  74192. * @constructor
  74193. * @param {Phaser.Sprite} sprite - The Sprite object this physics body belongs to.
  74194. */
  74195. Phaser.Physics.Arcade.Body = function (sprite) {
  74196. /**
  74197. * @property {Phaser.Sprite} sprite - Reference to the parent Sprite.
  74198. */
  74199. this.sprite = sprite;
  74200. /**
  74201. * @property {Phaser.Game} game - Local reference to game.
  74202. */
  74203. this.game = sprite.game;
  74204. /**
  74205. * @property {number} type - The type of physics system this body belongs to.
  74206. */
  74207. this.type = Phaser.Physics.ARCADE;
  74208. /**
  74209. * @property {boolean} enable - A disabled body won't be checked for any form of collision or overlap or have its pre/post updates run.
  74210. * @default
  74211. */
  74212. this.enable = true;
  74213. /**
  74214. * If `true` this Body is using circular collision detection. If `false` it is using rectangular.
  74215. * Use `Body.setCircle` to control the collision shape this Body uses.
  74216. * @property {boolean} isCircle
  74217. * @default
  74218. * @readOnly
  74219. */
  74220. this.isCircle = false;
  74221. /**
  74222. * The radius of the circular collision shape this Body is using if Body.setCircle has been enabled, relative to the Sprite's _texture_.
  74223. * If you wish to change the radius then call {@link #setCircle} again with the new value.
  74224. * If you wish to stop the Body using a circle then call {@link #setCircle} with a radius of zero (or undefined).
  74225. * The actual radius of the Body (at any Sprite scale) is equal to {@link #halfWidth} and the diameter is equal to {@link #width}.
  74226. * @property {number} radius
  74227. * @default
  74228. * @readOnly
  74229. */
  74230. this.radius = 0;
  74231. /**
  74232. * @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite's texture.
  74233. */
  74234. this.offset = new Phaser.Point();
  74235. /**
  74236. * @property {Phaser.Point} position - The position of the physics body, equivalent to ({@link #left}, {@link #top}).
  74237. * @readonly
  74238. */
  74239. this.position = new Phaser.Point(sprite.x, sprite.y);
  74240. /**
  74241. * @property {Phaser.Point} prev - The previous position of the physics body.
  74242. * @readonly
  74243. */
  74244. this.prev = new Phaser.Point(this.position.x, this.position.y);
  74245. /**
  74246. * @property {boolean} allowRotation - Allow this Body to be rotated? (via angularVelocity, etc)
  74247. * @default
  74248. */
  74249. this.allowRotation = true;
  74250. /**
  74251. * The Body's rotation in degrees, as calculated by its angularVelocity and angularAcceleration. Please understand that the collision Body
  74252. * itself never rotates, it is always axis-aligned. However these values are passed up to the parent Sprite and updates its rotation.
  74253. * @property {number} rotation
  74254. */
  74255. this.rotation = sprite.angle;
  74256. /**
  74257. * @property {number} preRotation - The previous rotation of the physics body, in degrees.
  74258. * @readonly
  74259. */
  74260. this.preRotation = sprite.angle;
  74261. /**
  74262. * @property {number} width - The calculated width of the physics body.
  74263. * @readonly
  74264. */
  74265. this.width = sprite.width;
  74266. /**
  74267. * @property {number} height - The calculated height of the physics body.
  74268. * @readonly
  74269. */
  74270. this.height = sprite.height;
  74271. /**
  74272. * @property {number} sourceWidth - The un-scaled original size.
  74273. * @readonly
  74274. */
  74275. this.sourceWidth = sprite.width;
  74276. /**
  74277. * @property {number} sourceHeight - The un-scaled original size.
  74278. * @readonly
  74279. */
  74280. this.sourceHeight = sprite.height;
  74281. if (sprite.texture)
  74282. {
  74283. this.sourceWidth = sprite.texture.frame.width;
  74284. this.sourceHeight = sprite.texture.frame.height;
  74285. }
  74286. /**
  74287. * @property {number} halfWidth - The calculated width / 2 of the physics body.
  74288. * @readonly
  74289. */
  74290. this.halfWidth = Math.abs(sprite.width / 2);
  74291. /**
  74292. * @property {number} halfHeight - The calculated height / 2 of the physics body.
  74293. * @readonly
  74294. */
  74295. this.halfHeight = Math.abs(sprite.height / 2);
  74296. /**
  74297. * @property {Phaser.Point} center - The center coordinate of the Physics Body.
  74298. * @readonly
  74299. */
  74300. this.center = new Phaser.Point(sprite.x + this.halfWidth, sprite.y + this.halfHeight);
  74301. /**
  74302. * @property {Phaser.Point} velocity - The velocity, or rate of change the Body's position. Measured in pixels per second.
  74303. */
  74304. this.velocity = new Phaser.Point();
  74305. /**
  74306. * @property {Phaser.Point} newVelocity - The distanced traveled during the last update, equal to `velocity * physicsElapsed`. Calculated during the Body.preUpdate and applied to its position.
  74307. * @readonly
  74308. */
  74309. this.newVelocity = new Phaser.Point();
  74310. /**
  74311. * @property {Phaser.Point} deltaMax - The Sprite position is updated based on the delta x/y values. You can set a cap on those (both +-) using deltaMax.
  74312. */
  74313. this.deltaMax = new Phaser.Point();
  74314. /**
  74315. * @property {Phaser.Point} acceleration - The acceleration is the rate of change of the velocity. Measured in pixels per second squared.
  74316. */
  74317. this.acceleration = new Phaser.Point();
  74318. /**
  74319. * @property {boolean} allowDrag - Allow this Body to be influenced by {@link #drag}?
  74320. * @default
  74321. */
  74322. this.allowDrag = true;
  74323. /**
  74324. * @property {Phaser.Point} drag - The drag applied to the motion of the Body (when {@link #allowDrag} is enabled). Measured in pixels per second squared.
  74325. */
  74326. this.drag = new Phaser.Point();
  74327. /**
  74328. * @property {boolean} allowGravity - Allow this Body to be influenced by gravity? Either world or local.
  74329. * @default
  74330. */
  74331. this.allowGravity = true;
  74332. /**
  74333. * @property {Phaser.Point} gravity - This Body's local gravity, **added** to any world gravity, unless Body.allowGravity is set to false.
  74334. */
  74335. this.gravity = new Phaser.Point();
  74336. /**
  74337. * @property {Phaser.Point} bounce - The elasticity of the Body when colliding. bounce.x/y = 1 means full rebound, bounce.x/y = 0.5 means 50% rebound velocity.
  74338. */
  74339. this.bounce = new Phaser.Point();
  74340. /**
  74341. * The elasticity of the Body when colliding with the World bounds.
  74342. * By default this property is `null`, in which case `Body.bounce` is used instead. Set this property
  74343. * to a Phaser.Point object in order to enable a World bounds specific bounce value.
  74344. * @property {Phaser.Point} worldBounce
  74345. */
  74346. this.worldBounce = null;
  74347. /**
  74348. * A Signal that is dispatched when this Body collides with the world bounds.
  74349. * Due to the potentially high volume of signals this could create it is disabled by default.
  74350. * To use this feature set this property to a Phaser.Signal: `sprite.body.onWorldBounds = new Phaser.Signal()`
  74351. * and it will be called when a collision happens, passing five arguments:
  74352. * `onWorldBounds(sprite, up, down, left, right)`
  74353. * where the Sprite is a reference to the Sprite that owns this Body, and the other arguments are booleans
  74354. * indicating on which side of the world the Body collided.
  74355. * @property {Phaser.Signal} onWorldBounds
  74356. */
  74357. this.onWorldBounds = null;
  74358. /**
  74359. * A Signal that is dispatched when this Body collides with another Body.
  74360. *
  74361. * You still need to call `game.physics.arcade.collide` in your `update` method in order
  74362. * for this signal to be dispatched.
  74363. *
  74364. * Usually you'd pass a callback to the `collide` method, but this signal provides for
  74365. * a different level of notification.
  74366. *
  74367. * Due to the potentially high volume of signals this could create it is disabled by default.
  74368. *
  74369. * To use this feature set this property to a Phaser.Signal: `sprite.body.onCollide = new Phaser.Signal()`
  74370. * and it will be called when a collision happens, passing two arguments: the sprites which collided.
  74371. * The first sprite in the argument is always the owner of this Body.
  74372. *
  74373. * If two Bodies with this Signal set collide, both will dispatch the Signal.
  74374. * @property {Phaser.Signal} onCollide
  74375. */
  74376. this.onCollide = null;
  74377. /**
  74378. * A Signal that is dispatched when this Body overlaps with another Body.
  74379. *
  74380. * You still need to call `game.physics.arcade.overlap` in your `update` method in order
  74381. * for this signal to be dispatched.
  74382. *
  74383. * Usually you'd pass a callback to the `overlap` method, but this signal provides for
  74384. * a different level of notification.
  74385. *
  74386. * Due to the potentially high volume of signals this could create it is disabled by default.
  74387. *
  74388. * To use this feature set this property to a Phaser.Signal: `sprite.body.onOverlap = new Phaser.Signal()`
  74389. * and it will be called when a collision happens, passing two arguments: the sprites which collided.
  74390. * The first sprite in the argument is always the owner of this Body.
  74391. *
  74392. * If two Bodies with this Signal set collide, both will dispatch the Signal.
  74393. * @property {Phaser.Signal} onOverlap
  74394. */
  74395. this.onOverlap = null;
  74396. /**
  74397. * @property {Phaser.Point} maxVelocity - The maximum velocity (in pixels per second squared) that the Body can reach.
  74398. * @default
  74399. */
  74400. this.maxVelocity = new Phaser.Point(10000, 10000);
  74401. /**
  74402. * @property {Phaser.Point} friction - If this Body is {@link #immovable} and moving, and another Body is 'riding' this one, this is the amount of motion the riding Body receives on each axis.
  74403. */
  74404. this.friction = new Phaser.Point(1, 0);
  74405. /**
  74406. * @property {number} angularVelocity - The angular velocity is the rate of change of the Body's rotation. It is measured in degrees per second.
  74407. * @default
  74408. */
  74409. this.angularVelocity = 0;
  74410. /**
  74411. * @property {number} angularAcceleration - The angular acceleration is the rate of change of the angular velocity. Measured in degrees per second squared.
  74412. * @default
  74413. */
  74414. this.angularAcceleration = 0;
  74415. /**
  74416. * @property {number} angularDrag - The drag applied during the rotation of the Body. Measured in degrees per second squared.
  74417. * @default
  74418. */
  74419. this.angularDrag = 0;
  74420. /**
  74421. * @property {number} maxAngular - The maximum angular velocity in degrees per second that the Body can reach.
  74422. * @default
  74423. */
  74424. this.maxAngular = 1000;
  74425. /**
  74426. * @property {number} mass - The mass of the Body. When two bodies collide their mass is used in the calculation to determine the exchange of velocity.
  74427. * @default
  74428. */
  74429. this.mass = 1;
  74430. /**
  74431. * @property {number} angle - The angle of the Body's **velocity** in radians.
  74432. * @readonly
  74433. */
  74434. this.angle = 0;
  74435. /**
  74436. * @property {number} speed - The speed of the Body in pixels per second, equal to the magnitude of the velocity.
  74437. * @readonly
  74438. */
  74439. this.speed = 0;
  74440. /**
  74441. * @property {number} facing - A const reference to the direction the Body is traveling or facing: Phaser.NONE, Phaser.LEFT, Phaser.RIGHT, Phaser.UP, or Phaser.DOWN. If the Body is moving on both axes, UP and DOWN take precedence.
  74442. * @default
  74443. */
  74444. this.facing = Phaser.NONE;
  74445. /**
  74446. * @property {boolean} immovable - An immovable Body will not receive any impacts from other bodies. **Two** immovable Bodies can't separate or exchange momentum and will pass through each other.
  74447. * @default
  74448. */
  74449. this.immovable = false;
  74450. /**
  74451. * Whether the physics system should update the Body's position and rotation based on its velocity, acceleration, drag, and gravity.
  74452. *
  74453. * If you have a Body that is being moved around the world via a tween or a Group motion, but its local x/y position never
  74454. * actually changes, then you should set Body.moves = false. Otherwise it will most likely fly off the screen.
  74455. * If you want the physics system to move the body around, then set moves to true.
  74456. *
  74457. * A Body with moves = false can still be moved slightly (but not accelerated) during collision separation unless you set {@link #immovable} as well.
  74458. *
  74459. * @property {boolean} moves - Set to true to allow the Physics system to move this Body, otherwise false to move it manually.
  74460. * @default
  74461. */
  74462. this.moves = true;
  74463. /**
  74464. * This flag allows you to disable the custom x separation that takes place by Physics.Arcade.separate.
  74465. * Used in combination with your own collision processHandler you can create whatever type of collision response you need.
  74466. * @property {boolean} customSeparateX - Use a custom separation system or the built-in one?
  74467. * @default
  74468. */
  74469. this.customSeparateX = false;
  74470. /**
  74471. * This flag allows you to disable the custom y separation that takes place by Physics.Arcade.separate.
  74472. * Used in combination with your own collision processHandler you can create whatever type of collision response you need.
  74473. * @property {boolean} customSeparateY - Use a custom separation system or the built-in one?
  74474. * @default
  74475. */
  74476. this.customSeparateY = false;
  74477. /**
  74478. * When this body collides with another, the amount of overlap is stored here.
  74479. * @property {number} overlapX - The amount of horizontal overlap during the collision.
  74480. */
  74481. this.overlapX = 0;
  74482. /**
  74483. * When this body collides with another, the amount of overlap is stored here.
  74484. * @property {number} overlapY - The amount of vertical overlap during the collision.
  74485. */
  74486. this.overlapY = 0;
  74487. /**
  74488. * If `Body.isCircle` is true, and this body collides with another circular body, the amount of overlap is stored here.
  74489. * @property {number} overlapR - The amount of overlap during the collision.
  74490. */
  74491. this.overlapR = 0;
  74492. /**
  74493. * If a body is overlapping with another body, but neither of them are moving (maybe they spawned on-top of each other?) this is set to true.
  74494. * @property {boolean} embedded - Body embed value.
  74495. */
  74496. this.embedded = false;
  74497. /**
  74498. * A Body can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World.
  74499. * @property {boolean} collideWorldBounds - Should the Body collide with the World bounds?
  74500. */
  74501. this.collideWorldBounds = false;
  74502. /**
  74503. * Set the checkCollision properties to control which directions collision is processed for this Body.
  74504. * For example checkCollision.up = false means it won't collide when the collision happened while moving up.
  74505. * If you need to disable a Body entirely, use `body.enable = false`, this will also disable motion.
  74506. * If you need to disable just collision and/or overlap checks, but retain motion, set `checkCollision.none = true`.
  74507. * @property {object} checkCollision - An object containing allowed collision (none, up, down, left, right).
  74508. */
  74509. this.checkCollision = { none: false, up: true, down: true, left: true, right: true };
  74510. /**
  74511. * This object is populated with boolean values when the Body collides with another.
  74512. * touching.up = true means the collision happened to the top of this Body for example.
  74513. * @property {object} touching - An object containing touching results (none, up, down, left, right).
  74514. */
  74515. this.touching = { none: true, up: false, down: false, left: false, right: false };
  74516. /**
  74517. * This object is populated with previous touching values from the bodies previous collision.
  74518. * @property {object} wasTouching - An object containing previous touching results (none, up, down, left, right).
  74519. */
  74520. this.wasTouching = { none: true, up: false, down: false, left: false, right: false };
  74521. /**
  74522. * This object is populated with boolean values when the Body collides with the World bounds or a Tile.
  74523. * For example if blocked.up is true then the Body cannot move up.
  74524. * @property {object} blocked - An object containing on which faces this Body is blocked from moving, if any (none, up, down, left, right).
  74525. */
  74526. this.blocked = { none: true, up: false, down: false, left: false, right: false };
  74527. /**
  74528. * If this is an especially small or fast moving object then it can sometimes skip over tilemap collisions if it moves through a tile in a step.
  74529. * Set this padding value to add extra padding to its bounds. tilePadding.x applied to its width, y to its height.
  74530. * @property {Phaser.Point} tilePadding - Extra padding to be added to this sprite's dimensions when checking for tile collision.
  74531. */
  74532. this.tilePadding = new Phaser.Point();
  74533. /**
  74534. * @property {boolean} dirty - If this Body in a preUpdate (true) or postUpdate (false) state?
  74535. */
  74536. this.dirty = false;
  74537. /**
  74538. * @property {boolean} skipQuadTree - If true and you collide this Sprite against a Group, it will disable the collision check from using a QuadTree.
  74539. */
  74540. this.skipQuadTree = false;
  74541. /**
  74542. * If true the Body will check itself against the Sprite.getBounds() dimensions and adjust its width and height accordingly.
  74543. * If false it will compare its dimensions against the Sprite scale instead, and adjust its width height if the scale has changed.
  74544. * Typically you would need to enable syncBounds if your sprite is the child of a responsive display object such as a FlexLayer,
  74545. * or in any situation where the Sprite scale doesn't change, but its parents scale is effecting the dimensions regardless.
  74546. * @property {boolean} syncBounds
  74547. * @default
  74548. */
  74549. this.syncBounds = false;
  74550. /**
  74551. * @property {boolean} isMoving - Set by the `moveTo` and `moveFrom` methods.
  74552. */
  74553. this.isMoving = false;
  74554. /**
  74555. * @property {boolean} stopVelocityOnCollide - Set by the `moveTo` and `moveFrom` methods.
  74556. */
  74557. this.stopVelocityOnCollide = true;
  74558. /**
  74559. * @property {integer} moveTimer - Internal time used by the `moveTo` and `moveFrom` methods.
  74560. * @private
  74561. */
  74562. this.moveTimer = 0;
  74563. /**
  74564. * @property {integer} moveDistance - Internal distance value, used by the `moveTo` and `moveFrom` methods.
  74565. * @private
  74566. */
  74567. this.moveDistance = 0;
  74568. /**
  74569. * @property {integer} moveDuration - Internal duration value, used by the `moveTo` and `moveFrom` methods.
  74570. * @private
  74571. */
  74572. this.moveDuration = 0;
  74573. /**
  74574. * @property {Phaser.Line} moveTarget - Set by the `moveTo` method, and updated each frame.
  74575. * @private
  74576. */
  74577. this.moveTarget = null;
  74578. /**
  74579. * @property {Phaser.Point} moveEnd - Set by the `moveTo` method, and updated each frame.
  74580. * @private
  74581. */
  74582. this.moveEnd = null;
  74583. /**
  74584. * @property {Phaser.Signal} onMoveComplete - Listen for the completion of `moveTo` or `moveFrom` events.
  74585. */
  74586. this.onMoveComplete = new Phaser.Signal();
  74587. /**
  74588. * @property {function} movementCallback - Optional callback. If set, invoked during the running of `moveTo` or `moveFrom` events.
  74589. */
  74590. this.movementCallback = null;
  74591. /**
  74592. * @property {object} movementCallbackContext - Context in which to call the movementCallback.
  74593. */
  74594. this.movementCallbackContext = null;
  74595. /**
  74596. * @property {boolean} _reset - Internal cache var.
  74597. * @private
  74598. */
  74599. this._reset = true;
  74600. /**
  74601. * @property {number} _sx - Internal cache var.
  74602. * @private
  74603. */
  74604. this._sx = sprite.scale.x;
  74605. /**
  74606. * @property {number} _sy - Internal cache var.
  74607. * @private
  74608. */
  74609. this._sy = sprite.scale.y;
  74610. /**
  74611. * @property {number} _dx - Internal cache var.
  74612. * @private
  74613. */
  74614. this._dx = 0;
  74615. /**
  74616. * @property {number} _dy - Internal cache var.
  74617. * @private
  74618. */
  74619. this._dy = 0;
  74620. };
  74621. Phaser.Physics.Arcade.Body.prototype = {
  74622. /**
  74623. * Internal method.
  74624. *
  74625. * @method Phaser.Physics.Arcade.Body#updateBounds
  74626. * @protected
  74627. */
  74628. updateBounds: function () {
  74629. if (this.syncBounds)
  74630. {
  74631. var b = this.sprite.getBounds();
  74632. b.ceilAll();
  74633. if (b.width !== this.width || b.height !== this.height)
  74634. {
  74635. this.width = b.width;
  74636. this.height = b.height;
  74637. this._reset = true;
  74638. }
  74639. }
  74640. else
  74641. {
  74642. var asx = Math.abs(this.sprite.scale.x);
  74643. var asy = Math.abs(this.sprite.scale.y);
  74644. if (asx !== this._sx || asy !== this._sy)
  74645. {
  74646. this.width = this.sourceWidth * asx;
  74647. this.height = this.sourceHeight * asy;
  74648. this._sx = asx;
  74649. this._sy = asy;
  74650. this._reset = true;
  74651. }
  74652. }
  74653. if (this._reset)
  74654. {
  74655. this.halfWidth = Math.floor(this.width / 2);
  74656. this.halfHeight = Math.floor(this.height / 2);
  74657. this.updateCenter();
  74658. }
  74659. },
  74660. /**
  74661. * Update the Body's center from its position.
  74662. *
  74663. * @method Phaser.Physics.Arcade.Body#updateCenter
  74664. * @protected
  74665. */
  74666. updateCenter: function () {
  74667. this.center.setTo(this.position.x + this.halfWidth, this.position.y + this.halfHeight);
  74668. },
  74669. /**
  74670. * Internal method.
  74671. *
  74672. * @method Phaser.Physics.Arcade.Body#preUpdate
  74673. * @protected
  74674. */
  74675. preUpdate: function () {
  74676. if (!this.enable || this.game.physics.arcade.isPaused)
  74677. {
  74678. return;
  74679. }
  74680. this.dirty = true;
  74681. // Store and reset collision flags
  74682. this.wasTouching.none = this.touching.none;
  74683. this.wasTouching.up = this.touching.up;
  74684. this.wasTouching.down = this.touching.down;
  74685. this.wasTouching.left = this.touching.left;
  74686. this.wasTouching.right = this.touching.right;
  74687. this.touching.none = true;
  74688. this.touching.up = false;
  74689. this.touching.down = false;
  74690. this.touching.left = false;
  74691. this.touching.right = false;
  74692. this.blocked.none = true;
  74693. this.blocked.up = false;
  74694. this.blocked.down = false;
  74695. this.blocked.left = false;
  74696. this.blocked.right = false;
  74697. this.overlapR = 0;
  74698. this.overlapX = 0;
  74699. this.overlapY = 0;
  74700. this.embedded = false;
  74701. this.updateBounds();
  74702. this.position.x = (this.sprite.world.x - (this.sprite.anchor.x * this.sprite.width)) + this.sprite.scale.x * this.offset.x;
  74703. this.position.x -= this.sprite.scale.x < 0 ? this.width : 0;
  74704. this.position.y = (this.sprite.world.y - (this.sprite.anchor.y * this.sprite.height)) + this.sprite.scale.y * this.offset.y;
  74705. this.position.y -= this.sprite.scale.y < 0 ? this.height : 0;
  74706. this.updateCenter();
  74707. this.rotation = this.sprite.angle;
  74708. this.preRotation = this.rotation;
  74709. if (this._reset || this.sprite.fresh)
  74710. {
  74711. this.prev.x = this.position.x;
  74712. this.prev.y = this.position.y;
  74713. }
  74714. if (this.moves)
  74715. {
  74716. this.game.physics.arcade.updateMotion(this);
  74717. this.newVelocity.set(this.velocity.x * this.game.time.physicsElapsed, this.velocity.y * this.game.time.physicsElapsed);
  74718. this.position.x += this.newVelocity.x;
  74719. this.position.y += this.newVelocity.y;
  74720. this.updateCenter();
  74721. if (this.position.x !== this.prev.x || this.position.y !== this.prev.y)
  74722. {
  74723. this.angle = Math.atan2(this.velocity.y, this.velocity.x);
  74724. }
  74725. this.speed = Math.sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y);
  74726. // Now the State update will throw collision checks at the Body
  74727. // And finally we'll integrate the new position back to the Sprite in postUpdate
  74728. if (this.collideWorldBounds)
  74729. {
  74730. if (this.checkWorldBounds() && this.onWorldBounds)
  74731. {
  74732. this.onWorldBounds.dispatch(this.sprite, this.blocked.up, this.blocked.down, this.blocked.left, this.blocked.right);
  74733. }
  74734. }
  74735. }
  74736. this._dx = this.deltaX();
  74737. this._dy = this.deltaY();
  74738. this._reset = false;
  74739. },
  74740. /**
  74741. * Internal method.
  74742. *
  74743. * @method Phaser.Physics.Arcade.Body#updateMovement
  74744. * @protected
  74745. */
  74746. updateMovement: function () {
  74747. var percent = 0;
  74748. var collided = (this.overlapX !== 0 || this.overlapY !== 0);
  74749. // Duration or Distance based?
  74750. if (this.moveDuration > 0)
  74751. {
  74752. this.moveTimer += this.game.time.elapsedMS;
  74753. percent = this.moveTimer / this.moveDuration;
  74754. }
  74755. else
  74756. {
  74757. this.moveTarget.end.set(this.position.x, this.position.y);
  74758. percent = this.moveTarget.length / this.moveDistance;
  74759. }
  74760. if (this.movementCallback)
  74761. {
  74762. var result = this.movementCallback.call(this.movementCallbackContext, this, this.velocity, percent);
  74763. }
  74764. if (collided || percent >= 1 || (result !== undefined && result !== true))
  74765. {
  74766. this.stopMovement((percent >= 1) || (this.stopVelocityOnCollide && collided));
  74767. return false;
  74768. }
  74769. return true;
  74770. },
  74771. /**
  74772. * If this Body is moving as a result of a call to `moveTo` or `moveFrom` (i.e. it
  74773. * has Body.isMoving true), then calling this method will stop the movement before
  74774. * either the duration or distance counters expire.
  74775. *
  74776. * The `onMoveComplete` signal is dispatched.
  74777. *
  74778. * @method Phaser.Physics.Arcade.Body#stopMovement
  74779. * @param {boolean} [stopVelocity] - Should the Body.velocity be set to zero?
  74780. */
  74781. stopMovement: function (stopVelocity) {
  74782. if (this.isMoving)
  74783. {
  74784. this.isMoving = false;
  74785. if (stopVelocity)
  74786. {
  74787. this.velocity.set(0);
  74788. }
  74789. // Send the Sprite this Body belongs to
  74790. // and a boolean indicating if it stopped because of a collision or not
  74791. this.onMoveComplete.dispatch(this.sprite, (this.overlapX !== 0 || this.overlapY !== 0));
  74792. }
  74793. },
  74794. /**
  74795. * Internal method.
  74796. *
  74797. * @method Phaser.Physics.Arcade.Body#postUpdate
  74798. * @protected
  74799. */
  74800. postUpdate: function () {
  74801. // Only allow postUpdate to be called once per frame
  74802. if (!this.enable || !this.dirty)
  74803. {
  74804. return;
  74805. }
  74806. // Moving?
  74807. if (this.isMoving)
  74808. {
  74809. this.updateMovement();
  74810. }
  74811. this.dirty = false;
  74812. if (this.deltaX() < 0)
  74813. {
  74814. this.facing = Phaser.LEFT;
  74815. }
  74816. else if (this.deltaX() > 0)
  74817. {
  74818. this.facing = Phaser.RIGHT;
  74819. }
  74820. if (this.deltaY() < 0)
  74821. {
  74822. this.facing = Phaser.UP;
  74823. }
  74824. else if (this.deltaY() > 0)
  74825. {
  74826. this.facing = Phaser.DOWN;
  74827. }
  74828. if (this.moves)
  74829. {
  74830. this._dx = this.deltaX();
  74831. this._dy = this.deltaY();
  74832. if (this.deltaMax.x !== 0 && this._dx !== 0)
  74833. {
  74834. if (this._dx < 0 && this._dx < -this.deltaMax.x)
  74835. {
  74836. this._dx = -this.deltaMax.x;
  74837. }
  74838. else if (this._dx > 0 && this._dx > this.deltaMax.x)
  74839. {
  74840. this._dx = this.deltaMax.x;
  74841. }
  74842. }
  74843. if (this.deltaMax.y !== 0 && this._dy !== 0)
  74844. {
  74845. if (this._dy < 0 && this._dy < -this.deltaMax.y)
  74846. {
  74847. this._dy = -this.deltaMax.y;
  74848. }
  74849. else if (this._dy > 0 && this._dy > this.deltaMax.y)
  74850. {
  74851. this._dy = this.deltaMax.y;
  74852. }
  74853. }
  74854. this.sprite.position.x += this._dx;
  74855. this.sprite.position.y += this._dy;
  74856. this._reset = true;
  74857. }
  74858. this.updateCenter();
  74859. if (this.allowRotation)
  74860. {
  74861. this.sprite.angle += this.deltaZ();
  74862. }
  74863. this.prev.x = this.position.x;
  74864. this.prev.y = this.position.y;
  74865. },
  74866. /**
  74867. * Internal method.
  74868. *
  74869. * @method Phaser.Physics.Arcade.Body#checkWorldBounds
  74870. * @protected
  74871. * @return {boolean} True if the Body collided with the world bounds, otherwise false.
  74872. */
  74873. checkWorldBounds: function () {
  74874. var pos = this.position;
  74875. var bounds = this.game.physics.arcade.bounds;
  74876. var check = this.game.physics.arcade.checkCollision;
  74877. var bx = (this.worldBounce) ? -this.worldBounce.x : -this.bounce.x;
  74878. var by = (this.worldBounce) ? -this.worldBounce.y : -this.bounce.y;
  74879. if (pos.x < bounds.x && check.left)
  74880. {
  74881. pos.x = bounds.x;
  74882. this.velocity.x *= bx;
  74883. this.blocked.left = true;
  74884. this.blocked.none = false;
  74885. }
  74886. else if (this.right > bounds.right && check.right)
  74887. {
  74888. pos.x = bounds.right - this.width;
  74889. this.velocity.x *= bx;
  74890. this.blocked.right = true;
  74891. this.blocked.none = false;
  74892. }
  74893. if (pos.y < bounds.y && check.up)
  74894. {
  74895. pos.y = bounds.y;
  74896. this.velocity.y *= by;
  74897. this.blocked.up = true;
  74898. this.blocked.none = false;
  74899. }
  74900. else if (this.bottom > bounds.bottom && check.down)
  74901. {
  74902. pos.y = bounds.bottom - this.height;
  74903. this.velocity.y *= by;
  74904. this.blocked.down = true;
  74905. this.blocked.none = false;
  74906. }
  74907. return !this.blocked.none;
  74908. },
  74909. /**
  74910. * Note: This method is experimental, and may be changed or removed in a future release.
  74911. *
  74912. * This method moves the Body in the given direction, for the duration specified.
  74913. * It works by setting the velocity on the Body, and an internal timer, and then
  74914. * monitoring the duration each frame. When the duration is up the movement is
  74915. * stopped and the `Body.onMoveComplete` signal is dispatched.
  74916. *
  74917. * Movement also stops if the Body collides or overlaps with any other Body.
  74918. *
  74919. * You can control if the velocity should be reset to zero on collision, by using
  74920. * the property `Body.stopVelocityOnCollide`.
  74921. *
  74922. * Stop the movement at any time by calling `Body.stopMovement`.
  74923. *
  74924. * You can optionally set a speed in pixels per second. If not specified it
  74925. * will use the current `Body.speed` value. If this is zero, the function will return false.
  74926. *
  74927. * Please note that due to browser timings you should allow for a variance in
  74928. * when the duration will actually expire. Depending on system it may be as much as
  74929. * +- 50ms. Also this method doesn't take into consideration any other forces acting
  74930. * on the Body, such as Gravity, drag or maxVelocity, all of which may impact the
  74931. * movement.
  74932. *
  74933. * @method Phaser.Physics.Arcade.Body#moveFrom
  74934. * @param {integer} duration - The duration of the movement, in ms.
  74935. * @param {integer} [speed] - The speed of the movement, in pixels per second. If not provided `Body.speed` is used.
  74936. * @param {integer} [direction] - The angle of movement. If not provided `Body.angle` is used.
  74937. * @return {boolean} True if the movement successfully started, otherwise false.
  74938. */
  74939. moveFrom: function (duration, speed, direction) {
  74940. if (speed === undefined) { speed = this.speed; }
  74941. if (speed === 0)
  74942. {
  74943. return false;
  74944. }
  74945. var angle;
  74946. if (direction === undefined)
  74947. {
  74948. angle = this.angle;
  74949. direction = this.game.math.radToDeg(angle);
  74950. }
  74951. else
  74952. {
  74953. angle = this.game.math.degToRad(direction);
  74954. }
  74955. this.moveTimer = 0;
  74956. this.moveDuration = duration;
  74957. // Avoid sin/cos
  74958. if (direction === 0 || direction === 180)
  74959. {
  74960. this.velocity.set(Math.cos(angle) * speed, 0);
  74961. }
  74962. else if (direction === 90 || direction === 270)
  74963. {
  74964. this.velocity.set(0, Math.sin(angle) * speed);
  74965. }
  74966. else
  74967. {
  74968. this.velocity.setToPolar(angle, speed);
  74969. }
  74970. this.isMoving = true;
  74971. return true;
  74972. },
  74973. /**
  74974. * Note: This method is experimental, and may be changed or removed in a future release.
  74975. *
  74976. * This method moves the Body in the given direction, for the duration specified.
  74977. * It works by setting the velocity on the Body, and an internal distance counter.
  74978. * The distance is monitored each frame. When the distance equals the distance
  74979. * specified in this call, the movement is stopped, and the `Body.onMoveComplete`
  74980. * signal is dispatched.
  74981. *
  74982. * Movement also stops if the Body collides or overlaps with any other Body.
  74983. *
  74984. * You can control if the velocity should be reset to zero on collision, by using
  74985. * the property `Body.stopVelocityOnCollide`.
  74986. *
  74987. * Stop the movement at any time by calling `Body.stopMovement`.
  74988. *
  74989. * Please note that due to browser timings you should allow for a variance in
  74990. * when the distance will actually expire.
  74991. *
  74992. * Note: This method doesn't take into consideration any other forces acting
  74993. * on the Body, such as Gravity, drag or maxVelocity, all of which may impact the
  74994. * movement.
  74995. *
  74996. * @method Phaser.Physics.Arcade.Body#moveTo
  74997. * @param {integer} duration - The duration of the movement, in ms.
  74998. * @param {integer} distance - The distance, in pixels, the Body will move.
  74999. * @param {integer} [direction] - The angle of movement. If not provided `Body.angle` is used.
  75000. * @return {boolean} True if the movement successfully started, otherwise false.
  75001. */
  75002. moveTo: function (duration, distance, direction) {
  75003. var speed = distance / (duration / 1000);
  75004. if (speed === 0)
  75005. {
  75006. return false;
  75007. }
  75008. var angle;
  75009. if (direction === undefined)
  75010. {
  75011. angle = this.angle;
  75012. direction = this.game.math.radToDeg(angle);
  75013. }
  75014. else
  75015. {
  75016. angle = this.game.math.degToRad(direction);
  75017. }
  75018. distance = Math.abs(distance);
  75019. this.moveDuration = 0;
  75020. this.moveDistance = distance;
  75021. if (this.moveTarget === null)
  75022. {
  75023. this.moveTarget = new Phaser.Line();
  75024. this.moveEnd = new Phaser.Point();
  75025. }
  75026. this.moveTarget.fromAngle(this.x, this.y, angle, distance);
  75027. this.moveEnd.set(this.moveTarget.end.x, this.moveTarget.end.y);
  75028. this.moveTarget.setTo(this.x, this.y, this.x, this.y);
  75029. // Avoid sin/cos
  75030. if (direction === 0 || direction === 180)
  75031. {
  75032. this.velocity.set(Math.cos(angle) * speed, 0);
  75033. }
  75034. else if (direction === 90 || direction === 270)
  75035. {
  75036. this.velocity.set(0, Math.sin(angle) * speed);
  75037. }
  75038. else
  75039. {
  75040. this.velocity.setToPolar(angle, speed);
  75041. }
  75042. this.isMoving = true;
  75043. return true;
  75044. },
  75045. /**
  75046. * You can modify the size of the physics Body to be any dimension you need.
  75047. * This allows you to make it smaller, or larger, than the parent Sprite. You
  75048. * can also control the x and y offset of the Body.
  75049. *
  75050. * The width, height, and offset arguments are relative to the Sprite
  75051. * _texture_ and are scaled with the Sprite's {@link Phaser.Sprite#scale}
  75052. * (but **not** the scale of any ancestors or the {@link Phaser.Camera#scale
  75053. * Camera scale}).
  75054. *
  75055. * For example: If you have a Sprite with a texture that is 80x100 in size,
  75056. * and you want the physics body to be 32x32 pixels in the middle of the
  75057. * texture, you would do:
  75058. *
  75059. * `setSize(32 / Math.abs(this.scale.x), 32 / Math.abs(this.scale.y), 24,
  75060. * 34)`
  75061. *
  75062. * Where the first two parameters are the new Body size (32x32 pixels)
  75063. * relative to the Sprite's scale. 24 is the horizontal offset of the Body
  75064. * from the top-left of the Sprites texture, and 34 is the vertical offset.
  75065. *
  75066. * If you've scaled a Sprite by altering its `width`, `height`, or `scale`
  75067. * and you want to position the Body relative to the Sprite's dimensions
  75068. * (which will differ from its texture's dimensions), you should divide these
  75069. * arguments by the Sprite's current scale:
  75070. *
  75071. * `setSize(32 / sprite.scale.x, 32 / sprite.scale.y)`
  75072. *
  75073. * Calling `setSize` on a Body that has already had `setCircle` will reset
  75074. * all of the Circle properties, making this Body rectangular again.
  75075. * @method Phaser.Physics.Arcade.Body#setSize
  75076. * @param {number} width - The width of the Body, relative to the Sprite's
  75077. * texture.
  75078. * @param {number} height - The height of the Body, relative to the Sprite's
  75079. * texture.
  75080. * @param {number} [offsetX] - The X offset of the Body from the left of the
  75081. * Sprite's texture.
  75082. * @param {number} [offsetY] - The Y offset of the Body from the top of the
  75083. * Sprite's texture.
  75084. */
  75085. setSize: function (width, height, offsetX, offsetY) {
  75086. if (offsetX === undefined) { offsetX = this.offset.x; }
  75087. if (offsetY === undefined) { offsetY = this.offset.y; }
  75088. this.sourceWidth = width;
  75089. this.sourceHeight = height;
  75090. this.width = this.sourceWidth * this._sx;
  75091. this.height = this.sourceHeight * this._sy;
  75092. this.halfWidth = Math.floor(this.width / 2);
  75093. this.halfHeight = Math.floor(this.height / 2);
  75094. this.offset.setTo(offsetX, offsetY);
  75095. this.updateCenter();
  75096. this.isCircle = false;
  75097. this.radius = 0;
  75098. },
  75099. /**
  75100. * Sets this Body as using a circle, of the given radius, for all collision detection instead of a rectangle.
  75101. * The radius is given in pixels (relative to the Sprite's _texture_) and is the distance from the center of the circle to the edge.
  75102. *
  75103. * You can also control the x and y offset, which is the position of the Body relative to the top-left of the Sprite's texture.
  75104. *
  75105. * To change a Body back to being rectangular again call `Body.setSize`.
  75106. *
  75107. * Note: Circular collision only happens with other Arcade Physics bodies, it does not
  75108. * work against tile maps, where rectangular collision is the only method supported.
  75109. *
  75110. * @method Phaser.Physics.Arcade.Body#setCircle
  75111. * @param {number} [radius] - The radius of the Body in pixels. Pass a value of zero / undefined, to stop the Body using a circle for collision.
  75112. * @param {number} [offsetX] - The X offset of the Body from the left of the Sprite's texture.
  75113. * @param {number} [offsetY] - The Y offset of the Body from the top of the Sprite's texture.
  75114. */
  75115. setCircle: function (radius, offsetX, offsetY) {
  75116. if (offsetX === undefined) { offsetX = this.offset.x; }
  75117. if (offsetY === undefined) { offsetY = this.offset.y; }
  75118. if (radius > 0)
  75119. {
  75120. this.isCircle = true;
  75121. this.radius = radius;
  75122. this.sourceWidth = radius * 2;
  75123. this.sourceHeight = radius * 2;
  75124. this.width = this.sourceWidth * this._sx;
  75125. this.height = this.sourceHeight * this._sy;
  75126. this.halfWidth = Math.floor(this.width / 2);
  75127. this.halfHeight = Math.floor(this.height / 2);
  75128. this.offset.setTo(offsetX, offsetY);
  75129. this.updateCenter();
  75130. }
  75131. else
  75132. {
  75133. this.isCircle = false;
  75134. }
  75135. },
  75136. /**
  75137. * Resets all Body values (velocity, acceleration, rotation, etc)
  75138. *
  75139. * @method Phaser.Physics.Arcade.Body#reset
  75140. * @param {number} x - The new x position of the Body.
  75141. * @param {number} y - The new y position of the Body.
  75142. */
  75143. reset: function (x, y) {
  75144. this.stop();
  75145. this.position.x = (x - (this.sprite.anchor.x * this.sprite.width)) + this.sprite.scale.x * this.offset.x;
  75146. this.position.x -= this.sprite.scale.x < 0 ? this.width : 0;
  75147. this.position.y = (y - (this.sprite.anchor.y * this.sprite.height)) + this.sprite.scale.y * this.offset.y;
  75148. this.position.y -= this.sprite.scale.y < 0 ? this.height : 0;
  75149. this.prev.x = this.position.x;
  75150. this.prev.y = this.position.y;
  75151. this.rotation = this.sprite.angle;
  75152. this.preRotation = this.rotation;
  75153. this.updateBounds();
  75154. this.updateCenter();
  75155. },
  75156. /**
  75157. * Sets acceleration, velocity, and {@link #speed} to 0.
  75158. *
  75159. * @method Phaser.Physics.Arcade.Body#stop
  75160. */
  75161. stop: function () {
  75162. this.velocity.set(0);
  75163. this.acceleration.set(0);
  75164. this.speed = 0;
  75165. this.angularVelocity = 0;
  75166. this.angularAcceleration = 0;
  75167. },
  75168. /**
  75169. * Returns the bounds of this physics body.
  75170. *
  75171. * Only used internally by the World collision methods.
  75172. *
  75173. * @method Phaser.Physics.Arcade.Body#getBounds
  75174. * @param {object} obj - The object in which to set the bounds values.
  75175. * @return {object} The object that was given to this method.
  75176. */
  75177. getBounds: function (obj) {
  75178. obj.x = this.x;
  75179. obj.y = this.y;
  75180. obj.right = this.right;
  75181. obj.bottom = this.bottom;
  75182. return obj;
  75183. },
  75184. /**
  75185. * Tests if a world point lies within this Body.
  75186. *
  75187. * @method Phaser.Physics.Arcade.Body#hitTest
  75188. * @param {number} x - The world x coordinate to test.
  75189. * @param {number} y - The world y coordinate to test.
  75190. * @return {boolean} True if the given coordinates are inside this Body, otherwise false.
  75191. */
  75192. hitTest: function (x, y) {
  75193. return (this.isCircle) ? Phaser.Circle.contains(this, x, y) : Phaser.Rectangle.contains(this, x, y);
  75194. },
  75195. /**
  75196. * Returns true if the bottom of this Body is in contact with either the world bounds or a tile.
  75197. *
  75198. * @method Phaser.Physics.Arcade.Body#onFloor
  75199. * @return {boolean} True if in contact with either the world bounds or a tile.
  75200. */
  75201. onFloor: function () {
  75202. return this.blocked.down;
  75203. },
  75204. /**
  75205. * Returns true if the top of this Body is in contact with either the world bounds or a tile.
  75206. *
  75207. * @method Phaser.Physics.Arcade.Body#onCeiling
  75208. * @return {boolean} True if in contact with either the world bounds or a tile.
  75209. */
  75210. onCeiling: function(){
  75211. return this.blocked.up;
  75212. },
  75213. /**
  75214. * Returns true if either side of this Body is in contact with either the world bounds or a tile.
  75215. *
  75216. * @method Phaser.Physics.Arcade.Body#onWall
  75217. * @return {boolean} True if in contact with either the world bounds or a tile.
  75218. */
  75219. onWall: function () {
  75220. return (this.blocked.left || this.blocked.right);
  75221. },
  75222. /**
  75223. * Returns the absolute delta x value.
  75224. *
  75225. * @method Phaser.Physics.Arcade.Body#deltaAbsX
  75226. * @return {number} The absolute delta value.
  75227. */
  75228. deltaAbsX: function () {
  75229. return (this.deltaX() > 0 ? this.deltaX() : -this.deltaX());
  75230. },
  75231. /**
  75232. * Returns the absolute delta y value.
  75233. *
  75234. * @method Phaser.Physics.Arcade.Body#deltaAbsY
  75235. * @return {number} The absolute delta value.
  75236. */
  75237. deltaAbsY: function () {
  75238. return (this.deltaY() > 0 ? this.deltaY() : -this.deltaY());
  75239. },
  75240. /**
  75241. * Returns the delta x value. The difference between Body.x now and in the previous step.
  75242. *
  75243. * @method Phaser.Physics.Arcade.Body#deltaX
  75244. * @return {number} The delta value. Positive if the motion was to the right, negative if to the left.
  75245. */
  75246. deltaX: function () {
  75247. return this.position.x - this.prev.x;
  75248. },
  75249. /**
  75250. * Returns the delta y value. The difference between Body.y now and in the previous step.
  75251. *
  75252. * @method Phaser.Physics.Arcade.Body#deltaY
  75253. * @return {number} The delta value. Positive if the motion was downwards, negative if upwards.
  75254. */
  75255. deltaY: function () {
  75256. return this.position.y - this.prev.y;
  75257. },
  75258. /**
  75259. * Returns the delta z value. The difference between Body.rotation now and in the previous step.
  75260. *
  75261. * @method Phaser.Physics.Arcade.Body#deltaZ
  75262. * @return {number} The delta value. Positive if the motion was clockwise, negative if anti-clockwise.
  75263. */
  75264. deltaZ: function () {
  75265. return this.rotation - this.preRotation;
  75266. },
  75267. /**
  75268. * Destroys this Body.
  75269. *
  75270. * First it calls Group.removeFromHash if the Game Object this Body belongs to is part of a Group.
  75271. * Then it nulls the Game Objects body reference, and nulls this Body.sprite reference.
  75272. *
  75273. * @method Phaser.Physics.Arcade.Body#destroy
  75274. */
  75275. destroy: function () {
  75276. if (this.sprite.parent && this.sprite.parent instanceof Phaser.Group)
  75277. {
  75278. this.sprite.parent.removeFromHash(this.sprite);
  75279. }
  75280. this.sprite.body = null;
  75281. this.sprite = null;
  75282. }
  75283. };
  75284. /**
  75285. * @name Phaser.Physics.Arcade.Body#left
  75286. * @property {number} left - The x position of the Body. The same as `Body.x`.
  75287. */
  75288. Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "left", {
  75289. get: function () {
  75290. return this.position.x;
  75291. }
  75292. });
  75293. /**
  75294. * @name Phaser.Physics.Arcade.Body#right
  75295. * @property {number} right - The right value of this Body (same as Body.x + Body.width)
  75296. * @readonly
  75297. */
  75298. Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "right", {
  75299. get: function () {
  75300. return this.position.x + this.width;
  75301. }
  75302. });
  75303. /**
  75304. * @name Phaser.Physics.Arcade.Body#top
  75305. * @property {number} top - The y position of the Body. The same as `Body.y`.
  75306. */
  75307. Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "top", {
  75308. get: function () {
  75309. return this.position.y;
  75310. }
  75311. });
  75312. /**
  75313. * @name Phaser.Physics.Arcade.Body#bottom
  75314. * @property {number} bottom - The bottom value of this Body (same as Body.y + Body.height)
  75315. * @readonly
  75316. */
  75317. Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "bottom", {
  75318. get: function () {
  75319. return this.position.y + this.height;
  75320. }
  75321. });
  75322. /**
  75323. * @name Phaser.Physics.Arcade.Body#x
  75324. * @property {number} x - The x position.
  75325. */
  75326. Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "x", {
  75327. get: function () {
  75328. return this.position.x;
  75329. },
  75330. set: function (value) {
  75331. this.position.x = value;
  75332. }
  75333. });
  75334. /**
  75335. * @name Phaser.Physics.Arcade.Body#y
  75336. * @property {number} y - The y position.
  75337. */
  75338. Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "y", {
  75339. get: function () {
  75340. return this.position.y;
  75341. },
  75342. set: function (value) {
  75343. this.position.y = value;
  75344. }
  75345. });
  75346. /**
  75347. * Render Sprite Body.
  75348. *
  75349. * @method Phaser.Physics.Arcade.Body#render
  75350. * @param {object} context - The context to render to.
  75351. * @param {Phaser.Physics.Arcade.Body} body - The Body to render the info of.
  75352. * @param {string} [color='rgba(0,255,0,0.4)'] - color of the debug info to be rendered. (format is css color string).
  75353. * @param {boolean} [filled=true] - Render the objected as a filled (default, true) or a stroked (false)
  75354. * @param {number} [lineWidth=1] - The width of the stroke when unfilled.
  75355. */
  75356. Phaser.Physics.Arcade.Body.render = function (context, body, color, filled, lineWidth) {
  75357. if (filled === undefined) { filled = true; }
  75358. color = color || 'rgba(0,255,0,0.4)';
  75359. context.fillStyle = color;
  75360. context.strokeStyle = color;
  75361. context.lineWidth = lineWidth || 1;
  75362. if (body.isCircle)
  75363. {
  75364. context.beginPath();
  75365. context.arc(body.center.x - body.game.camera.x, body.center.y - body.game.camera.y, body.halfWidth, 0, 2 * Math.PI);
  75366. if (filled)
  75367. {
  75368. context.fill();
  75369. }
  75370. else
  75371. {
  75372. context.stroke();
  75373. }
  75374. }
  75375. else
  75376. {
  75377. if (filled)
  75378. {
  75379. context.fillRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height);
  75380. }
  75381. else
  75382. {
  75383. context.strokeRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height);
  75384. }
  75385. }
  75386. };
  75387. /**
  75388. * Render Sprite Body Physics Data as text.
  75389. *
  75390. * @method Phaser.Physics.Arcade.Body#renderBodyInfo
  75391. * @param {Phaser.Physics.Arcade.Body} body - The Body to render the info of.
  75392. * @param {number} x - X position of the debug info to be rendered.
  75393. * @param {number} y - Y position of the debug info to be rendered.
  75394. * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
  75395. */
  75396. Phaser.Physics.Arcade.Body.renderBodyInfo = function (debug, body) {
  75397. debug.line('x: ' + body.x.toFixed(2), 'y: ' + body.y.toFixed(2), 'width: ' + body.width, 'height: ' + body.height);
  75398. debug.line('velocity x: ' + body.velocity.x.toFixed(2), 'y: ' + body.velocity.y.toFixed(2), 'deltaX: ' + body._dx.toFixed(2), 'deltaY: ' + body._dy.toFixed(2));
  75399. debug.line('acceleration x: ' + body.acceleration.x.toFixed(2), 'y: ' + body.acceleration.y.toFixed(2), 'speed: ' + body.speed.toFixed(2), 'angle: ' + body.angle.toFixed(2));
  75400. debug.line('gravity x: ' + body.gravity.x, 'y: ' + body.gravity.y, 'bounce x: ' + body.bounce.x.toFixed(2), 'y: ' + body.bounce.y.toFixed(2));
  75401. debug.line('touching left: ' + body.touching.left, 'right: ' + body.touching.right, 'up: ' + body.touching.up, 'down: ' + body.touching.down);
  75402. debug.line('blocked left: ' + body.blocked.left, 'right: ' + body.blocked.right, 'up: ' + body.blocked.up, 'down: ' + body.blocked.down);
  75403. };
  75404. Phaser.Physics.Arcade.Body.prototype.constructor = Phaser.Physics.Arcade.Body;
  75405. /**
  75406. * @author Richard Davey <rich@photonstorm.com>
  75407. * @copyright 2016 Photon Storm Ltd.
  75408. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  75409. */
  75410. /**
  75411. * The Arcade Physics Tile map collision methods.
  75412. *
  75413. * @class Phaser.Physics.Arcade.TilemapCollision
  75414. * @constructor
  75415. */
  75416. Phaser.Physics.Arcade.TilemapCollision = function () {};
  75417. Phaser.Physics.Arcade.TilemapCollision.prototype = {
  75418. /**
  75419. * @property {number} TILE_BIAS - A value added to the delta values during collision with tiles. Adjust this if you get tunneling.
  75420. */
  75421. TILE_BIAS: 16,
  75422. /**
  75423. * An internal function. Use Phaser.Physics.Arcade.collide instead.
  75424. *
  75425. * @method Phaser.Physics.Arcade#collideSpriteVsTilemapLayer
  75426. * @private
  75427. * @param {Phaser.Sprite} sprite - The sprite to check.
  75428. * @param {Phaser.TilemapLayer} tilemapLayer - The layer to check.
  75429. * @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
  75430. * @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
  75431. * @param {object} callbackContext - The context in which to run the callbacks.
  75432. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  75433. */
  75434. collideSpriteVsTilemapLayer: function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly) {
  75435. if (!sprite.body)
  75436. {
  75437. return;
  75438. }
  75439. var mapData = tilemapLayer.getTiles(
  75440. sprite.body.position.x - sprite.body.tilePadding.x - tilemapLayer.getTileOffsetX(),
  75441. sprite.body.position.y - sprite.body.tilePadding.y - tilemapLayer.getTileOffsetY(),
  75442. sprite.body.width + sprite.body.tilePadding.x,
  75443. sprite.body.height + sprite.body.tilePadding.y,
  75444. false, false);
  75445. if (mapData.length === 0)
  75446. {
  75447. return;
  75448. }
  75449. for (var i = 0; i < mapData.length; i++)
  75450. {
  75451. if (processCallback)
  75452. {
  75453. if (processCallback.call(callbackContext, sprite, mapData[i]))
  75454. {
  75455. if (this.separateTile(i, sprite.body, mapData[i], tilemapLayer, overlapOnly))
  75456. {
  75457. this._total++;
  75458. if (collideCallback)
  75459. {
  75460. collideCallback.call(callbackContext, sprite, mapData[i]);
  75461. }
  75462. }
  75463. }
  75464. }
  75465. else
  75466. {
  75467. if (this.separateTile(i, sprite.body, mapData[i], tilemapLayer, overlapOnly))
  75468. {
  75469. this._total++;
  75470. if (collideCallback)
  75471. {
  75472. collideCallback.call(callbackContext, sprite, mapData[i]);
  75473. }
  75474. }
  75475. }
  75476. }
  75477. },
  75478. /**
  75479. * An internal function. Use Phaser.Physics.Arcade.collide instead.
  75480. *
  75481. * @private
  75482. * @method Phaser.Physics.Arcade#collideGroupVsTilemapLayer
  75483. * @param {Phaser.Group} group - The Group to check.
  75484. * @param {Phaser.TilemapLayer} tilemapLayer - The layer to check.
  75485. * @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
  75486. * @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
  75487. * @param {object} callbackContext - The context in which to run the callbacks.
  75488. * @param {boolean} overlapOnly - Just run an overlap or a full collision.
  75489. */
  75490. collideGroupVsTilemapLayer: function (group, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly) {
  75491. if (group.length === 0)
  75492. {
  75493. return;
  75494. }
  75495. for (var i = 0; i < group.children.length; i++)
  75496. {
  75497. if (group.children[i].exists)
  75498. {
  75499. this.collideSpriteVsTilemapLayer(group.children[i], tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly);
  75500. }
  75501. }
  75502. },
  75503. /**
  75504. * The core separation function to separate a physics body and a tile.
  75505. *
  75506. * @private
  75507. * @method Phaser.Physics.Arcade#separateTile
  75508. * @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
  75509. * @param {Phaser.Tile} tile - The tile to collide against.
  75510. * @param {Phaser.TilemapLayer} tilemapLayer - The tilemapLayer to collide against.
  75511. * @return {boolean} Returns true if the body was separated, otherwise false.
  75512. */
  75513. separateTile: function (i, body, tile, tilemapLayer, overlapOnly) {
  75514. if (!body.enable)
  75515. {
  75516. return false;
  75517. }
  75518. var tilemapLayerOffsetX = tilemapLayer.getTileOffsetX();
  75519. var tilemapLayerOffsetY = tilemapLayer.getTileOffsetY();
  75520. // We re-check for collision in case body was separated in a previous step
  75521. if (!tile.intersects((body.position.x - tilemapLayerOffsetX), (body.position.y - tilemapLayerOffsetY), (body.right - tilemapLayerOffsetX), (body.bottom - tilemapLayerOffsetY)))
  75522. {
  75523. // no collision so bail out (separated in a previous step)
  75524. return false;
  75525. }
  75526. else if (overlapOnly)
  75527. {
  75528. // There is an overlap, and we don't need to separate. Bail.
  75529. return true;
  75530. }
  75531. // They overlap. Any custom callbacks?
  75532. // A local callback always takes priority over a layer level callback
  75533. if (tile.collisionCallback && !tile.collisionCallback.call(tile.collisionCallbackContext, body.sprite, tile))
  75534. {
  75535. // If it returns true then we can carry on, otherwise we should abort.
  75536. return false;
  75537. }
  75538. else if (typeof tile.layer.callbacks !== 'undefined' && tile.layer.callbacks[tile.index] && !tile.layer.callbacks[tile.index].callback.call(tile.layer.callbacks[tile.index].callbackContext, body.sprite, tile))
  75539. {
  75540. // If it returns true then we can carry on, otherwise we should abort.
  75541. return false;
  75542. }
  75543. // We don't need to go any further if this tile doesn't actually separate
  75544. if (!tile.faceLeft && !tile.faceRight && !tile.faceTop && !tile.faceBottom)
  75545. {
  75546. // This could happen if the tile was meant to be collided with re: a callback, but otherwise isn't needed for separation
  75547. return false;
  75548. }
  75549. var ox = 0;
  75550. var oy = 0;
  75551. var minX = 0;
  75552. var minY = 1;
  75553. if (body.deltaAbsX() > body.deltaAbsY())
  75554. {
  75555. // Moving faster horizontally, check X axis first
  75556. minX = -1;
  75557. }
  75558. else if (body.deltaAbsX() < body.deltaAbsY())
  75559. {
  75560. // Moving faster vertically, check Y axis first
  75561. minY = -1;
  75562. }
  75563. if (body.deltaX() !== 0 && body.deltaY() !== 0 && (tile.faceLeft || tile.faceRight) && (tile.faceTop || tile.faceBottom))
  75564. {
  75565. // We only need do this if both axis have checking faces AND we're moving in both directions
  75566. minX = Math.min(Math.abs((body.position.x - tilemapLayerOffsetX) - tile.right), Math.abs((body.right - tilemapLayerOffsetX) - tile.left));
  75567. minY = Math.min(Math.abs((body.position.y - tilemapLayerOffsetY) - tile.bottom), Math.abs((body.bottom - tilemapLayerOffsetY) - tile.top));
  75568. }
  75569. if (minX < minY)
  75570. {
  75571. if (tile.faceLeft || tile.faceRight)
  75572. {
  75573. ox = this.tileCheckX(body, tile, tilemapLayer);
  75574. // That's horizontal done, check if we still intersects? If not then we can return now
  75575. if (ox !== 0 && !tile.intersects((body.position.x - tilemapLayerOffsetX), (body.position.y - tilemapLayerOffsetY), (body.right - tilemapLayerOffsetX), (body.bottom - tilemapLayerOffsetY)))
  75576. {
  75577. return true;
  75578. }
  75579. }
  75580. if (tile.faceTop || tile.faceBottom)
  75581. {
  75582. oy = this.tileCheckY(body, tile, tilemapLayer);
  75583. }
  75584. }
  75585. else
  75586. {
  75587. if (tile.faceTop || tile.faceBottom)
  75588. {
  75589. oy = this.tileCheckY(body, tile, tilemapLayer);
  75590. // That's vertical done, check if we still intersects? If not then we can return now
  75591. if (oy !== 0 && !tile.intersects((body.position.x - tilemapLayerOffsetX), (body.position.y - tilemapLayerOffsetY), (body.right - tilemapLayerOffsetX), (body.bottom - tilemapLayerOffsetY)))
  75592. {
  75593. return true;
  75594. }
  75595. }
  75596. if (tile.faceLeft || tile.faceRight)
  75597. {
  75598. ox = this.tileCheckX(body, tile, tilemapLayer);
  75599. }
  75600. }
  75601. return (ox !== 0 || oy !== 0);
  75602. },
  75603. /**
  75604. * Check the body against the given tile on the X axis.
  75605. *
  75606. * @private
  75607. * @method Phaser.Physics.Arcade#tileCheckX
  75608. * @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
  75609. * @param {Phaser.Tile} tile - The tile to check.
  75610. * @param {Phaser.TilemapLayer} tilemapLayer - The tilemapLayer to collide against.
  75611. * @return {number} The amount of separation that occurred.
  75612. */
  75613. tileCheckX: function (body, tile, tilemapLayer) {
  75614. var ox = 0;
  75615. var tilemapLayerOffsetX = tilemapLayer.getTileOffsetX();
  75616. if (body.deltaX() < 0 && !body.blocked.left && tile.collideRight && body.checkCollision.left)
  75617. {
  75618. // Body is moving LEFT
  75619. if (tile.faceRight && (body.x - tilemapLayerOffsetX) < tile.right)
  75620. {
  75621. ox = (body.x - tilemapLayerOffsetX) - tile.right;
  75622. if (ox < -this.TILE_BIAS)
  75623. {
  75624. ox = 0;
  75625. }
  75626. }
  75627. }
  75628. else if (body.deltaX() > 0 && !body.blocked.right && tile.collideLeft && body.checkCollision.right)
  75629. {
  75630. // Body is moving RIGHT
  75631. if (tile.faceLeft && (body.right - tilemapLayerOffsetX) > tile.left)
  75632. {
  75633. ox = (body.right - tilemapLayerOffsetX) - tile.left;
  75634. if (ox > this.TILE_BIAS)
  75635. {
  75636. ox = 0;
  75637. }
  75638. }
  75639. }
  75640. if (ox !== 0)
  75641. {
  75642. if (body.customSeparateX)
  75643. {
  75644. body.overlapX = ox;
  75645. }
  75646. else
  75647. {
  75648. this.processTileSeparationX(body, ox);
  75649. }
  75650. }
  75651. return ox;
  75652. },
  75653. /**
  75654. * Check the body against the given tile on the Y axis.
  75655. *
  75656. * @private
  75657. * @method Phaser.Physics.Arcade#tileCheckY
  75658. * @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
  75659. * @param {Phaser.Tile} tile - The tile to check.
  75660. * @param {Phaser.TilemapLayer} tilemapLayer - The tilemapLayer to collide against.
  75661. * @return {number} The amount of separation that occurred.
  75662. */
  75663. tileCheckY: function (body, tile, tilemapLayer) {
  75664. var oy = 0;
  75665. var tilemapLayerOffsetY = tilemapLayer.getTileOffsetY();
  75666. if (body.deltaY() < 0 && !body.blocked.up && tile.collideDown && body.checkCollision.up)
  75667. {
  75668. // Body is moving UP
  75669. if (tile.faceBottom && (body.y - tilemapLayerOffsetY) < tile.bottom)
  75670. {
  75671. oy = (body.y - tilemapLayerOffsetY) - tile.bottom;
  75672. if (oy < -this.TILE_BIAS)
  75673. {
  75674. oy = 0;
  75675. }
  75676. }
  75677. }
  75678. else if (body.deltaY() > 0 && !body.blocked.down && tile.collideUp && body.checkCollision.down)
  75679. {
  75680. // Body is moving DOWN
  75681. if (tile.faceTop && (body.bottom - tilemapLayerOffsetY) > tile.top)
  75682. {
  75683. oy = (body.bottom - tilemapLayerOffsetY) - tile.top;
  75684. if (oy > this.TILE_BIAS)
  75685. {
  75686. oy = 0;
  75687. }
  75688. }
  75689. }
  75690. if (oy !== 0)
  75691. {
  75692. if (body.customSeparateY)
  75693. {
  75694. body.overlapY = oy;
  75695. }
  75696. else
  75697. {
  75698. this.processTileSeparationY(body, oy);
  75699. }
  75700. }
  75701. return oy;
  75702. },
  75703. /**
  75704. * Internal function to process the separation of a physics body from a tile.
  75705. *
  75706. * @private
  75707. * @method Phaser.Physics.Arcade#processTileSeparationX
  75708. * @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
  75709. * @param {number} x - The x separation amount.
  75710. */
  75711. processTileSeparationX: function (body, x) {
  75712. if (x < 0)
  75713. {
  75714. body.blocked.left = true;
  75715. body.blocked.none = false;
  75716. }
  75717. else if (x > 0)
  75718. {
  75719. body.blocked.right = true;
  75720. body.blocked.none = false;
  75721. }
  75722. body.position.x -= x;
  75723. if (body.bounce.x === 0)
  75724. {
  75725. body.velocity.x = 0;
  75726. }
  75727. else
  75728. {
  75729. body.velocity.x = -body.velocity.x * body.bounce.x;
  75730. }
  75731. },
  75732. /**
  75733. * Internal function to process the separation of a physics body from a tile.
  75734. *
  75735. * @private
  75736. * @method Phaser.Physics.Arcade#processTileSeparationY
  75737. * @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
  75738. * @param {number} y - The y separation amount.
  75739. */
  75740. processTileSeparationY: function (body, y) {
  75741. if (y < 0)
  75742. {
  75743. body.blocked.up = true;
  75744. body.blocked.none = false;
  75745. }
  75746. else if (y > 0)
  75747. {
  75748. body.blocked.down = true;
  75749. body.blocked.none = false;
  75750. }
  75751. body.position.y -= y;
  75752. if (body.bounce.y === 0)
  75753. {
  75754. body.velocity.y = 0;
  75755. }
  75756. else
  75757. {
  75758. body.velocity.y = -body.velocity.y * body.bounce.y;
  75759. }
  75760. }
  75761. };
  75762. // Merge this with the Arcade Physics prototype
  75763. Phaser.Utils.mixinPrototype(Phaser.Physics.Arcade.prototype, Phaser.Physics.Arcade.TilemapCollision.prototype);
  75764. /**
  75765. * @author Richard Davey <rich@photonstorm.com>
  75766. * @copyright 2016 Photon Storm Ltd.
  75767. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  75768. */
  75769. // Add an extra properties to p2 that we need
  75770. p2.Body.prototype.parent = null;
  75771. p2.Spring.prototype.parent = null;
  75772. /**
  75773. * This is your main access to the P2 Physics World.
  75774. * From here you can create materials, listen for events and add bodies into the physics simulation.
  75775. *
  75776. * @class Phaser.Physics.P2
  75777. * @constructor
  75778. * @param {Phaser.Game} game - Reference to the current game instance.
  75779. * @param {object} [config] - Physics configuration object passed in from the game constructor.
  75780. */
  75781. Phaser.Physics.P2 = function (game, config) {
  75782. /**
  75783. * @property {Phaser.Game} game - Local reference to game.
  75784. */
  75785. this.game = game;
  75786. if (config === undefined)
  75787. {
  75788. config = { gravity: [0, 0], broadphase: new p2.SAPBroadphase() };
  75789. }
  75790. else
  75791. {
  75792. if (!config.hasOwnProperty('gravity'))
  75793. {
  75794. config.gravity = [0, 0];
  75795. }
  75796. if (!config.hasOwnProperty('broadphase'))
  75797. {
  75798. config.broadphase = new p2.SAPBroadphase();
  75799. }
  75800. }
  75801. /**
  75802. * @property {object} config - The p2 World configuration object.
  75803. * @protected
  75804. */
  75805. this.config = config;
  75806. /**
  75807. * @property {p2.World} world - The p2 World in which the simulation is run.
  75808. * @protected
  75809. */
  75810. this.world = new p2.World(this.config);
  75811. /**
  75812. * @property {number} frameRate - The frame rate the world will be stepped at. Defaults to 1 / 60, but you can change here. Also see useElapsedTime property.
  75813. * @default
  75814. */
  75815. this.frameRate = 1 / 60;
  75816. /**
  75817. * @property {boolean} useElapsedTime - If true the frameRate value will be ignored and instead p2 will step with the value of Game.Time.physicsElapsed, which is a delta time value.
  75818. * @default
  75819. */
  75820. this.useElapsedTime = false;
  75821. /**
  75822. * @property {boolean} paused - The paused state of the P2 World.
  75823. * @default
  75824. */
  75825. this.paused = false;
  75826. /**
  75827. * @property {array<Phaser.Physics.P2.Material>} materials - A local array of all created Materials.
  75828. * @protected
  75829. */
  75830. this.materials = [];
  75831. /**
  75832. * @property {Phaser.Physics.P2.InversePointProxy} gravity - The gravity applied to all bodies each step.
  75833. */
  75834. this.gravity = new Phaser.Physics.P2.InversePointProxy(this, this.world.gravity);
  75835. /**
  75836. * @property {object} walls - An object containing the 4 wall bodies that bound the physics world.
  75837. */
  75838. this.walls = { left: null, right: null, top: null, bottom: null };
  75839. /**
  75840. * This signal is dispatched when a new Body is added to the World.
  75841. *
  75842. * It sends 1 argument: `body` which is the `Phaser.Physics.P2.Body` that was added to the world.
  75843. *
  75844. * @property {Phaser.Signal} onBodyAdded
  75845. */
  75846. this.onBodyAdded = new Phaser.Signal();
  75847. /**
  75848. * This signal is dispatched when a Body is removed to the World.
  75849. *
  75850. * It sends 1 argument: `body` which is the `Phaser.Physics.P2.Body` that was removed from the world.
  75851. *
  75852. * @property {Phaser.Signal} onBodyRemoved
  75853. */
  75854. this.onBodyRemoved = new Phaser.Signal();
  75855. /**
  75856. * This signal is dispatched when a Spring is added to the World.
  75857. *
  75858. * It sends 1 argument: `spring` which is either a `Phaser.Physics.P2.Spring`, `p2.LinearSpring` or `p2.RotationalSpring` that was added to the world.
  75859. *
  75860. * @property {Phaser.Signal} onSpringAdded
  75861. */
  75862. this.onSpringAdded = new Phaser.Signal();
  75863. /**
  75864. * This signal is dispatched when a Spring is removed from the World.
  75865. *
  75866. * It sends 1 argument: `spring` which is either a `Phaser.Physics.P2.Spring`, `p2.LinearSpring` or `p2.RotationalSpring` that was removed from the world.
  75867. *
  75868. * @property {Phaser.Signal} onSpringRemoved
  75869. */
  75870. this.onSpringRemoved = new Phaser.Signal();
  75871. /**
  75872. * This signal is dispatched when a Constraint is added to the World.
  75873. *
  75874. * It sends 1 argument: `constraint` which is the `Phaser.Physics.P2.Constraint` that was added to the world.
  75875. *
  75876. * @property {Phaser.Signal} onConstraintAdded
  75877. */
  75878. this.onConstraintAdded = new Phaser.Signal();
  75879. /**
  75880. * This signal is dispatched when a Constraint is removed from the World.
  75881. *
  75882. * It sends 1 argument: `constraint` which is the `Phaser.Physics.P2.Constraint` that was removed from the world.
  75883. *
  75884. * @property {Phaser.Signal} onConstraintRemoved
  75885. */
  75886. this.onConstraintRemoved = new Phaser.Signal();
  75887. /**
  75888. * This signal is dispatched when a Contact Material is added to the World.
  75889. *
  75890. * It sends 1 argument: `material` which is the `Phaser.Physics.P2.ContactMaterial` that was added to the world.
  75891. *
  75892. * @property {Phaser.Signal} onContactMaterialAdded
  75893. */
  75894. this.onContactMaterialAdded = new Phaser.Signal();
  75895. /**
  75896. * This signal is dispatched when a Contact Material is removed from the World.
  75897. *
  75898. * It sends 1 argument: `material` which is the `Phaser.Physics.P2.ContactMaterial` that was removed from the world.
  75899. *
  75900. * @property {Phaser.Signal} onContactMaterialRemoved
  75901. */
  75902. this.onContactMaterialRemoved = new Phaser.Signal();
  75903. /**
  75904. * @property {function} postBroadphaseCallback - A postBroadphase callback.
  75905. */
  75906. this.postBroadphaseCallback = null;
  75907. /**
  75908. * @property {object} callbackContext - The context under which the callbacks are fired.
  75909. */
  75910. this.callbackContext = null;
  75911. /**
  75912. * This Signal is dispatched when a first contact is created between two bodies. This happens *before* the step has been done.
  75913. *
  75914. * It sends 5 arguments: `bodyA`, `bodyB`, `shapeA`, `shapeB` and `contactEquations`.
  75915. *
  75916. * It is possible that in certain situations the `bodyA` or `bodyB` values are `null`. You should check for this
  75917. * in your own code to avoid processing potentially null physics bodies.
  75918. *
  75919. * @property {Phaser.Signal} onBeginContact
  75920. */
  75921. this.onBeginContact = new Phaser.Signal();
  75922. /**
  75923. * This Signal is dispatched when final contact occurs between two bodies. This happens *before* the step has been done.
  75924. *
  75925. * It sends 4 arguments: `bodyA`, `bodyB`, `shapeA` and `shapeB`.
  75926. *
  75927. * It is possible that in certain situations the `bodyA` or `bodyB` values are `null`. You should check for this
  75928. * in your own code to avoid processing potentially null physics bodies.
  75929. *
  75930. * @property {Phaser.Signal} onEndContact
  75931. */
  75932. this.onEndContact = new Phaser.Signal();
  75933. // Pixel to meter function overrides
  75934. if (config.hasOwnProperty('mpx') && config.hasOwnProperty('pxm') && config.hasOwnProperty('mpxi') && config.hasOwnProperty('pxmi'))
  75935. {
  75936. this.mpx = config.mpx;
  75937. this.mpxi = config.mpxi;
  75938. this.pxm = config.pxm;
  75939. this.pxmi = config.pxmi;
  75940. }
  75941. // Hook into the World events
  75942. this.world.on("beginContact", this.beginContactHandler, this);
  75943. this.world.on("endContact", this.endContactHandler, this);
  75944. /**
  75945. * @property {array} collisionGroups - An array containing the collision groups that have been defined in the World.
  75946. */
  75947. this.collisionGroups = [];
  75948. /**
  75949. * @property {Phaser.Physics.P2.CollisionGroup} nothingCollisionGroup - A default collision group.
  75950. */
  75951. this.nothingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(1);
  75952. /**
  75953. * @property {Phaser.Physics.P2.CollisionGroup} boundsCollisionGroup - A default collision group.
  75954. */
  75955. this.boundsCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2);
  75956. /**
  75957. * @property {Phaser.Physics.P2.CollisionGroup} everythingCollisionGroup - A default collision group.
  75958. */
  75959. this.everythingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2147483648);
  75960. /**
  75961. * @property {array} boundsCollidesWith - An array of the bodies the world bounds collides with.
  75962. */
  75963. this.boundsCollidesWith = [];
  75964. /**
  75965. * @property {array} _toRemove - Internal var used to hold references to bodies to remove from the world on the next step.
  75966. * @private
  75967. */
  75968. this._toRemove = [];
  75969. /**
  75970. * @property {number} _collisionGroupID - Internal var.
  75971. * @private
  75972. */
  75973. this._collisionGroupID = 2;
  75974. /**
  75975. * @property {boolean} _boundsLeft - Internal var that keeps track of world bounds settings.
  75976. * @private
  75977. */
  75978. this._boundsLeft = true;
  75979. /**
  75980. * @property {boolean} _boundsRight - Internal var that keeps track of world bounds settings.
  75981. * @private
  75982. */
  75983. this._boundsRight = true;
  75984. /**
  75985. * @property {boolean} _boundsTop - Internal var that keeps track of world bounds settings.
  75986. * @private
  75987. */
  75988. this._boundsTop = true;
  75989. /**
  75990. * @property {boolean} _boundsBottom - Internal var that keeps track of world bounds settings.
  75991. * @private
  75992. */
  75993. this._boundsBottom = true;
  75994. /**
  75995. * @property {boolean} _boundsOwnGroup - Internal var that keeps track of world bounds settings.
  75996. * @private
  75997. */
  75998. this._boundsOwnGroup = false;
  75999. // By default we want everything colliding with everything
  76000. this.setBoundsToWorld(true, true, true, true, false);
  76001. };
  76002. Phaser.Physics.P2.prototype = {
  76003. /**
  76004. * This will add a P2 Physics body into the removal list for the next step.
  76005. *
  76006. * @method Phaser.Physics.P2#removeBodyNextStep
  76007. * @param {Phaser.Physics.P2.Body} body - The body to remove at the start of the next step.
  76008. */
  76009. removeBodyNextStep: function (body) {
  76010. this._toRemove.push(body);
  76011. },
  76012. /**
  76013. * Called at the start of the core update loop. Purges flagged bodies from the world.
  76014. *
  76015. * @method Phaser.Physics.P2#preUpdate
  76016. */
  76017. preUpdate: function () {
  76018. var i = this._toRemove.length;
  76019. while (i--)
  76020. {
  76021. this.removeBody(this._toRemove[i]);
  76022. }
  76023. this._toRemove.length = 0;
  76024. },
  76025. /**
  76026. * This will create a P2 Physics body on the given game object or array of game objects.
  76027. * A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
  76028. * Note: When the game object is enabled for P2 physics it has its anchor x/y set to 0.5 so it becomes centered.
  76029. *
  76030. * @method Phaser.Physics.P2#enable
  76031. * @param {object|array|Phaser.Group} object - The game object to create the physics body on. Can also be an array or Group of objects, a body will be created on every child that has a `body` property.
  76032. * @param {boolean} [debug=false] - Create a debug object to go with this body?
  76033. * @param {boolean} [children=true] - Should a body be created on all children of this object? If true it will recurse down the display list as far as it can go.
  76034. */
  76035. enable: function (object, debug, children) {
  76036. if (debug === undefined) { debug = false; }
  76037. if (children === undefined) { children = true; }
  76038. var i = 1;
  76039. if (Array.isArray(object))
  76040. {
  76041. i = object.length;
  76042. while (i--)
  76043. {
  76044. if (object[i] instanceof Phaser.Group)
  76045. {
  76046. // If it's a Group then we do it on the children regardless
  76047. this.enable(object[i].children, debug, children);
  76048. }
  76049. else
  76050. {
  76051. this.enableBody(object[i], debug);
  76052. if (children && object[i].hasOwnProperty('children') && object[i].children.length > 0)
  76053. {
  76054. this.enable(object[i], debug, true);
  76055. }
  76056. }
  76057. }
  76058. }
  76059. else
  76060. {
  76061. if (object instanceof Phaser.Group)
  76062. {
  76063. // If it's a Group then we do it on the children regardless
  76064. this.enable(object.children, debug, children);
  76065. }
  76066. else
  76067. {
  76068. this.enableBody(object, debug);
  76069. if (children && object.hasOwnProperty('children') && object.children.length > 0)
  76070. {
  76071. this.enable(object.children, debug, true);
  76072. }
  76073. }
  76074. }
  76075. },
  76076. /**
  76077. * Creates a P2 Physics body on the given game object.
  76078. * A game object can only have 1 physics body active at any one time, and it can't be changed until the body is nulled.
  76079. *
  76080. * @method Phaser.Physics.P2#enableBody
  76081. * @param {object} object - The game object to create the physics body on. A body will only be created if this object has a null `body` property.
  76082. * @param {boolean} debug - Create a debug object to go with this body?
  76083. */
  76084. enableBody: function (object, debug) {
  76085. if (object.hasOwnProperty('body') && object.body === null)
  76086. {
  76087. object.body = new Phaser.Physics.P2.Body(this.game, object, object.x, object.y, 1);
  76088. object.body.debug = debug;
  76089. if (typeof object.anchor !== 'undefined') {
  76090. object.anchor.set(0.5);
  76091. }
  76092. }
  76093. },
  76094. /**
  76095. * Impact event handling is disabled by default. Enable it before any impact events will be dispatched.
  76096. * In a busy world hundreds of impact events can be generated every step, so only enable this if you cannot do what you need via beginContact or collision masks.
  76097. *
  76098. * @method Phaser.Physics.P2#setImpactEvents
  76099. * @param {boolean} state - Set to true to enable impact events, or false to disable.
  76100. */
  76101. setImpactEvents: function (state) {
  76102. if (state)
  76103. {
  76104. this.world.on("impact", this.impactHandler, this);
  76105. }
  76106. else
  76107. {
  76108. this.world.off("impact", this.impactHandler, this);
  76109. }
  76110. },
  76111. /**
  76112. * Sets a callback to be fired after the Broadphase has collected collision pairs in the world.
  76113. * Just because a pair exists it doesn't mean they *will* collide, just that they potentially could do.
  76114. * If your calback returns `false` the pair will be removed from the narrowphase. This will stop them testing for collision this step.
  76115. * Returning `true` from the callback will ensure they are checked in the narrowphase.
  76116. *
  76117. * @method Phaser.Physics.P2#setPostBroadphaseCallback
  76118. * @param {function} callback - The callback that will receive the postBroadphase event data. It must return a boolean. Set to null to disable an existing callback.
  76119. * @param {object} context - The context under which the callback will be fired.
  76120. */
  76121. setPostBroadphaseCallback: function (callback, context) {
  76122. this.postBroadphaseCallback = callback;
  76123. this.callbackContext = context;
  76124. if (callback !== null)
  76125. {
  76126. this.world.on("postBroadphase", this.postBroadphaseHandler, this);
  76127. }
  76128. else
  76129. {
  76130. this.world.off("postBroadphase", this.postBroadphaseHandler, this);
  76131. }
  76132. },
  76133. /**
  76134. * Internal handler for the postBroadphase event.
  76135. *
  76136. * @method Phaser.Physics.P2#postBroadphaseHandler
  76137. * @private
  76138. * @param {object} event - The event data.
  76139. */
  76140. postBroadphaseHandler: function (event) {
  76141. if (!this.postBroadphaseCallback || event.pairs.length === 0)
  76142. {
  76143. return;
  76144. }
  76145. for (var i = event.pairs.length - 2; i >= 0; i -= 2)
  76146. {
  76147. if (event.pairs[i].parent && event.pairs[i+1].parent && !this.postBroadphaseCallback.call(this.callbackContext, event.pairs[i].parent, event.pairs[i+1].parent))
  76148. {
  76149. event.pairs.splice(i, 2);
  76150. }
  76151. }
  76152. },
  76153. /**
  76154. * Handles a p2 impact event.
  76155. *
  76156. * @method Phaser.Physics.P2#impactHandler
  76157. * @private
  76158. * @param {object} event - The event data.
  76159. */
  76160. impactHandler: function (event) {
  76161. if (event.bodyA.parent && event.bodyB.parent)
  76162. {
  76163. // Body vs. Body callbacks
  76164. var a = event.bodyA.parent;
  76165. var b = event.bodyB.parent;
  76166. if (a._bodyCallbacks[event.bodyB.id])
  76167. {
  76168. a._bodyCallbacks[event.bodyB.id].call(a._bodyCallbackContext[event.bodyB.id], a, b, event.shapeA, event.shapeB);
  76169. }
  76170. if (b._bodyCallbacks[event.bodyA.id])
  76171. {
  76172. b._bodyCallbacks[event.bodyA.id].call(b._bodyCallbackContext[event.bodyA.id], b, a, event.shapeB, event.shapeA);
  76173. }
  76174. // Body vs. Group callbacks
  76175. if (a._groupCallbacks[event.shapeB.collisionGroup])
  76176. {
  76177. a._groupCallbacks[event.shapeB.collisionGroup].call(a._groupCallbackContext[event.shapeB.collisionGroup], a, b, event.shapeA, event.shapeB);
  76178. }
  76179. if (b._groupCallbacks[event.shapeA.collisionGroup])
  76180. {
  76181. b._groupCallbacks[event.shapeA.collisionGroup].call(b._groupCallbackContext[event.shapeA.collisionGroup], b, a, event.shapeB, event.shapeA);
  76182. }
  76183. }
  76184. },
  76185. /**
  76186. * Handles a p2 begin contact event.
  76187. *
  76188. * @method Phaser.Physics.P2#beginContactHandler
  76189. * @param {object} event - The event data.
  76190. */
  76191. beginContactHandler: function (event) {
  76192. if (event.bodyA && event.bodyB)
  76193. {
  76194. this.onBeginContact.dispatch(event.bodyA, event.bodyB, event.shapeA, event.shapeB, event.contactEquations);
  76195. if (event.bodyA.parent)
  76196. {
  76197. event.bodyA.parent.onBeginContact.dispatch(event.bodyB.parent, event.bodyB, event.shapeA, event.shapeB, event.contactEquations);
  76198. }
  76199. if (event.bodyB.parent)
  76200. {
  76201. event.bodyB.parent.onBeginContact.dispatch(event.bodyA.parent, event.bodyA, event.shapeB, event.shapeA, event.contactEquations);
  76202. }
  76203. }
  76204. },
  76205. /**
  76206. * Handles a p2 end contact event.
  76207. *
  76208. * @method Phaser.Physics.P2#endContactHandler
  76209. * @param {object} event - The event data.
  76210. */
  76211. endContactHandler: function (event) {
  76212. if (event.bodyA && event.bodyB)
  76213. {
  76214. this.onEndContact.dispatch(event.bodyA, event.bodyB, event.shapeA, event.shapeB);
  76215. if (event.bodyA.parent)
  76216. {
  76217. event.bodyA.parent.onEndContact.dispatch(event.bodyB.parent, event.bodyB, event.shapeA, event.shapeB);
  76218. }
  76219. if (event.bodyB.parent)
  76220. {
  76221. event.bodyB.parent.onEndContact.dispatch(event.bodyA.parent, event.bodyA, event.shapeB, event.shapeA);
  76222. }
  76223. }
  76224. },
  76225. /**
  76226. * Sets the bounds of the Physics world to match the Game.World dimensions.
  76227. * You can optionally set which 'walls' to create: left, right, top or bottom.
  76228. *
  76229. * @method Phaser.Physics#setBoundsToWorld
  76230. * @param {boolean} [left=true] - If true will create the left bounds wall.
  76231. * @param {boolean} [right=true] - If true will create the right bounds wall.
  76232. * @param {boolean} [top=true] - If true will create the top bounds wall.
  76233. * @param {boolean} [bottom=true] - If true will create the bottom bounds wall.
  76234. * @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
  76235. */
  76236. setBoundsToWorld: function (left, right, top, bottom, setCollisionGroup) {
  76237. this.setBounds(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, left, right, top, bottom, setCollisionGroup);
  76238. },
  76239. /**
  76240. * Sets the given material against the 4 bounds of this World.
  76241. *
  76242. * @method Phaser.Physics#setWorldMaterial
  76243. * @param {Phaser.Physics.P2.Material} material - The material to set.
  76244. * @param {boolean} [left=true] - If true will set the material on the left bounds wall.
  76245. * @param {boolean} [right=true] - If true will set the material on the right bounds wall.
  76246. * @param {boolean} [top=true] - If true will set the material on the top bounds wall.
  76247. * @param {boolean} [bottom=true] - If true will set the material on the bottom bounds wall.
  76248. */
  76249. setWorldMaterial: function (material, left, right, top, bottom) {
  76250. if (left === undefined) { left = true; }
  76251. if (right === undefined) { right = true; }
  76252. if (top === undefined) { top = true; }
  76253. if (bottom === undefined) { bottom = true; }
  76254. if (left && this.walls.left)
  76255. {
  76256. this.walls.left.shapes[0].material = material;
  76257. }
  76258. if (right && this.walls.right)
  76259. {
  76260. this.walls.right.shapes[0].material = material;
  76261. }
  76262. if (top && this.walls.top)
  76263. {
  76264. this.walls.top.shapes[0].material = material;
  76265. }
  76266. if (bottom && this.walls.bottom)
  76267. {
  76268. this.walls.bottom.shapes[0].material = material;
  76269. }
  76270. },
  76271. /**
  76272. * By default the World will be set to collide everything with everything. The bounds of the world is a Body with 4 shapes, one for each face.
  76273. * If you start to use your own collision groups then your objects will no longer collide with the bounds.
  76274. * To fix this you need to adjust the bounds to use its own collision group first BEFORE changing your Sprites collision group.
  76275. *
  76276. * @method Phaser.Physics.P2#updateBoundsCollisionGroup
  76277. * @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
  76278. */
  76279. updateBoundsCollisionGroup: function (setCollisionGroup) {
  76280. if (setCollisionGroup === undefined) { setCollisionGroup = true; }
  76281. var mask = (setCollisionGroup) ? this.boundsCollisionGroup.mask : this.everythingCollisionGroup.mask;
  76282. if (this.walls.left)
  76283. {
  76284. this.walls.left.shapes[0].collisionGroup = mask;
  76285. }
  76286. if (this.walls.right)
  76287. {
  76288. this.walls.right.shapes[0].collisionGroup = mask;
  76289. }
  76290. if (this.walls.top)
  76291. {
  76292. this.walls.top.shapes[0].collisionGroup = mask;
  76293. }
  76294. if (this.walls.bottom)
  76295. {
  76296. this.walls.bottom.shapes[0].collisionGroup = mask;
  76297. }
  76298. this._boundsOwnGroup = setCollisionGroup;
  76299. },
  76300. /**
  76301. * Sets the bounds of the Physics world to match the given world pixel dimensions.
  76302. * You can optionally set which 'walls' to create: left, right, top or bottom.
  76303. * If none of the walls are given it will default to use the walls settings it had previously.
  76304. * I.e. if you previously told it to not have the left or right walls, and you then adjust the world size
  76305. * the newly created bounds will also not have the left and right walls.
  76306. * Explicitly state them in the parameters to override this.
  76307. *
  76308. * @method Phaser.Physics.P2#setBounds
  76309. * @param {number} x - The x coordinate of the top-left corner of the bounds.
  76310. * @param {number} y - The y coordinate of the top-left corner of the bounds.
  76311. * @param {number} width - The width of the bounds.
  76312. * @param {number} height - The height of the bounds.
  76313. * @param {boolean} [left=true] - If true will create the left bounds wall.
  76314. * @param {boolean} [right=true] - If true will create the right bounds wall.
  76315. * @param {boolean} [top=true] - If true will create the top bounds wall.
  76316. * @param {boolean} [bottom=true] - If true will create the bottom bounds wall.
  76317. * @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
  76318. */
  76319. setBounds: function (x, y, width, height, left, right, top, bottom, setCollisionGroup) {
  76320. if (left === undefined) { left = this._boundsLeft; }
  76321. if (right === undefined) { right = this._boundsRight; }
  76322. if (top === undefined) { top = this._boundsTop; }
  76323. if (bottom === undefined) { bottom = this._boundsBottom; }
  76324. if (setCollisionGroup === undefined) { setCollisionGroup = this._boundsOwnGroup; }
  76325. this.setupWall(left, 'left', x, y, 1.5707963267948966, setCollisionGroup);
  76326. this.setupWall(right, 'right', x + width, y, -1.5707963267948966, setCollisionGroup);
  76327. this.setupWall(top, 'top', x, y, -3.141592653589793, setCollisionGroup);
  76328. this.setupWall(bottom, 'bottom', x, y + height, 0, setCollisionGroup);
  76329. // Remember the bounds settings in case they change later on via World.setBounds
  76330. this._boundsLeft = left;
  76331. this._boundsRight = right;
  76332. this._boundsTop = top;
  76333. this._boundsBottom = bottom;
  76334. this._boundsOwnGroup = setCollisionGroup;
  76335. },
  76336. /**
  76337. * Internal method called by setBounds. Responsible for creating, updating or
  76338. * removing the wall body shapes.
  76339. *
  76340. * @method Phaser.Physics.P2#setupWall
  76341. * @private
  76342. * @param {boolean} create - True to create the wall shape, false to remove it.
  76343. * @param {string} wall - The wall segment to update.
  76344. * @param {number} x - The x coordinate of the wall.
  76345. * @param {number} y - The y coordinate of the wall.
  76346. * @param {float} angle - The angle of the wall.
  76347. * @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
  76348. */
  76349. setupWall: function (create, wall, x, y, angle, setCollisionGroup) {
  76350. if (create)
  76351. {
  76352. // We need a left wall. Do we have one already?
  76353. if (this.walls[wall])
  76354. {
  76355. this.walls[wall].position = [ this.pxmi(x), this.pxmi(y) ];
  76356. }
  76357. else
  76358. {
  76359. this.walls[wall] = new p2.Body({ mass: 0, position: [ this.pxmi(x), this.pxmi(y) ], angle: angle });
  76360. this.walls[wall].addShape(new p2.Plane());
  76361. this.world.addBody(this.walls[wall]);
  76362. }
  76363. if (setCollisionGroup)
  76364. {
  76365. this.walls[wall].shapes[0].collisionGroup = this.boundsCollisionGroup.mask;
  76366. }
  76367. }
  76368. else
  76369. {
  76370. if (this.walls[wall])
  76371. {
  76372. this.world.removeBody(this.walls[wall]);
  76373. this.walls[wall] = null;
  76374. }
  76375. }
  76376. },
  76377. /**
  76378. * Pauses the P2 World independent of the game pause state.
  76379. *
  76380. * @method Phaser.Physics.P2#pause
  76381. */
  76382. pause: function() {
  76383. this.paused = true;
  76384. },
  76385. /**
  76386. * Resumes a paused P2 World.
  76387. *
  76388. * @method Phaser.Physics.P2#resume
  76389. */
  76390. resume: function() {
  76391. this.paused = false;
  76392. },
  76393. /**
  76394. * Internal P2 update loop.
  76395. *
  76396. * @method Phaser.Physics.P2#update
  76397. */
  76398. update: function () {
  76399. // Do nothing if the physics engine was paused before
  76400. if (this.paused)
  76401. {
  76402. return;
  76403. }
  76404. if (this.useElapsedTime)
  76405. {
  76406. this.world.step(this.game.time.physicsElapsed);
  76407. }
  76408. else
  76409. {
  76410. this.world.step(this.frameRate);
  76411. }
  76412. },
  76413. /**
  76414. * Called by Phaser.Physics when a State swap occurs.
  76415. * Starts the begin and end Contact listeners again.
  76416. *
  76417. * @method Phaser.Physics.P2#reset
  76418. */
  76419. reset: function () {
  76420. this.world.on("beginContact", this.beginContactHandler, this);
  76421. this.world.on("endContact", this.endContactHandler, this);
  76422. this.nothingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(1);
  76423. this.boundsCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2);
  76424. this.everythingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2147483648);
  76425. this._collisionGroupID = 2;
  76426. this.setBoundsToWorld(true, true, true, true, false);
  76427. },
  76428. /**
  76429. * Clears all bodies from the simulation, resets callbacks and resets the collision bitmask.
  76430. *
  76431. * The P2 world is also cleared:
  76432. *
  76433. * * Removes all solver equations
  76434. * * Removes all constraints
  76435. * * Removes all bodies
  76436. * * Removes all springs
  76437. * * Removes all contact materials
  76438. *
  76439. * This is called automatically when you switch state.
  76440. *
  76441. * @method Phaser.Physics.P2#clear
  76442. */
  76443. clear: function () {
  76444. this.world.time = 0;
  76445. this.world.fixedStepTime = 0;
  76446. // Remove all solver equations
  76447. if (this.world.solver && this.world.solver.equations.length)
  76448. {
  76449. this.world.solver.removeAllEquations();
  76450. }
  76451. // Remove all constraints
  76452. var cs = this.world.constraints;
  76453. for (var i = cs.length - 1; i >= 0; i--)
  76454. {
  76455. this.world.removeConstraint(cs[i]);
  76456. }
  76457. // Remove all bodies
  76458. var bodies = this.world.bodies;
  76459. for (var i = bodies.length - 1; i >= 0; i--)
  76460. {
  76461. this.world.removeBody(bodies[i]);
  76462. }
  76463. // Remove all springs
  76464. var springs = this.world.springs;
  76465. for (var i = springs.length - 1; i >= 0; i--)
  76466. {
  76467. this.world.removeSpring(springs[i]);
  76468. }
  76469. // Remove all contact materials
  76470. var cms = this.world.contactMaterials;
  76471. for (var i = cms.length - 1; i >= 0; i--)
  76472. {
  76473. this.world.removeContactMaterial(cms[i]);
  76474. }
  76475. this.world.off("beginContact", this.beginContactHandler, this);
  76476. this.world.off("endContact", this.endContactHandler, this);
  76477. this.postBroadphaseCallback = null;
  76478. this.callbackContext = null;
  76479. this.impactCallback = null;
  76480. this.collisionGroups = [];
  76481. this._toRemove = [];
  76482. this.boundsCollidesWith = [];
  76483. // Remove the world bounds
  76484. this.walls = { left: null, right: null, top: null, bottom: null };
  76485. },
  76486. /**
  76487. * Clears all bodies from the simulation and unlinks World from Game. Should only be called on game shutdown. Call `clear` on a State change.
  76488. *
  76489. * @method Phaser.Physics.P2#destroy
  76490. */
  76491. destroy: function () {
  76492. this.clear();
  76493. this.game = null;
  76494. },
  76495. /**
  76496. * Add a body to the world.
  76497. *
  76498. * @method Phaser.Physics.P2#addBody
  76499. * @param {Phaser.Physics.P2.Body} body - The Body to add to the World.
  76500. * @return {boolean} True if the Body was added successfully, otherwise false.
  76501. */
  76502. addBody: function (body) {
  76503. if (body.data.world)
  76504. {
  76505. return false;
  76506. }
  76507. else
  76508. {
  76509. this.world.addBody(body.data);
  76510. this.onBodyAdded.dispatch(body);
  76511. return true;
  76512. }
  76513. },
  76514. /**
  76515. * Removes a body from the world. This will silently fail if the body wasn't part of the world to begin with.
  76516. *
  76517. * @method Phaser.Physics.P2#removeBody
  76518. * @param {Phaser.Physics.P2.Body} body - The Body to remove from the World.
  76519. * @return {Phaser.Physics.P2.Body} The Body that was removed.
  76520. */
  76521. removeBody: function (body) {
  76522. if (body.data.world === this.world)
  76523. {
  76524. this.world.removeBody(body.data);
  76525. this.onBodyRemoved.dispatch(body);
  76526. }
  76527. return body;
  76528. },
  76529. /**
  76530. * Adds a Spring to the world.
  76531. *
  76532. * @method Phaser.Physics.P2#addSpring
  76533. * @param {Phaser.Physics.P2.Spring|p2.LinearSpring|p2.RotationalSpring} spring - The Spring to add to the World.
  76534. * @return {Phaser.Physics.P2.Spring} The Spring that was added.
  76535. */
  76536. addSpring: function (spring) {
  76537. if (spring instanceof Phaser.Physics.P2.Spring || spring instanceof Phaser.Physics.P2.RotationalSpring)
  76538. {
  76539. this.world.addSpring(spring.data);
  76540. }
  76541. else
  76542. {
  76543. this.world.addSpring(spring);
  76544. }
  76545. this.onSpringAdded.dispatch(spring);
  76546. return spring;
  76547. },
  76548. /**
  76549. * Removes a Spring from the world.
  76550. *
  76551. * @method Phaser.Physics.P2#removeSpring
  76552. * @param {Phaser.Physics.P2.Spring} spring - The Spring to remove from the World.
  76553. * @return {Phaser.Physics.P2.Spring} The Spring that was removed.
  76554. */
  76555. removeSpring: function (spring) {
  76556. if (spring instanceof Phaser.Physics.P2.Spring || spring instanceof Phaser.Physics.P2.RotationalSpring)
  76557. {
  76558. this.world.removeSpring(spring.data);
  76559. }
  76560. else
  76561. {
  76562. this.world.removeSpring(spring);
  76563. }
  76564. this.onSpringRemoved.dispatch(spring);
  76565. return spring;
  76566. },
  76567. /**
  76568. * Creates a constraint that tries to keep the distance between two bodies constant.
  76569. *
  76570. * @method Phaser.Physics.P2#createDistanceConstraint
  76571. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  76572. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  76573. * @param {number} distance - The distance to keep between the bodies.
  76574. * @param {Array} [localAnchorA] - The anchor point for bodyA, defined locally in bodyA frame. Defaults to [0,0].
  76575. * @param {Array} [localAnchorB] - The anchor point for bodyB, defined locally in bodyB frame. Defaults to [0,0].
  76576. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  76577. * @return {Phaser.Physics.P2.DistanceConstraint} The constraint
  76578. */
  76579. createDistanceConstraint: function (bodyA, bodyB, distance, localAnchorA, localAnchorB, maxForce) {
  76580. bodyA = this.getBody(bodyA);
  76581. bodyB = this.getBody(bodyB);
  76582. if (!bodyA || !bodyB)
  76583. {
  76584. console.warn('Cannot create Constraint, invalid body objects given');
  76585. }
  76586. else
  76587. {
  76588. return this.addConstraint(new Phaser.Physics.P2.DistanceConstraint(this, bodyA, bodyB, distance, localAnchorA, localAnchorB, maxForce));
  76589. }
  76590. },
  76591. /**
  76592. * Creates a constraint that tries to keep the distance between two bodies constant.
  76593. *
  76594. * @method Phaser.Physics.P2#createGearConstraint
  76595. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  76596. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  76597. * @param {number} [angle=0] - The relative angle
  76598. * @param {number} [ratio=1] - The gear ratio.
  76599. * @return {Phaser.Physics.P2.GearConstraint} The constraint
  76600. */
  76601. createGearConstraint: function (bodyA, bodyB, angle, ratio) {
  76602. bodyA = this.getBody(bodyA);
  76603. bodyB = this.getBody(bodyB);
  76604. if (!bodyA || !bodyB)
  76605. {
  76606. console.warn('Cannot create Constraint, invalid body objects given');
  76607. }
  76608. else
  76609. {
  76610. return this.addConstraint(new Phaser.Physics.P2.GearConstraint(this, bodyA, bodyB, angle, ratio));
  76611. }
  76612. },
  76613. /**
  76614. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  76615. * The pivot points are given in world (pixel) coordinates.
  76616. *
  76617. * @method Phaser.Physics.P2#createRevoluteConstraint
  76618. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  76619. * @param {Array} pivotA - The point relative to the center of mass of bodyA which bodyA is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  76620. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  76621. * @param {Array} pivotB - The point relative to the center of mass of bodyB which bodyB is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  76622. * @param {number} [maxForce=0] - The maximum force that should be applied to constrain the bodies.
  76623. * @param {Float32Array} [worldPivot=null] - A pivot point given in world coordinates. If specified, localPivotA and localPivotB are automatically computed from this value.
  76624. * @return {Phaser.Physics.P2.RevoluteConstraint} The constraint
  76625. */
  76626. createRevoluteConstraint: function (bodyA, pivotA, bodyB, pivotB, maxForce, worldPivot) {
  76627. bodyA = this.getBody(bodyA);
  76628. bodyB = this.getBody(bodyB);
  76629. if (!bodyA || !bodyB)
  76630. {
  76631. console.warn('Cannot create Constraint, invalid body objects given');
  76632. }
  76633. else
  76634. {
  76635. return this.addConstraint(new Phaser.Physics.P2.RevoluteConstraint(this, bodyA, pivotA, bodyB, pivotB, maxForce, worldPivot));
  76636. }
  76637. },
  76638. /**
  76639. * Locks the relative position between two bodies.
  76640. *
  76641. * @method Phaser.Physics.P2#createLockConstraint
  76642. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  76643. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  76644. * @param {Array} [offset] - The offset of bodyB in bodyA's frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  76645. * @param {number} [angle=0] - The angle of bodyB in bodyA's frame.
  76646. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  76647. * @return {Phaser.Physics.P2.LockConstraint} The constraint
  76648. */
  76649. createLockConstraint: function (bodyA, bodyB, offset, angle, maxForce) {
  76650. bodyA = this.getBody(bodyA);
  76651. bodyB = this.getBody(bodyB);
  76652. if (!bodyA || !bodyB)
  76653. {
  76654. console.warn('Cannot create Constraint, invalid body objects given');
  76655. }
  76656. else
  76657. {
  76658. return this.addConstraint(new Phaser.Physics.P2.LockConstraint(this, bodyA, bodyB, offset, angle, maxForce));
  76659. }
  76660. },
  76661. /**
  76662. * Constraint that only allows bodies to move along a line, relative to each other.
  76663. * See http://www.iforce2d.net/b2dtut/joints-prismatic
  76664. *
  76665. * @method Phaser.Physics.P2#createPrismaticConstraint
  76666. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  76667. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  76668. * @param {boolean} [lockRotation=true] - If set to false, bodyB will be free to rotate around its anchor point.
  76669. * @param {Array} [anchorA] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  76670. * @param {Array} [anchorB] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  76671. * @param {Array} [axis] - An axis, defined in body A frame, that body B's anchor point may slide along. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  76672. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  76673. * @return {Phaser.Physics.P2.PrismaticConstraint} The constraint
  76674. */
  76675. createPrismaticConstraint: function (bodyA, bodyB, lockRotation, anchorA, anchorB, axis, maxForce) {
  76676. bodyA = this.getBody(bodyA);
  76677. bodyB = this.getBody(bodyB);
  76678. if (!bodyA || !bodyB)
  76679. {
  76680. console.warn('Cannot create Constraint, invalid body objects given');
  76681. }
  76682. else
  76683. {
  76684. return this.addConstraint(new Phaser.Physics.P2.PrismaticConstraint(this, bodyA, bodyB, lockRotation, anchorA, anchorB, axis, maxForce));
  76685. }
  76686. },
  76687. /**
  76688. * Adds a Constraint to the world.
  76689. *
  76690. * @method Phaser.Physics.P2#addConstraint
  76691. * @param {Phaser.Physics.P2.Constraint} constraint - The Constraint to add to the World.
  76692. * @return {Phaser.Physics.P2.Constraint} The Constraint that was added.
  76693. */
  76694. addConstraint: function (constraint) {
  76695. this.world.addConstraint(constraint);
  76696. this.onConstraintAdded.dispatch(constraint);
  76697. return constraint;
  76698. },
  76699. /**
  76700. * Removes a Constraint from the world.
  76701. *
  76702. * @method Phaser.Physics.P2#removeConstraint
  76703. * @param {Phaser.Physics.P2.Constraint} constraint - The Constraint to be removed from the World.
  76704. * @return {Phaser.Physics.P2.Constraint} The Constraint that was removed.
  76705. */
  76706. removeConstraint: function (constraint) {
  76707. this.world.removeConstraint(constraint);
  76708. this.onConstraintRemoved.dispatch(constraint);
  76709. return constraint;
  76710. },
  76711. /**
  76712. * Adds a Contact Material to the world.
  76713. *
  76714. * @method Phaser.Physics.P2#addContactMaterial
  76715. * @param {Phaser.Physics.P2.ContactMaterial} material - The Contact Material to be added to the World.
  76716. * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was added.
  76717. */
  76718. addContactMaterial: function (material) {
  76719. this.world.addContactMaterial(material);
  76720. this.onContactMaterialAdded.dispatch(material);
  76721. return material;
  76722. },
  76723. /**
  76724. * Removes a Contact Material from the world.
  76725. *
  76726. * @method Phaser.Physics.P2#removeContactMaterial
  76727. * @param {Phaser.Physics.P2.ContactMaterial} material - The Contact Material to be removed from the World.
  76728. * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was removed.
  76729. */
  76730. removeContactMaterial: function (material) {
  76731. this.world.removeContactMaterial(material);
  76732. this.onContactMaterialRemoved.dispatch(material);
  76733. return material;
  76734. },
  76735. /**
  76736. * Gets a Contact Material based on the two given Materials.
  76737. *
  76738. * @method Phaser.Physics.P2#getContactMaterial
  76739. * @param {Phaser.Physics.P2.Material} materialA - The first Material to search for.
  76740. * @param {Phaser.Physics.P2.Material} materialB - The second Material to search for.
  76741. * @return {Phaser.Physics.P2.ContactMaterial|boolean} The Contact Material or false if none was found matching the Materials given.
  76742. */
  76743. getContactMaterial: function (materialA, materialB) {
  76744. return this.world.getContactMaterial(materialA, materialB);
  76745. },
  76746. /**
  76747. * Sets the given Material against all Shapes owned by all the Bodies in the given array.
  76748. *
  76749. * @method Phaser.Physics.P2#setMaterial
  76750. * @param {Phaser.Physics.P2.Material} material - The Material to be applied to the given Bodies.
  76751. * @param {array<Phaser.Physics.P2.Body>} bodies - An Array of Body objects that the given Material will be set on.
  76752. */
  76753. setMaterial: function (material, bodies) {
  76754. var i = bodies.length;
  76755. while (i--)
  76756. {
  76757. bodies[i].setMaterial(material);
  76758. }
  76759. },
  76760. /**
  76761. * Creates a Material. Materials are applied to Shapes owned by a Body and can be set with Body.setMaterial().
  76762. * Materials are a way to control what happens when Shapes collide. Combine unique Materials together to create Contact Materials.
  76763. * Contact Materials have properties such as friction and restitution that allow for fine-grained collision control between different Materials.
  76764. *
  76765. * @method Phaser.Physics.P2#createMaterial
  76766. * @param {string} [name] - Optional name of the Material. Each Material has a unique ID but string names are handy for debugging.
  76767. * @param {Phaser.Physics.P2.Body} [body] - Optional Body. If given it will assign the newly created Material to the Body shapes.
  76768. * @return {Phaser.Physics.P2.Material} The Material that was created. This is also stored in Phaser.Physics.P2.materials.
  76769. */
  76770. createMaterial: function (name, body) {
  76771. name = name || '';
  76772. var material = new Phaser.Physics.P2.Material(name);
  76773. this.materials.push(material);
  76774. if (typeof body !== 'undefined')
  76775. {
  76776. body.setMaterial(material);
  76777. }
  76778. return material;
  76779. },
  76780. /**
  76781. * Creates a Contact Material from the two given Materials. You can then edit the properties of the Contact Material directly.
  76782. *
  76783. * @method Phaser.Physics.P2#createContactMaterial
  76784. * @param {Phaser.Physics.P2.Material} [materialA] - The first Material to create the ContactMaterial from. If undefined it will create a new Material object first.
  76785. * @param {Phaser.Physics.P2.Material} [materialB] - The second Material to create the ContactMaterial from. If undefined it will create a new Material object first.
  76786. * @param {object} [options] - Material options object.
  76787. * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was created.
  76788. */
  76789. createContactMaterial: function (materialA, materialB, options) {
  76790. if (materialA === undefined) { materialA = this.createMaterial(); }
  76791. if (materialB === undefined) { materialB = this.createMaterial(); }
  76792. var contact = new Phaser.Physics.P2.ContactMaterial(materialA, materialB, options);
  76793. return this.addContactMaterial(contact);
  76794. },
  76795. /**
  76796. * Populates and returns an array with references to of all current Bodies in the world.
  76797. *
  76798. * @method Phaser.Physics.P2#getBodies
  76799. * @return {array<Phaser.Physics.P2.Body>} An array containing all current Bodies in the world.
  76800. */
  76801. getBodies: function () {
  76802. var output = [];
  76803. var i = this.world.bodies.length;
  76804. while (i--)
  76805. {
  76806. output.push(this.world.bodies[i].parent);
  76807. }
  76808. return output;
  76809. },
  76810. /**
  76811. * Checks the given object to see if it has a p2.Body and if so returns it.
  76812. *
  76813. * @method Phaser.Physics.P2#getBody
  76814. * @param {object} object - The object to check for a p2.Body on.
  76815. * @return {p2.Body} The p2.Body, or null if not found.
  76816. */
  76817. getBody: function (object) {
  76818. if (object instanceof p2.Body)
  76819. {
  76820. // Native p2 body
  76821. return object;
  76822. }
  76823. else if (object instanceof Phaser.Physics.P2.Body)
  76824. {
  76825. // Phaser P2 Body
  76826. return object.data;
  76827. }
  76828. else if (object['body'] && object['body'].type === Phaser.Physics.P2JS)
  76829. {
  76830. // Sprite, TileSprite, etc
  76831. return object.body.data;
  76832. }
  76833. return null;
  76834. },
  76835. /**
  76836. * Populates and returns an array of all current Springs in the world.
  76837. *
  76838. * @method Phaser.Physics.P2#getSprings
  76839. * @return {array<Phaser.Physics.P2.Spring>} An array containing all current Springs in the world.
  76840. */
  76841. getSprings: function () {
  76842. var output = [];
  76843. var i = this.world.springs.length;
  76844. while (i--)
  76845. {
  76846. output.push(this.world.springs[i].parent);
  76847. }
  76848. return output;
  76849. },
  76850. /**
  76851. * Populates and returns an array of all current Constraints in the world.
  76852. * You will get an array of p2 constraints back. This can be of mixed types, for example the array may contain
  76853. * PrismaticConstraints, RevoluteConstraints or any other valid p2 constraint type.
  76854. *
  76855. * @method Phaser.Physics.P2#getConstraints
  76856. * @return {array<Phaser.Physics.P2.Constraint>} An array containing all current Constraints in the world.
  76857. */
  76858. getConstraints: function () {
  76859. var output = [];
  76860. var i = this.world.constraints.length;
  76861. while (i--)
  76862. {
  76863. output.push(this.world.constraints[i]);
  76864. }
  76865. return output;
  76866. },
  76867. /**
  76868. * Test if a world point overlaps bodies. You will get an array of actual P2 bodies back. You can find out which Sprite a Body belongs to
  76869. * (if any) by checking the Body.parent.sprite property. Body.parent is a Phaser.Physics.P2.Body property.
  76870. *
  76871. * @method Phaser.Physics.P2#hitTest
  76872. * @param {Phaser.Point} worldPoint - Point to use for intersection tests. The points values must be in world (pixel) coordinates.
  76873. * @param {Array<Phaser.Physics.P2.Body|Phaser.Sprite|p2.Body>} [bodies] - A list of objects to check for intersection. If not given it will check Phaser.Physics.P2.world.bodies (i.e. all world bodies)
  76874. * @param {number} [precision=5] - Used for matching against particles and lines. Adds some margin to these infinitesimal objects.
  76875. * @param {boolean} [filterStatic=false] - If true all Static objects will be removed from the results array.
  76876. * @return {Array} Array of bodies that overlap the point.
  76877. */
  76878. hitTest: function (worldPoint, bodies, precision, filterStatic) {
  76879. if (bodies === undefined) { bodies = this.world.bodies; }
  76880. if (precision === undefined) { precision = 5; }
  76881. if (filterStatic === undefined) { filterStatic = false; }
  76882. var physicsPosition = [ this.pxmi(worldPoint.x), this.pxmi(worldPoint.y) ];
  76883. var query = [];
  76884. var i = bodies.length;
  76885. while (i--)
  76886. {
  76887. if (bodies[i] instanceof Phaser.Physics.P2.Body && !(filterStatic && bodies[i].data.type === p2.Body.STATIC))
  76888. {
  76889. query.push(bodies[i].data);
  76890. }
  76891. else if (bodies[i] instanceof p2.Body && bodies[i].parent && !(filterStatic && bodies[i].type === p2.Body.STATIC))
  76892. {
  76893. query.push(bodies[i]);
  76894. }
  76895. else if (bodies[i] instanceof Phaser.Sprite && bodies[i].hasOwnProperty('body') && !(filterStatic && bodies[i].body.data.type === p2.Body.STATIC))
  76896. {
  76897. query.push(bodies[i].body.data);
  76898. }
  76899. }
  76900. return this.world.hitTest(physicsPosition, query, precision);
  76901. },
  76902. /**
  76903. * Converts the current world into a JSON object.
  76904. *
  76905. * @method Phaser.Physics.P2#toJSON
  76906. * @return {object} A JSON representation of the world.
  76907. */
  76908. toJSON: function () {
  76909. return this.world.toJSON();
  76910. },
  76911. /**
  76912. * Creates a new Collision Group and optionally applies it to the given object.
  76913. * Collision Groups are handled using bitmasks, therefore you have a fixed limit you can create before you need to re-use older groups.
  76914. *
  76915. * @method Phaser.Physics.P2#createCollisionGroup
  76916. * @param {Phaser.Group|Phaser.Sprite} [object] - An optional Sprite or Group to apply the Collision Group to. If a Group is given it will be applied to all top-level children.
  76917. */
  76918. createCollisionGroup: function (object) {
  76919. var bitmask = Math.pow(2, this._collisionGroupID);
  76920. if (this.walls.left)
  76921. {
  76922. this.walls.left.shapes[0].collisionMask = this.walls.left.shapes[0].collisionMask | bitmask;
  76923. }
  76924. if (this.walls.right)
  76925. {
  76926. this.walls.right.shapes[0].collisionMask = this.walls.right.shapes[0].collisionMask | bitmask;
  76927. }
  76928. if (this.walls.top)
  76929. {
  76930. this.walls.top.shapes[0].collisionMask = this.walls.top.shapes[0].collisionMask | bitmask;
  76931. }
  76932. if (this.walls.bottom)
  76933. {
  76934. this.walls.bottom.shapes[0].collisionMask = this.walls.bottom.shapes[0].collisionMask | bitmask;
  76935. }
  76936. this._collisionGroupID++;
  76937. var group = new Phaser.Physics.P2.CollisionGroup(bitmask);
  76938. this.collisionGroups.push(group);
  76939. if (object)
  76940. {
  76941. this.setCollisionGroup(object, group);
  76942. }
  76943. return group;
  76944. },
  76945. /**
  76946. * Sets the given CollisionGroup to be the collision group for all shapes in this Body, unless a shape is specified.
  76947. * Note that this resets the collisionMask and any previously set groups. See Body.collides() for appending them.
  76948. *
  76949. * @method Phaser.Physics.P2y#setCollisionGroup
  76950. * @param {Phaser.Group|Phaser.Sprite} object - A Sprite or Group to apply the Collision Group to. If a Group is given it will be applied to all top-level children.
  76951. * @param {Phaser.Physics.CollisionGroup} group - The Collision Group that this Bodies shapes will use.
  76952. */
  76953. setCollisionGroup: function (object, group) {
  76954. if (object instanceof Phaser.Group)
  76955. {
  76956. for (var i = 0; i < object.total; i++)
  76957. {
  76958. if (object.children[i]['body'] && object.children[i]['body'].type === Phaser.Physics.P2JS)
  76959. {
  76960. object.children[i].body.setCollisionGroup(group);
  76961. }
  76962. }
  76963. }
  76964. else
  76965. {
  76966. object.body.setCollisionGroup(group);
  76967. }
  76968. },
  76969. /**
  76970. * Creates a linear spring, connecting two bodies. A spring can have a resting length, a stiffness and damping.
  76971. *
  76972. * @method Phaser.Physics.P2#createSpring
  76973. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  76974. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  76975. * @param {number} [restLength=1] - Rest length of the spring. A number > 0.
  76976. * @param {number} [stiffness=100] - Stiffness of the spring. A number >= 0.
  76977. * @param {number} [damping=1] - Damping of the spring. A number >= 0.
  76978. * @param {Array} [worldA] - Where to hook the spring to body A in world coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  76979. * @param {Array} [worldB] - Where to hook the spring to body B in world coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  76980. * @param {Array} [localA] - Where to hook the spring to body A in local body coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  76981. * @param {Array} [localB] - Where to hook the spring to body B in local body coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  76982. * @return {Phaser.Physics.P2.Spring} The spring
  76983. */
  76984. createSpring: function (bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB) {
  76985. bodyA = this.getBody(bodyA);
  76986. bodyB = this.getBody(bodyB);
  76987. if (!bodyA || !bodyB)
  76988. {
  76989. console.warn('Cannot create Spring, invalid body objects given');
  76990. }
  76991. else
  76992. {
  76993. return this.addSpring(new Phaser.Physics.P2.Spring(this, bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB));
  76994. }
  76995. },
  76996. /**
  76997. * Creates a rotational spring, connecting two bodies. A spring can have a resting length, a stiffness and damping.
  76998. *
  76999. * @method Phaser.Physics.P2#createRotationalSpring
  77000. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  77001. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  77002. * @param {number} [restAngle] - The relative angle of bodies at which the spring is at rest. If not given, it's set to the current relative angle between the bodies.
  77003. * @param {number} [stiffness=100] - Stiffness of the spring. A number >= 0.
  77004. * @param {number} [damping=1] - Damping of the spring. A number >= 0.
  77005. * @return {Phaser.Physics.P2.RotationalSpring} The spring
  77006. */
  77007. createRotationalSpring: function (bodyA, bodyB, restAngle, stiffness, damping) {
  77008. bodyA = this.getBody(bodyA);
  77009. bodyB = this.getBody(bodyB);
  77010. if (!bodyA || !bodyB)
  77011. {
  77012. console.warn('Cannot create Rotational Spring, invalid body objects given');
  77013. }
  77014. else
  77015. {
  77016. return this.addSpring(new Phaser.Physics.P2.RotationalSpring(this, bodyA, bodyB, restAngle, stiffness, damping));
  77017. }
  77018. },
  77019. /**
  77020. * Creates a new Body and adds it to the World.
  77021. *
  77022. * @method Phaser.Physics.P2#createBody
  77023. * @param {number} x - The x coordinate of Body.
  77024. * @param {number} y - The y coordinate of Body.
  77025. * @param {number} mass - The mass of the Body. A mass of 0 means a 'static' Body is created.
  77026. * @param {boolean} [addToWorld=false] - Automatically add this Body to the world? (usually false as it won't have any shapes on construction).
  77027. * @param {object} options - An object containing the build options:
  77028. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  77029. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  77030. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  77031. * @param {(number[]|...number)} points - An array of 2d vectors that form the convex or concave polygon.
  77032. * Either [[0,0], [0,1],...] or a flat array of numbers that will be interpreted as [x,y, x,y, ...],
  77033. * or the arguments passed can be flat x,y values e.g. `setPolygon(options, x,y, x,y, x,y, ...)` where `x` and `y` are numbers.
  77034. * @return {Phaser.Physics.P2.Body} The body
  77035. */
  77036. createBody: function (x, y, mass, addToWorld, options, data) {
  77037. if (addToWorld === undefined) { addToWorld = false; }
  77038. var body = new Phaser.Physics.P2.Body(this.game, null, x, y, mass);
  77039. if (data)
  77040. {
  77041. var result = body.addPolygon(options, data);
  77042. if (!result)
  77043. {
  77044. return false;
  77045. }
  77046. }
  77047. if (addToWorld)
  77048. {
  77049. this.world.addBody(body.data);
  77050. }
  77051. return body;
  77052. },
  77053. /**
  77054. * Creates a new Particle and adds it to the World.
  77055. *
  77056. * @method Phaser.Physics.P2#createParticle
  77057. * @param {number} x - The x coordinate of Body.
  77058. * @param {number} y - The y coordinate of Body.
  77059. * @param {number} mass - The mass of the Body. A mass of 0 means a 'static' Body is created.
  77060. * @param {boolean} [addToWorld=false] - Automatically add this Body to the world? (usually false as it won't have any shapes on construction).
  77061. * @param {object} options - An object containing the build options:
  77062. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  77063. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  77064. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  77065. * @param {(number[]|...number)} points - An array of 2d vectors that form the convex or concave polygon.
  77066. * Either [[0,0], [0,1],...] or a flat array of numbers that will be interpreted as [x,y, x,y, ...],
  77067. * or the arguments passed can be flat x,y values e.g. `setPolygon(options, x,y, x,y, x,y, ...)` where `x` and `y` are numbers.
  77068. */
  77069. createParticle: function (x, y, mass, addToWorld, options, data) {
  77070. if (addToWorld === undefined) { addToWorld = false; }
  77071. var body = new Phaser.Physics.P2.Body(this.game, null, x, y, mass);
  77072. if (data)
  77073. {
  77074. var result = body.addPolygon(options, data);
  77075. if (!result)
  77076. {
  77077. return false;
  77078. }
  77079. }
  77080. if (addToWorld)
  77081. {
  77082. this.world.addBody(body.data);
  77083. }
  77084. return body;
  77085. },
  77086. /**
  77087. * Converts all of the polyline, polygon, and rectangle objects inside a Tiled ObjectGroup into physics bodies that are added to the world.
  77088. * Note that the polylines and polygons must be created in such a way that they can withstand polygon decomposition.
  77089. *
  77090. * @method Phaser.Physics.P2#convertCollisionObjects
  77091. * @param {Phaser.Tilemap} map - The Tilemap to get the map data from.
  77092. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to map.currentLayer.
  77093. * @param {boolean} [addToWorld=true] - If true it will automatically add each body to the world.
  77094. * @return {array} An array of the Phaser.Physics.Body objects that have been created.
  77095. */
  77096. convertCollisionObjects: function (map, layer, addToWorld) {
  77097. if (addToWorld === undefined) { addToWorld = true; }
  77098. var output = [];
  77099. for (var i = 0, len = map.collision[layer].length; i < len; i++)
  77100. {
  77101. // name: json.layers[i].objects[v].name,
  77102. // x: json.layers[i].objects[v].x,
  77103. // y: json.layers[i].objects[v].y,
  77104. // width: json.layers[i].objects[v].width,
  77105. // height: json.layers[i].objects[v].height,
  77106. // visible: json.layers[i].objects[v].visible,
  77107. // properties: json.layers[i].objects[v].properties,
  77108. // polyline: json.layers[i].objects[v].polyline
  77109. var object = map.collision[layer][i];
  77110. var shapeData = object.polyline || object.polygon;
  77111. // polyline/polygon shape data present
  77112. if (shapeData)
  77113. {
  77114. var body = this.createBody(object.x, object.y, 0, addToWorld, {}, shapeData);
  77115. }
  77116. // tilemap parser sets rectangle=true when parsing object groups
  77117. else if (object.rectangle)
  77118. {
  77119. var body = this.createBody(object.x, object.y, 0, addToWorld);
  77120. body.addRectangle(object.width, object.height, object.width / 2, object.height / 2);
  77121. }
  77122. // ellipse could be added here, but Tiled ellipses use height/width instead of radius
  77123. // (to support oblong ellipses), which p2 doesn't currently support.
  77124. if (body)
  77125. {
  77126. output.push(body);
  77127. }
  77128. }
  77129. return output;
  77130. },
  77131. /**
  77132. * Clears all physics bodies from the given TilemapLayer that were created with `World.convertTilemap`.
  77133. *
  77134. * @method Phaser.Physics.P2#clearTilemapLayerBodies
  77135. * @param {Phaser.Tilemap} map - The Tilemap to get the map data from.
  77136. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to map.currentLayer.
  77137. */
  77138. clearTilemapLayerBodies: function (map, layer) {
  77139. layer = map.getLayer(layer);
  77140. var i = map.layers[layer].bodies.length;
  77141. while (i--)
  77142. {
  77143. map.layers[layer].bodies[i].destroy();
  77144. }
  77145. map.layers[layer].bodies.length = 0;
  77146. },
  77147. /**
  77148. * Goes through all tiles in the given Tilemap and TilemapLayer and converts those set to collide into physics bodies.
  77149. * Only call this *after* you have specified all of the tiles you wish to collide with calls like Tilemap.setCollisionBetween, etc.
  77150. * Every time you call this method it will destroy any previously created bodies and remove them from the world.
  77151. * Therefore understand it's a very expensive operation and not to be done in a core game update loop.
  77152. *
  77153. * @method Phaser.Physics.P2#convertTilemap
  77154. * @param {Phaser.Tilemap} map - The Tilemap to get the map data from.
  77155. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to map.currentLayer.
  77156. * @param {boolean} [addToWorld=true] - If true it will automatically add each body to the world, otherwise it's up to you to do so.
  77157. * @param {boolean} [optimize=true] - If true adjacent colliding tiles will be combined into a single body to save processing. However it means you cannot perform specific Tile to Body collision responses.
  77158. * @return {array} An array of the Phaser.Physics.P2.Body objects that were created.
  77159. */
  77160. convertTilemap: function (map, layer, addToWorld, optimize) {
  77161. layer = map.getLayer(layer);
  77162. if (addToWorld === undefined) { addToWorld = true; }
  77163. if (optimize === undefined) { optimize = true; }
  77164. // If the bodies array is already populated we need to nuke it
  77165. this.clearTilemapLayerBodies(map, layer);
  77166. var width = 0;
  77167. var sx = 0;
  77168. var sy = 0;
  77169. for (var y = 0, h = map.layers[layer].height; y < h; y++)
  77170. {
  77171. width = 0;
  77172. for (var x = 0, w = map.layers[layer].width; x < w; x++)
  77173. {
  77174. var tile = map.layers[layer].data[y][x];
  77175. if (tile && tile.index > -1 && tile.collides)
  77176. {
  77177. if (optimize)
  77178. {
  77179. var right = map.getTileRight(layer, x, y);
  77180. if (width === 0)
  77181. {
  77182. sx = tile.x * tile.width;
  77183. sy = tile.y * tile.height;
  77184. width = tile.width;
  77185. }
  77186. if (right && right.collides)
  77187. {
  77188. width += tile.width;
  77189. }
  77190. else
  77191. {
  77192. var body = this.createBody(sx, sy, 0, false);
  77193. body.addRectangle(width, tile.height, width / 2, tile.height / 2, 0);
  77194. if (addToWorld)
  77195. {
  77196. this.addBody(body);
  77197. }
  77198. map.layers[layer].bodies.push(body);
  77199. width = 0;
  77200. }
  77201. }
  77202. else
  77203. {
  77204. var body = this.createBody(tile.x * tile.width, tile.y * tile.height, 0, false);
  77205. body.addRectangle(tile.width, tile.height, tile.width / 2, tile.height / 2, 0);
  77206. if (addToWorld)
  77207. {
  77208. this.addBody(body);
  77209. }
  77210. map.layers[layer].bodies.push(body);
  77211. }
  77212. }
  77213. }
  77214. }
  77215. return map.layers[layer].bodies;
  77216. },
  77217. /**
  77218. * Convert p2 physics value (meters) to pixel scale.
  77219. * By default Phaser uses a scale of 20px per meter.
  77220. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  77221. *
  77222. * @method Phaser.Physics.P2#mpx
  77223. * @param {number} v - The value to convert.
  77224. * @return {number} The scaled value.
  77225. */
  77226. mpx: function (v) {
  77227. return v *= 20;
  77228. },
  77229. /**
  77230. * Convert pixel value to p2 physics scale (meters).
  77231. * By default Phaser uses a scale of 20px per meter.
  77232. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  77233. *
  77234. * @method Phaser.Physics.P2#pxm
  77235. * @param {number} v - The value to convert.
  77236. * @return {number} The scaled value.
  77237. */
  77238. pxm: function (v) {
  77239. return v * 0.05;
  77240. },
  77241. /**
  77242. * Convert p2 physics value (meters) to pixel scale and inverses it.
  77243. * By default Phaser uses a scale of 20px per meter.
  77244. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  77245. *
  77246. * @method Phaser.Physics.P2#mpxi
  77247. * @param {number} v - The value to convert.
  77248. * @return {number} The scaled value.
  77249. */
  77250. mpxi: function (v) {
  77251. return v *= -20;
  77252. },
  77253. /**
  77254. * Convert pixel value to p2 physics scale (meters) and inverses it.
  77255. * By default Phaser uses a scale of 20px per meter.
  77256. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  77257. *
  77258. * @method Phaser.Physics.P2#pxmi
  77259. * @param {number} v - The value to convert.
  77260. * @return {number} The scaled value.
  77261. */
  77262. pxmi: function (v) {
  77263. return v * -0.05;
  77264. }
  77265. };
  77266. /**
  77267. * @name Phaser.Physics.P2#friction
  77268. * @property {number} friction - Friction between colliding bodies. This value is used if no matching ContactMaterial is found for a Material pair.
  77269. */
  77270. Object.defineProperty(Phaser.Physics.P2.prototype, "friction", {
  77271. get: function () {
  77272. return this.world.defaultContactMaterial.friction;
  77273. },
  77274. set: function (value) {
  77275. this.world.defaultContactMaterial.friction = value;
  77276. }
  77277. });
  77278. /**
  77279. * @name Phaser.Physics.P2#restitution
  77280. * @property {number} restitution - Default coefficient of restitution between colliding bodies. This value is used if no matching ContactMaterial is found for a Material pair.
  77281. */
  77282. Object.defineProperty(Phaser.Physics.P2.prototype, "restitution", {
  77283. get: function () {
  77284. return this.world.defaultContactMaterial.restitution;
  77285. },
  77286. set: function (value) {
  77287. this.world.defaultContactMaterial.restitution = value;
  77288. }
  77289. });
  77290. /**
  77291. * @name Phaser.Physics.P2#contactMaterial
  77292. * @property {p2.ContactMaterial} contactMaterial - The default Contact Material being used by the World.
  77293. */
  77294. Object.defineProperty(Phaser.Physics.P2.prototype, "contactMaterial", {
  77295. get: function () {
  77296. return this.world.defaultContactMaterial;
  77297. },
  77298. set: function (value) {
  77299. this.world.defaultContactMaterial = value;
  77300. }
  77301. });
  77302. /**
  77303. * @name Phaser.Physics.P2#applySpringForces
  77304. * @property {boolean} applySpringForces - Enable to automatically apply spring forces each step.
  77305. */
  77306. Object.defineProperty(Phaser.Physics.P2.prototype, "applySpringForces", {
  77307. get: function () {
  77308. return this.world.applySpringForces;
  77309. },
  77310. set: function (value) {
  77311. this.world.applySpringForces = value;
  77312. }
  77313. });
  77314. /**
  77315. * @name Phaser.Physics.P2#applyDamping
  77316. * @property {boolean} applyDamping - Enable to automatically apply body damping each step.
  77317. */
  77318. Object.defineProperty(Phaser.Physics.P2.prototype, "applyDamping", {
  77319. get: function () {
  77320. return this.world.applyDamping;
  77321. },
  77322. set: function (value) {
  77323. this.world.applyDamping = value;
  77324. }
  77325. });
  77326. /**
  77327. * @name Phaser.Physics.P2#applyGravity
  77328. * @property {boolean} applyGravity - Enable to automatically apply gravity each step.
  77329. */
  77330. Object.defineProperty(Phaser.Physics.P2.prototype, "applyGravity", {
  77331. get: function () {
  77332. return this.world.applyGravity;
  77333. },
  77334. set: function (value) {
  77335. this.world.applyGravity = value;
  77336. }
  77337. });
  77338. /**
  77339. * @name Phaser.Physics.P2#solveConstraints
  77340. * @property {boolean} solveConstraints - Enable/disable constraint solving in each step.
  77341. */
  77342. Object.defineProperty(Phaser.Physics.P2.prototype, "solveConstraints", {
  77343. get: function () {
  77344. return this.world.solveConstraints;
  77345. },
  77346. set: function (value) {
  77347. this.world.solveConstraints = value;
  77348. }
  77349. });
  77350. /**
  77351. * @name Phaser.Physics.P2#time
  77352. * @property {boolean} time - The World time.
  77353. * @readonly
  77354. */
  77355. Object.defineProperty(Phaser.Physics.P2.prototype, "time", {
  77356. get: function () {
  77357. return this.world.time;
  77358. }
  77359. });
  77360. /**
  77361. * @name Phaser.Physics.P2#emitImpactEvent
  77362. * @property {boolean} emitImpactEvent - Set to true if you want to the world to emit the "impact" event. Turning this off could improve performance.
  77363. */
  77364. Object.defineProperty(Phaser.Physics.P2.prototype, "emitImpactEvent", {
  77365. get: function () {
  77366. return this.world.emitImpactEvent;
  77367. },
  77368. set: function (value) {
  77369. this.world.emitImpactEvent = value;
  77370. }
  77371. });
  77372. /**
  77373. * How to deactivate bodies during simulation. Possible modes are: World.NO_SLEEPING, World.BODY_SLEEPING and World.ISLAND_SLEEPING.
  77374. * If sleeping is enabled, you might need to wake up the bodies if they fall asleep when they shouldn't. If you want to enable sleeping in the world, but want to disable it for a particular body, see Body.allowSleep.
  77375. * @name Phaser.Physics.P2#sleepMode
  77376. * @property {number} sleepMode
  77377. */
  77378. Object.defineProperty(Phaser.Physics.P2.prototype, "sleepMode", {
  77379. get: function () {
  77380. return this.world.sleepMode;
  77381. },
  77382. set: function (value) {
  77383. this.world.sleepMode = value;
  77384. }
  77385. });
  77386. /**
  77387. * @name Phaser.Physics.P2#total
  77388. * @property {number} total - The total number of bodies in the world.
  77389. * @readonly
  77390. */
  77391. Object.defineProperty(Phaser.Physics.P2.prototype, "total", {
  77392. get: function () {
  77393. return this.world.bodies.length;
  77394. }
  77395. });
  77396. /* jshint noarg: false */
  77397. /**
  77398. * @author Georgios Kaleadis https://github.com/georgiee
  77399. * @author Richard Davey <rich@photonstorm.com>
  77400. * @copyright 2016 Photon Storm Ltd.
  77401. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  77402. */
  77403. /**
  77404. * Allow to access a list of created fixture (coming from Body#addPhaserPolygon)
  77405. * which itself parse the input from PhysicsEditor with the custom phaser exporter.
  77406. * You can access fixtures of a Body by a group index or even by providing a fixture Key.
  77407. * You can set the fixture key and also the group index for a fixture in PhysicsEditor.
  77408. * This gives you the power to create a complex body built of many fixtures and modify them
  77409. * during runtime (to remove parts, set masks, categories & sensor properties)
  77410. *
  77411. * @class Phaser.Physics.P2.FixtureList
  77412. * @constructor
  77413. * @param {Array} list - A list of fixtures (from Phaser.Physics.P2.Body#addPhaserPolygon)
  77414. */
  77415. Phaser.Physics.P2.FixtureList = function (list) {
  77416. if (!Array.isArray(list))
  77417. {
  77418. list = [list];
  77419. }
  77420. this.rawList = list;
  77421. this.init();
  77422. this.parse(this.rawList);
  77423. };
  77424. Phaser.Physics.P2.FixtureList.prototype = {
  77425. /**
  77426. * @method Phaser.Physics.P2.FixtureList#init
  77427. */
  77428. init: function () {
  77429. /**
  77430. * @property {object} namedFixtures - Collect all fixtures with a key
  77431. * @private
  77432. */
  77433. this.namedFixtures = {};
  77434. /**
  77435. * @property {Array} groupedFixtures - Collect all given fixtures per group index. Notice: Every fixture with a key also belongs to a group
  77436. * @private
  77437. */
  77438. this.groupedFixtures = [];
  77439. /**
  77440. * @property {Array} allFixtures - This is a list of everything in this collection
  77441. * @private
  77442. */
  77443. this.allFixtures = [];
  77444. },
  77445. /**
  77446. * @method Phaser.Physics.P2.FixtureList#setCategory
  77447. * @param {number} bit - The bit to set as the collision group.
  77448. * @param {string} fixtureKey - Only apply to the fixture with the given key.
  77449. */
  77450. setCategory: function (bit, fixtureKey) {
  77451. var setter = function(fixture) {
  77452. fixture.collisionGroup = bit;
  77453. };
  77454. this.getFixtures(fixtureKey).forEach(setter);
  77455. },
  77456. /**
  77457. * @method Phaser.Physics.P2.FixtureList#setMask
  77458. * @param {number} bit - The bit to set as the collision mask
  77459. * @param {string} fixtureKey - Only apply to the fixture with the given key
  77460. */
  77461. setMask: function (bit, fixtureKey) {
  77462. var setter = function(fixture) {
  77463. fixture.collisionMask = bit;
  77464. };
  77465. this.getFixtures(fixtureKey).forEach(setter);
  77466. },
  77467. /**
  77468. * @method Phaser.Physics.P2.FixtureList#setSensor
  77469. * @param {boolean} value - sensor true or false
  77470. * @param {string} fixtureKey - Only apply to the fixture with the given key
  77471. */
  77472. setSensor: function (value, fixtureKey) {
  77473. var setter = function(fixture) {
  77474. fixture.sensor = value;
  77475. };
  77476. this.getFixtures(fixtureKey).forEach(setter);
  77477. },
  77478. /**
  77479. * @method Phaser.Physics.P2.FixtureList#setMaterial
  77480. * @param {Object} material - The contact material for a fixture
  77481. * @param {string} fixtureKey - Only apply to the fixture with the given key
  77482. */
  77483. setMaterial: function (material, fixtureKey) {
  77484. var setter = function(fixture) {
  77485. fixture.material = material;
  77486. };
  77487. this.getFixtures(fixtureKey).forEach(setter);
  77488. },
  77489. /**
  77490. * Accessor to get either a list of specified fixtures by key or the whole fixture list
  77491. *
  77492. * @method Phaser.Physics.P2.FixtureList#getFixtures
  77493. * @param {array} keys - A list of fixture keys
  77494. */
  77495. getFixtures: function (keys) {
  77496. var fixtures = [];
  77497. if (keys)
  77498. {
  77499. if (!(keys instanceof Array))
  77500. {
  77501. keys = [keys];
  77502. }
  77503. var self = this;
  77504. keys.forEach(function(key) {
  77505. if (self.namedFixtures[key])
  77506. {
  77507. fixtures.push(self.namedFixtures[key]);
  77508. }
  77509. });
  77510. return this.flatten(fixtures);
  77511. }
  77512. else
  77513. {
  77514. return this.allFixtures;
  77515. }
  77516. },
  77517. /**
  77518. * Accessor to get either a single fixture by its key.
  77519. *
  77520. * @method Phaser.Physics.P2.FixtureList#getFixtureByKey
  77521. * @param {string} key - The key of the fixture.
  77522. */
  77523. getFixtureByKey: function (key) {
  77524. return this.namedFixtures[key];
  77525. },
  77526. /**
  77527. * Accessor to get a group of fixtures by its group index.
  77528. *
  77529. * @method Phaser.Physics.P2.FixtureList#getGroup
  77530. * @param {number} groupID - The group index.
  77531. */
  77532. getGroup: function (groupID) {
  77533. return this.groupedFixtures[groupID];
  77534. },
  77535. /**
  77536. * Parser for the output of Phaser.Physics.P2.Body#addPhaserPolygon
  77537. *
  77538. * @method Phaser.Physics.P2.FixtureList#parse
  77539. */
  77540. parse: function () {
  77541. var key, value, _ref, _results;
  77542. _ref = this.rawList;
  77543. _results = [];
  77544. for (key in _ref)
  77545. {
  77546. value = _ref[key];
  77547. if (!isNaN(key - 0))
  77548. {
  77549. this.groupedFixtures[key] = this.groupedFixtures[key] || [];
  77550. this.groupedFixtures[key] = this.groupedFixtures[key].concat(value);
  77551. }
  77552. else
  77553. {
  77554. this.namedFixtures[key] = this.flatten(value);
  77555. }
  77556. _results.push(this.allFixtures = this.flatten(this.groupedFixtures));
  77557. }
  77558. },
  77559. /**
  77560. * A helper to flatten arrays. This is very useful as the fixtures are nested from time to time due to the way P2 creates and splits polygons.
  77561. *
  77562. * @method Phaser.Physics.P2.FixtureList#flatten
  77563. * @param {array} array - The array to flatten. Notice: This will happen recursive not shallow.
  77564. */
  77565. flatten: function (array) {
  77566. var result, self;
  77567. result = [];
  77568. self = arguments.callee;
  77569. array.forEach(function(item) {
  77570. return Array.prototype.push.apply(result, (Array.isArray(item) ? self(item) : [item]));
  77571. });
  77572. return result;
  77573. }
  77574. };
  77575. /**
  77576. * @author Richard Davey <rich@photonstorm.com>
  77577. * @copyright 2016 Photon Storm Ltd.
  77578. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  77579. */
  77580. /**
  77581. * A PointProxy is an internal class that allows for direct getter/setter style property access to Arrays and TypedArrays.
  77582. *
  77583. * @class Phaser.Physics.P2.PointProxy
  77584. * @constructor
  77585. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  77586. * @param {any} destination - The object to bind to.
  77587. */
  77588. Phaser.Physics.P2.PointProxy = function (world, destination) {
  77589. this.world = world;
  77590. this.destination = destination;
  77591. };
  77592. Phaser.Physics.P2.PointProxy.prototype.constructor = Phaser.Physics.P2.PointProxy;
  77593. /**
  77594. * @name Phaser.Physics.P2.PointProxy#x
  77595. * @property {number} x - The x property of this PointProxy get and set in pixels.
  77596. */
  77597. Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "x", {
  77598. get: function () {
  77599. return this.world.mpx(this.destination[0]);
  77600. },
  77601. set: function (value) {
  77602. this.destination[0] = this.world.pxm(value);
  77603. }
  77604. });
  77605. /**
  77606. * @name Phaser.Physics.P2.PointProxy#y
  77607. * @property {number} y - The y property of this PointProxy get and set in pixels.
  77608. */
  77609. Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "y", {
  77610. get: function () {
  77611. return this.world.mpx(this.destination[1]);
  77612. },
  77613. set: function (value) {
  77614. this.destination[1] = this.world.pxm(value);
  77615. }
  77616. });
  77617. /**
  77618. * @name Phaser.Physics.P2.PointProxy#mx
  77619. * @property {number} mx - The x property of this PointProxy get and set in meters.
  77620. */
  77621. Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "mx", {
  77622. get: function () {
  77623. return this.destination[0];
  77624. },
  77625. set: function (value) {
  77626. this.destination[0] = value;
  77627. }
  77628. });
  77629. /**
  77630. * @name Phaser.Physics.P2.PointProxy#my
  77631. * @property {number} my - The x property of this PointProxy get and set in meters.
  77632. */
  77633. Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "my", {
  77634. get: function () {
  77635. return this.destination[1];
  77636. },
  77637. set: function (value) {
  77638. this.destination[1] = value;
  77639. }
  77640. });
  77641. /**
  77642. * @author Richard Davey <rich@photonstorm.com>
  77643. * @copyright 2016 Photon Storm Ltd.
  77644. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  77645. */
  77646. /**
  77647. * A InversePointProxy is an internal class that allows for direct getter/setter style property access to Arrays and TypedArrays but inverses the values on set.
  77648. *
  77649. * @class Phaser.Physics.P2.InversePointProxy
  77650. * @constructor
  77651. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  77652. * @param {any} destination - The object to bind to.
  77653. */
  77654. Phaser.Physics.P2.InversePointProxy = function (world, destination) {
  77655. this.world = world;
  77656. this.destination = destination;
  77657. };
  77658. Phaser.Physics.P2.InversePointProxy.prototype.constructor = Phaser.Physics.P2.InversePointProxy;
  77659. /**
  77660. * @name Phaser.Physics.P2.InversePointProxy#x
  77661. * @property {number} x - The x property of this InversePointProxy get and set in pixels.
  77662. */
  77663. Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "x", {
  77664. get: function () {
  77665. return this.world.mpxi(this.destination[0]);
  77666. },
  77667. set: function (value) {
  77668. this.destination[0] = this.world.pxmi(value);
  77669. }
  77670. });
  77671. /**
  77672. * @name Phaser.Physics.P2.InversePointProxy#y
  77673. * @property {number} y - The y property of this InversePointProxy get and set in pixels.
  77674. */
  77675. Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "y", {
  77676. get: function () {
  77677. return this.world.mpxi(this.destination[1]);
  77678. },
  77679. set: function (value) {
  77680. this.destination[1] = this.world.pxmi(value);
  77681. }
  77682. });
  77683. /**
  77684. * @name Phaser.Physics.P2.InversePointProxy#mx
  77685. * @property {number} mx - The x property of this InversePointProxy get and set in meters.
  77686. */
  77687. Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "mx", {
  77688. get: function () {
  77689. return this.destination[0];
  77690. },
  77691. set: function (value) {
  77692. this.destination[0] = -value;
  77693. }
  77694. });
  77695. /**
  77696. * @name Phaser.Physics.P2.InversePointProxy#my
  77697. * @property {number} my - The y property of this InversePointProxy get and set in meters.
  77698. */
  77699. Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "my", {
  77700. get: function () {
  77701. return this.destination[1];
  77702. },
  77703. set: function (value) {
  77704. this.destination[1] = -value;
  77705. }
  77706. });
  77707. /**
  77708. * @author Richard Davey <rich@photonstorm.com>
  77709. * @copyright 2016 Photon Storm Ltd.
  77710. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  77711. */
  77712. /**
  77713. * The Physics Body is typically linked to a single Sprite and defines properties that determine how the physics body is simulated.
  77714. * These properties affect how the body reacts to forces, what forces it generates on itself (to simulate friction), and how it reacts to collisions in the scene.
  77715. * In most cases, the properties are used to simulate physical effects. Each body also has its own property values that determine exactly how it reacts to forces and collisions in the scene.
  77716. * By default a single Rectangle shape is added to the Body that matches the dimensions of the parent Sprite. See addShape, removeShape, clearShapes to add extra shapes around the Body.
  77717. * Note: When bound to a Sprite to avoid single-pixel jitters on mobile devices we strongly recommend using Sprite sizes that are even on both axis, i.e. 128x128 not 127x127.
  77718. * Note: When a game object is given a P2 body it has its anchor x/y set to 0.5, so it becomes centered.
  77719. *
  77720. * @class Phaser.Physics.P2.Body
  77721. * @constructor
  77722. * @param {Phaser.Game} game - Game reference to the currently running game.
  77723. * @param {Phaser.Sprite} [sprite] - The Sprite object this physics body belongs to.
  77724. * @param {number} [x=0] - The x coordinate of this Body.
  77725. * @param {number} [y=0] - The y coordinate of this Body.
  77726. * @param {number} [mass=1] - The default mass of this Body (0 = static).
  77727. */
  77728. Phaser.Physics.P2.Body = function (game, sprite, x, y, mass) {
  77729. sprite = sprite || null;
  77730. x = x || 0;
  77731. y = y || 0;
  77732. if (mass === undefined) { mass = 1; }
  77733. /**
  77734. * @property {Phaser.Game} game - Local reference to game.
  77735. */
  77736. this.game = game;
  77737. /**
  77738. * @property {Phaser.Physics.P2} world - Local reference to the P2 World.
  77739. */
  77740. this.world = game.physics.p2;
  77741. /**
  77742. * @property {Phaser.Sprite} sprite - Reference to the parent Sprite.
  77743. */
  77744. this.sprite = sprite;
  77745. /**
  77746. * @property {number} type - The type of physics system this body belongs to.
  77747. */
  77748. this.type = Phaser.Physics.P2JS;
  77749. /**
  77750. * @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
  77751. */
  77752. this.offset = new Phaser.Point();
  77753. /**
  77754. * @property {p2.Body} data - The p2 Body data.
  77755. * @protected
  77756. */
  77757. this.data = new p2.Body({ position: [ this.world.pxmi(x), this.world.pxmi(y) ], mass: mass });
  77758. this.data.parent = this;
  77759. /**
  77760. * @property {Phaser.Physics.P2.InversePointProxy} velocity - The velocity of the body. Set velocity.x to a negative value to move to the left, position to the right. velocity.y negative values move up, positive move down.
  77761. */
  77762. this.velocity = new Phaser.Physics.P2.InversePointProxy(this.world, this.data.velocity);
  77763. /**
  77764. * @property {Phaser.Physics.P2.InversePointProxy} force - The force applied to the body.
  77765. */
  77766. this.force = new Phaser.Physics.P2.InversePointProxy(this.world, this.data.force);
  77767. /**
  77768. * @property {Phaser.Point} gravity - A locally applied gravity force to the Body. Applied directly before the world step. NOTE: Not currently implemented.
  77769. */
  77770. this.gravity = new Phaser.Point();
  77771. /**
  77772. * Dispatched when a first contact is created between shapes in two bodies.
  77773. * This event is fired during the step, so collision has already taken place.
  77774. *
  77775. * The event will be sent 5 arguments in this order:
  77776. *
  77777. * The Phaser.Physics.P2.Body it is in contact with. *This might be null* if the Body was created directly in the p2 world.
  77778. * The p2.Body this Body is in contact with.
  77779. * The Shape from this body that caused the contact.
  77780. * The Shape from the contact body.
  77781. * The Contact Equation data array.
  77782. *
  77783. * @property {Phaser.Signal} onBeginContact
  77784. */
  77785. this.onBeginContact = new Phaser.Signal();
  77786. /**
  77787. * Dispatched when contact ends between shapes in two bodies.
  77788. * This event is fired during the step, so collision has already taken place.
  77789. *
  77790. * The event will be sent 4 arguments in this order:
  77791. *
  77792. * The Phaser.Physics.P2.Body it is in contact with. *This might be null* if the Body was created directly in the p2 world.
  77793. * The p2.Body this Body has ended contact with.
  77794. * The Shape from this body that caused the original contact.
  77795. * The Shape from the contact body.
  77796. *
  77797. * @property {Phaser.Signal} onEndContact
  77798. */
  77799. this.onEndContact = new Phaser.Signal();
  77800. /**
  77801. * @property {array} collidesWith - Array of CollisionGroups that this Bodies shapes collide with.
  77802. */
  77803. this.collidesWith = [];
  77804. /**
  77805. * @property {boolean} removeNextStep - To avoid deleting this body during a physics step, and causing all kinds of problems, set removeNextStep to true to have it removed in the next preUpdate.
  77806. */
  77807. this.removeNextStep = false;
  77808. /**
  77809. * @property {Phaser.Physics.P2.BodyDebug} debugBody - Reference to the debug body.
  77810. */
  77811. this.debugBody = null;
  77812. /**
  77813. * @property {boolean} dirty - Internally used by Sprite.x/y
  77814. */
  77815. this.dirty = false;
  77816. /**
  77817. * @property {boolean} _collideWorldBounds - Internal var that determines if this Body collides with the world bounds or not.
  77818. * @private
  77819. */
  77820. this._collideWorldBounds = true;
  77821. /**
  77822. * @property {object} _bodyCallbacks - Array of Body callbacks.
  77823. * @private
  77824. */
  77825. this._bodyCallbacks = {};
  77826. /**
  77827. * @property {object} _bodyCallbackContext - Array of Body callback contexts.
  77828. * @private
  77829. */
  77830. this._bodyCallbackContext = {};
  77831. /**
  77832. * @property {object} _groupCallbacks - Array of Group callbacks.
  77833. * @private
  77834. */
  77835. this._groupCallbacks = {};
  77836. /**
  77837. * @property {object} _bodyCallbackContext - Array of Grouo callback contexts.
  77838. * @private
  77839. */
  77840. this._groupCallbackContext = {};
  77841. /**
  77842. * @property {boolean} _reset - Internal var.
  77843. * @private
  77844. */
  77845. this._reset = false;
  77846. // Set-up the default shape
  77847. if (sprite)
  77848. {
  77849. this.setRectangleFromSprite(sprite);
  77850. if (sprite.exists)
  77851. {
  77852. this.game.physics.p2.addBody(this);
  77853. }
  77854. }
  77855. };
  77856. Phaser.Physics.P2.Body.prototype = {
  77857. /**
  77858. * Sets a callback to be fired any time a shape in this Body impacts with a shape in the given Body. The impact test is performed against body.id values.
  77859. * The callback will be sent 4 parameters: This body, the body that impacted, the Shape in this body and the shape in the impacting body.
  77860. * Note that the impact event happens after collision resolution, so it cannot be used to prevent a collision from happening.
  77861. * It also happens mid-step. So do not destroy a Body during this callback, instead set safeDestroy to true so it will be killed on the next preUpdate.
  77862. *
  77863. * @method Phaser.Physics.P2.Body#createBodyCallback
  77864. * @param {Phaser.Sprite|Phaser.TileSprite|Phaser.Physics.P2.Body|p2.Body} object - The object to send impact events for.
  77865. * @param {function} callback - The callback to fire on impact. Set to null to clear a previously set callback.
  77866. * @param {object} callbackContext - The context under which the callback will fire.
  77867. */
  77868. createBodyCallback: function (object, callback, callbackContext) {
  77869. var id = -1;
  77870. if (object['id'])
  77871. {
  77872. id = object.id;
  77873. }
  77874. else if (object['body'])
  77875. {
  77876. id = object.body.id;
  77877. }
  77878. if (id > -1)
  77879. {
  77880. if (callback === null)
  77881. {
  77882. delete (this._bodyCallbacks[id]);
  77883. delete (this._bodyCallbackContext[id]);
  77884. }
  77885. else
  77886. {
  77887. this._bodyCallbacks[id] = callback;
  77888. this._bodyCallbackContext[id] = callbackContext;
  77889. }
  77890. }
  77891. },
  77892. /**
  77893. * Sets a callback to be fired any time this Body impacts with the given Group. The impact test is performed against shape.collisionGroup values.
  77894. * The callback will be sent 4 parameters: This body, the body that impacted, the Shape in this body and the shape in the impacting body.
  77895. * This callback will only fire if this Body has been assigned a collision group.
  77896. * Note that the impact event happens after collision resolution, so it cannot be used to prevent a collision from happening.
  77897. * It also happens mid-step. So do not destroy a Body during this callback, instead set safeDestroy to true so it will be killed on the next preUpdate.
  77898. *
  77899. * @method Phaser.Physics.P2.Body#createGroupCallback
  77900. * @param {Phaser.Physics.CollisionGroup} group - The Group to send impact events for.
  77901. * @param {function} callback - The callback to fire on impact. Set to null to clear a previously set callback.
  77902. * @param {object} callbackContext - The context under which the callback will fire.
  77903. */
  77904. createGroupCallback: function (group, callback, callbackContext) {
  77905. if (callback === null)
  77906. {
  77907. delete (this._groupCallbacks[group.mask]);
  77908. delete (this._groupCallbackContext[group.mask]);
  77909. }
  77910. else
  77911. {
  77912. this._groupCallbacks[group.mask] = callback;
  77913. this._groupCallbackContext[group.mask] = callbackContext;
  77914. }
  77915. },
  77916. /**
  77917. * Gets the collision bitmask from the groups this body collides with.
  77918. *
  77919. * @method Phaser.Physics.P2.Body#getCollisionMask
  77920. * @return {number} The bitmask.
  77921. */
  77922. getCollisionMask: function () {
  77923. var mask = 0;
  77924. if (this._collideWorldBounds)
  77925. {
  77926. mask = this.game.physics.p2.boundsCollisionGroup.mask;
  77927. }
  77928. for (var i = 0; i < this.collidesWith.length; i++)
  77929. {
  77930. mask = mask | this.collidesWith[i].mask;
  77931. }
  77932. return mask;
  77933. },
  77934. /**
  77935. * Updates the collisionMask.
  77936. *
  77937. * @method Phaser.Physics.P2.Body#updateCollisionMask
  77938. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision group will be added to all Shapes in this Body.
  77939. */
  77940. updateCollisionMask: function (shape) {
  77941. var mask = this.getCollisionMask();
  77942. if (shape === undefined)
  77943. {
  77944. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  77945. {
  77946. this.data.shapes[i].collisionMask = mask;
  77947. }
  77948. }
  77949. else
  77950. {
  77951. shape.collisionMask = mask;
  77952. }
  77953. },
  77954. /**
  77955. * Sets the given CollisionGroup to be the collision group for all shapes in this Body, unless a shape is specified.
  77956. * This also resets the collisionMask.
  77957. *
  77958. * @method Phaser.Physics.P2.Body#setCollisionGroup
  77959. * @param {Phaser.Physics.CollisionGroup} group - The Collision Group that this Bodies shapes will use.
  77960. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision group will be added to all Shapes in this Body.
  77961. */
  77962. setCollisionGroup: function (group, shape) {
  77963. var mask = this.getCollisionMask();
  77964. if (shape === undefined)
  77965. {
  77966. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  77967. {
  77968. this.data.shapes[i].collisionGroup = group.mask;
  77969. this.data.shapes[i].collisionMask = mask;
  77970. }
  77971. }
  77972. else
  77973. {
  77974. shape.collisionGroup = group.mask;
  77975. shape.collisionMask = mask;
  77976. }
  77977. },
  77978. /**
  77979. * Clears the collision data from the shapes in this Body. Optionally clears Group and/or Mask.
  77980. *
  77981. * @method Phaser.Physics.P2.Body#clearCollision
  77982. * @param {boolean} [clearGroup=true] - Clear the collisionGroup value from the shape/s?
  77983. * @param {boolean} [clearMask=true] - Clear the collisionMask value from the shape/s?
  77984. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision data will be cleared from all Shapes in this Body.
  77985. */
  77986. clearCollision: function (clearGroup, clearMask, shape) {
  77987. if (clearGroup === undefined) { clearGroup = true; }
  77988. if (clearMask === undefined) { clearMask = true; }
  77989. if (shape === undefined)
  77990. {
  77991. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  77992. {
  77993. if (clearGroup)
  77994. {
  77995. this.data.shapes[i].collisionGroup = null;
  77996. }
  77997. if (clearMask)
  77998. {
  77999. this.data.shapes[i].collisionMask = null;
  78000. }
  78001. }
  78002. }
  78003. else
  78004. {
  78005. if (clearGroup)
  78006. {
  78007. shape.collisionGroup = null;
  78008. }
  78009. if (clearMask)
  78010. {
  78011. shape.collisionMask = null;
  78012. }
  78013. }
  78014. if (clearGroup)
  78015. {
  78016. this.collidesWith.length = 0;
  78017. }
  78018. },
  78019. /**
  78020. * Removes the given CollisionGroup, or array of CollisionGroups, from the list of groups that this body will collide with and updates the collision masks.
  78021. *
  78022. * @method Phaser.Physics.P2.Body#removeCollisionGroup
  78023. * @param {Phaser.Physics.CollisionGroup|array} group - The Collision Group or Array of Collision Groups that this Bodies shapes should not collide with anymore.
  78024. * @param {boolean} [clearCallback=true] - Clear the callback that will be triggered when this Body impacts with the given Group?
  78025. * @param {p2.Shape} [shape] - An optional Shape. If not provided the updated collision mask will be added to all Shapes in this Body.
  78026. */
  78027. removeCollisionGroup: function (group, clearCallback, shape) {
  78028. if (clearCallback === undefined) { clearCallback = true; }
  78029. var index;
  78030. if (Array.isArray(group))
  78031. {
  78032. for (var i = 0; i < group.length; i++)
  78033. {
  78034. index = this.collidesWith.indexOf(group[i]);
  78035. if (index > -1)
  78036. {
  78037. this.collidesWith.splice(index, 1);
  78038. if (clearCallback)
  78039. {
  78040. delete (this._groupCallbacks[group.mask]);
  78041. delete (this._groupCallbackContext[group.mask]);
  78042. }
  78043. }
  78044. }
  78045. }
  78046. else
  78047. {
  78048. index = this.collidesWith.indexOf(group);
  78049. if (index > -1)
  78050. {
  78051. this.collidesWith.splice(index, 1);
  78052. if (clearCallback)
  78053. {
  78054. delete (this._groupCallbacks[group.mask]);
  78055. delete (this._groupCallbackContext[group.mask]);
  78056. }
  78057. }
  78058. }
  78059. var mask = this.getCollisionMask();
  78060. if (shape === undefined)
  78061. {
  78062. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  78063. {
  78064. this.data.shapes[i].collisionMask = mask;
  78065. }
  78066. }
  78067. else
  78068. {
  78069. shape.collisionMask = mask;
  78070. }
  78071. },
  78072. /**
  78073. * Adds the given CollisionGroup, or array of CollisionGroups, to the list of groups that this body will collide with and updates the collision masks.
  78074. *
  78075. * @method Phaser.Physics.P2.Body#collides
  78076. * @param {Phaser.Physics.CollisionGroup|array} group - The Collision Group or Array of Collision Groups that this Bodies shapes will collide with.
  78077. * @param {function} [callback] - Optional callback that will be triggered when this Body impacts with the given Group.
  78078. * @param {object} [callbackContext] - The context under which the callback will be called.
  78079. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision mask will be added to all Shapes in this Body.
  78080. */
  78081. collides: function (group, callback, callbackContext, shape) {
  78082. if (Array.isArray(group))
  78083. {
  78084. for (var i = 0; i < group.length; i++)
  78085. {
  78086. if (this.collidesWith.indexOf(group[i]) === -1)
  78087. {
  78088. this.collidesWith.push(group[i]);
  78089. if (callback)
  78090. {
  78091. this.createGroupCallback(group[i], callback, callbackContext);
  78092. }
  78093. }
  78094. }
  78095. }
  78096. else
  78097. {
  78098. if (this.collidesWith.indexOf(group) === -1)
  78099. {
  78100. this.collidesWith.push(group);
  78101. if (callback)
  78102. {
  78103. this.createGroupCallback(group, callback, callbackContext);
  78104. }
  78105. }
  78106. }
  78107. var mask = this.getCollisionMask();
  78108. if (shape === undefined)
  78109. {
  78110. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  78111. {
  78112. this.data.shapes[i].collisionMask = mask;
  78113. }
  78114. }
  78115. else
  78116. {
  78117. shape.collisionMask = mask;
  78118. }
  78119. },
  78120. /**
  78121. * Moves the shape offsets so their center of mass becomes the body center of mass.
  78122. *
  78123. * @method Phaser.Physics.P2.Body#adjustCenterOfMass
  78124. */
  78125. adjustCenterOfMass: function () {
  78126. this.data.adjustCenterOfMass();
  78127. this.shapeChanged();
  78128. },
  78129. /**
  78130. * Gets the velocity of a point in the body.
  78131. *
  78132. * @method Phaser.Physics.P2.Body#getVelocityAtPoint
  78133. * @param {Array} result - A vector to store the result in.
  78134. * @param {Array} relativePoint - A world oriented vector, indicating the position of the point to get the velocity from.
  78135. * @return {Array} The result vector.
  78136. */
  78137. getVelocityAtPoint: function (result, relativePoint) {
  78138. return this.data.getVelocityAtPoint(result, relativePoint);
  78139. },
  78140. /**
  78141. * Apply damping, see http://code.google.com/p/bullet/issues/detail?id=74 for details.
  78142. *
  78143. * @method Phaser.Physics.P2.Body#applyDamping
  78144. * @param {number} dt - Current time step.
  78145. */
  78146. applyDamping: function (dt) {
  78147. this.data.applyDamping(dt);
  78148. },
  78149. /**
  78150. * Apply impulse to a point relative to the body.
  78151. * This could for example be a point on the Body surface. An impulse is a force added to a body during a short
  78152. * period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
  78153. *
  78154. * @method Phaser.Physics.P2.Body#applyImpulse
  78155. * @param {Float32Array|Array} impulse - The impulse vector to add, oriented in world space.
  78156. * @param {number} worldX - A point relative to the body in world space. If not given, it is set to zero and all of the impulse will be exerted on the center of mass.
  78157. * @param {number} worldY - A point relative to the body in world space. If not given, it is set to zero and all of the impulse will be exerted on the center of mass.
  78158. */
  78159. applyImpulse: function (impulse, worldX, worldY) {
  78160. this.data.applyImpulse(impulse, [this.world.pxmi(worldX), this.world.pxmi(worldY)]);
  78161. },
  78162. /**
  78163. * Apply impulse to a point local to the body.
  78164. *
  78165. * This could for example be a point on the Body surface. An impulse is a force added to a body during a short
  78166. * period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
  78167. *
  78168. * @method Phaser.Physics.P2.Body#applyImpulseLocal
  78169. * @param {Float32Array|Array} impulse - The impulse vector to add, oriented in local space.
  78170. * @param {number} localX - A local point on the body.
  78171. * @param {number} localY - A local point on the body.
  78172. */
  78173. applyImpulseLocal: function (impulse, localX, localY) {
  78174. this.data.applyImpulseLocal(impulse, [this.world.pxmi(localX), this.world.pxmi(localY)]);
  78175. },
  78176. /**
  78177. * Apply force to a world point.
  78178. *
  78179. * This could for example be a point on the RigidBody surface. Applying force
  78180. * this way will add to Body.force and Body.angularForce.
  78181. *
  78182. * @method Phaser.Physics.P2.Body#applyForce
  78183. * @param {Float32Array|Array} force - The force vector to add.
  78184. * @param {number} worldX - The world x point to apply the force on.
  78185. * @param {number} worldY - The world y point to apply the force on.
  78186. */
  78187. applyForce: function (force, worldX, worldY) {
  78188. this.data.applyForce(force, [this.world.pxmi(worldX), this.world.pxmi(worldY)]);
  78189. },
  78190. /**
  78191. * Sets the force on the body to zero.
  78192. *
  78193. * @method Phaser.Physics.P2.Body#setZeroForce
  78194. */
  78195. setZeroForce: function () {
  78196. this.data.setZeroForce();
  78197. },
  78198. /**
  78199. * If this Body is dynamic then this will zero its angular velocity.
  78200. *
  78201. * @method Phaser.Physics.P2.Body#setZeroRotation
  78202. */
  78203. setZeroRotation: function () {
  78204. this.data.angularVelocity = 0;
  78205. },
  78206. /**
  78207. * If this Body is dynamic then this will zero its velocity on both axis.
  78208. *
  78209. * @method Phaser.Physics.P2.Body#setZeroVelocity
  78210. */
  78211. setZeroVelocity: function () {
  78212. this.data.velocity[0] = 0;
  78213. this.data.velocity[1] = 0;
  78214. },
  78215. /**
  78216. * Sets the Body damping and angularDamping to zero.
  78217. *
  78218. * @method Phaser.Physics.P2.Body#setZeroDamping
  78219. */
  78220. setZeroDamping: function () {
  78221. this.data.damping = 0;
  78222. this.data.angularDamping = 0;
  78223. },
  78224. /**
  78225. * Transform a world point to local body frame.
  78226. *
  78227. * @method Phaser.Physics.P2.Body#toLocalFrame
  78228. * @param {Float32Array|Array} out - The vector to store the result in.
  78229. * @param {Float32Array|Array} worldPoint - The input world vector.
  78230. */
  78231. toLocalFrame: function (out, worldPoint) {
  78232. return this.data.toLocalFrame(out, worldPoint);
  78233. },
  78234. /**
  78235. * Transform a local point to world frame.
  78236. *
  78237. * @method Phaser.Physics.P2.Body#toWorldFrame
  78238. * @param {Array} out - The vector to store the result in.
  78239. * @param {Array} localPoint - The input local vector.
  78240. */
  78241. toWorldFrame: function (out, localPoint) {
  78242. return this.data.toWorldFrame(out, localPoint);
  78243. },
  78244. /**
  78245. * This will rotate the Body by the given speed to the left (counter-clockwise).
  78246. *
  78247. * @method Phaser.Physics.P2.Body#rotateLeft
  78248. * @param {number} speed - The speed at which it should rotate.
  78249. */
  78250. rotateLeft: function (speed) {
  78251. this.data.angularVelocity = this.world.pxm(-speed);
  78252. },
  78253. /**
  78254. * This will rotate the Body by the given speed to the left (clockwise).
  78255. *
  78256. * @method Phaser.Physics.P2.Body#rotateRight
  78257. * @param {number} speed - The speed at which it should rotate.
  78258. */
  78259. rotateRight: function (speed) {
  78260. this.data.angularVelocity = this.world.pxm(speed);
  78261. },
  78262. /**
  78263. * Moves the Body forwards based on its current angle and the given speed.
  78264. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78265. *
  78266. * @method Phaser.Physics.P2.Body#moveForward
  78267. * @param {number} speed - The speed at which it should move forwards.
  78268. */
  78269. moveForward: function (speed) {
  78270. var magnitude = this.world.pxmi(-speed);
  78271. var angle = this.data.angle + Math.PI / 2;
  78272. this.data.velocity[0] = magnitude * Math.cos(angle);
  78273. this.data.velocity[1] = magnitude * Math.sin(angle);
  78274. },
  78275. /**
  78276. * Moves the Body backwards based on its current angle and the given speed.
  78277. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78278. *
  78279. * @method Phaser.Physics.P2.Body#moveBackward
  78280. * @param {number} speed - The speed at which it should move backwards.
  78281. */
  78282. moveBackward: function (speed) {
  78283. var magnitude = this.world.pxmi(-speed);
  78284. var angle = this.data.angle + Math.PI / 2;
  78285. this.data.velocity[0] = -(magnitude * Math.cos(angle));
  78286. this.data.velocity[1] = -(magnitude * Math.sin(angle));
  78287. },
  78288. /**
  78289. * Applies a force to the Body that causes it to 'thrust' forwards, based on its current angle and the given speed.
  78290. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78291. *
  78292. * @method Phaser.Physics.P2.Body#thrust
  78293. * @param {number} speed - The speed at which it should thrust.
  78294. */
  78295. thrust: function (speed) {
  78296. var magnitude = this.world.pxmi(-speed);
  78297. var angle = this.data.angle + Math.PI / 2;
  78298. this.data.force[0] += magnitude * Math.cos(angle);
  78299. this.data.force[1] += magnitude * Math.sin(angle);
  78300. },
  78301. /**
  78302. * Applies a force to the Body that causes it to 'thrust' to the left, based on its current angle and the given speed.
  78303. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78304. *
  78305. * @method Phaser.Physics.P2.Body#thrustLeft
  78306. * @param {number} speed - The speed at which it should move to the left.
  78307. */
  78308. thrustLeft: function (speed) {
  78309. var magnitude = this.world.pxmi(-speed);
  78310. var angle = this.data.angle;
  78311. this.data.force[0] += magnitude * Math.cos(angle);
  78312. this.data.force[1] += magnitude * Math.sin(angle);
  78313. },
  78314. /**
  78315. * Applies a force to the Body that causes it to 'thrust' to the right, based on its current angle and the given speed.
  78316. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78317. *
  78318. * @method Phaser.Physics.P2.Body#thrustRight
  78319. * @param {number} speed - The speed at which it should move to the right.
  78320. */
  78321. thrustRight: function (speed) {
  78322. var magnitude = this.world.pxmi(-speed);
  78323. var angle = this.data.angle;
  78324. this.data.force[0] -= magnitude * Math.cos(angle);
  78325. this.data.force[1] -= magnitude * Math.sin(angle);
  78326. },
  78327. /**
  78328. * Applies a force to the Body that causes it to 'thrust' backwards (in reverse), based on its current angle and the given speed.
  78329. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78330. *
  78331. * @method Phaser.Physics.P2.Body#reverse
  78332. * @param {number} speed - The speed at which it should reverse.
  78333. */
  78334. reverse: function (speed) {
  78335. var magnitude = this.world.pxmi(-speed);
  78336. var angle = this.data.angle + Math.PI / 2;
  78337. this.data.force[0] -= magnitude * Math.cos(angle);
  78338. this.data.force[1] -= magnitude * Math.sin(angle);
  78339. },
  78340. /**
  78341. * If this Body is dynamic then this will move it to the left by setting its x velocity to the given speed.
  78342. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78343. *
  78344. * @method Phaser.Physics.P2.Body#moveLeft
  78345. * @param {number} speed - The speed at which it should move to the left, in pixels per second.
  78346. */
  78347. moveLeft: function (speed) {
  78348. this.data.velocity[0] = this.world.pxmi(-speed);
  78349. },
  78350. /**
  78351. * If this Body is dynamic then this will move it to the right by setting its x velocity to the given speed.
  78352. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78353. *
  78354. * @method Phaser.Physics.P2.Body#moveRight
  78355. * @param {number} speed - The speed at which it should move to the right, in pixels per second.
  78356. */
  78357. moveRight: function (speed) {
  78358. this.data.velocity[0] = this.world.pxmi(speed);
  78359. },
  78360. /**
  78361. * If this Body is dynamic then this will move it up by setting its y velocity to the given speed.
  78362. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78363. *
  78364. * @method Phaser.Physics.P2.Body#moveUp
  78365. * @param {number} speed - The speed at which it should move up, in pixels per second.
  78366. */
  78367. moveUp: function (speed) {
  78368. this.data.velocity[1] = this.world.pxmi(-speed);
  78369. },
  78370. /**
  78371. * If this Body is dynamic then this will move it down by setting its y velocity to the given speed.
  78372. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  78373. *
  78374. * @method Phaser.Physics.P2.Body#moveDown
  78375. * @param {number} speed - The speed at which it should move down, in pixels per second.
  78376. */
  78377. moveDown: function (speed) {
  78378. this.data.velocity[1] = this.world.pxmi(speed);
  78379. },
  78380. /**
  78381. * Internal method. This is called directly before the sprites are sent to the renderer and after the update function has finished.
  78382. *
  78383. * @method Phaser.Physics.P2.Body#preUpdate
  78384. * @protected
  78385. */
  78386. preUpdate: function () {
  78387. this.dirty = true;
  78388. if (this.removeNextStep)
  78389. {
  78390. this.removeFromWorld();
  78391. this.removeNextStep = false;
  78392. }
  78393. },
  78394. /**
  78395. * Internal method. This is called directly before the sprites are sent to the renderer and after the update function has finished.
  78396. *
  78397. * @method Phaser.Physics.P2.Body#postUpdate
  78398. * @protected
  78399. */
  78400. postUpdate: function () {
  78401. this.sprite.x = this.world.mpxi(this.data.position[0]) + this.offset.x;
  78402. this.sprite.y = this.world.mpxi(this.data.position[1]) + this.offset.y;
  78403. if (!this.fixedRotation)
  78404. {
  78405. this.sprite.rotation = this.data.angle;
  78406. }
  78407. if (this.debugBody)
  78408. {
  78409. this.debugBody.updateSpriteTransform();
  78410. }
  78411. this.dirty = false;
  78412. },
  78413. /**
  78414. * Resets the Body force, velocity (linear and angular) and rotation. Optionally resets damping and mass.
  78415. *
  78416. * @method Phaser.Physics.P2.Body#reset
  78417. * @param {number} x - The new x position of the Body.
  78418. * @param {number} y - The new x position of the Body.
  78419. * @param {boolean} [resetDamping=false] - Resets the linear and angular damping.
  78420. * @param {boolean} [resetMass=false] - Sets the Body mass back to 1.
  78421. */
  78422. reset: function (x, y, resetDamping, resetMass) {
  78423. if (resetDamping === undefined) { resetDamping = false; }
  78424. if (resetMass === undefined) { resetMass = false; }
  78425. this.setZeroForce();
  78426. this.setZeroVelocity();
  78427. this.setZeroRotation();
  78428. if (resetDamping)
  78429. {
  78430. this.setZeroDamping();
  78431. }
  78432. if (resetMass)
  78433. {
  78434. this.mass = 1;
  78435. }
  78436. this.x = x;
  78437. this.y = y;
  78438. },
  78439. /**
  78440. * Adds this physics body to the world.
  78441. *
  78442. * @method Phaser.Physics.P2.Body#addToWorld
  78443. */
  78444. addToWorld: function () {
  78445. if (this.game.physics.p2._toRemove)
  78446. {
  78447. for (var i = 0; i < this.game.physics.p2._toRemove.length; i++)
  78448. {
  78449. if (this.game.physics.p2._toRemove[i] === this)
  78450. {
  78451. this.game.physics.p2._toRemove.splice(i, 1);
  78452. }
  78453. }
  78454. }
  78455. if (this.data.world !== this.game.physics.p2.world)
  78456. {
  78457. this.game.physics.p2.addBody(this);
  78458. }
  78459. },
  78460. /**
  78461. * Removes this physics body from the world.
  78462. *
  78463. * @method Phaser.Physics.P2.Body#removeFromWorld
  78464. */
  78465. removeFromWorld: function () {
  78466. if (this.data.world === this.game.physics.p2.world)
  78467. {
  78468. this.game.physics.p2.removeBodyNextStep(this);
  78469. }
  78470. },
  78471. /**
  78472. * Destroys this Body and all references it holds to other objects.
  78473. *
  78474. * @method Phaser.Physics.P2.Body#destroy
  78475. */
  78476. destroy: function () {
  78477. this.removeFromWorld();
  78478. this.clearShapes();
  78479. this._bodyCallbacks = {};
  78480. this._bodyCallbackContext = {};
  78481. this._groupCallbacks = {};
  78482. this._groupCallbackContext = {};
  78483. if (this.debugBody)
  78484. {
  78485. this.debugBody.destroy(true, true);
  78486. }
  78487. this.debugBody = null;
  78488. if (this.sprite)
  78489. {
  78490. this.sprite.body = null;
  78491. this.sprite = null;
  78492. }
  78493. },
  78494. /**
  78495. * Removes all Shapes from this Body.
  78496. *
  78497. * @method Phaser.Physics.P2.Body#clearShapes
  78498. */
  78499. clearShapes: function () {
  78500. var i = this.data.shapes.length;
  78501. while (i--)
  78502. {
  78503. this.data.removeShape(this.data.shapes[i]);
  78504. }
  78505. this.shapeChanged();
  78506. },
  78507. /**
  78508. * Add a shape to the body. You can pass a local transform when adding a shape, so that the shape gets an offset and an angle relative to the body center of mass.
  78509. * Will automatically update the mass properties and bounding radius.
  78510. * If this Body had a previously set Collision Group you will need to re-apply it to the new Shape this creates.
  78511. *
  78512. * @method Phaser.Physics.P2.Body#addShape
  78513. * @param {p2.Shape} shape - The shape to add to the body.
  78514. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78515. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78516. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78517. * @return {p2.Shape} The shape that was added to the body.
  78518. */
  78519. addShape: function (shape, offsetX, offsetY, rotation) {
  78520. if (offsetX === undefined) { offsetX = 0; }
  78521. if (offsetY === undefined) { offsetY = 0; }
  78522. if (rotation === undefined) { rotation = 0; }
  78523. this.data.addShape(shape, [this.world.pxmi(offsetX), this.world.pxmi(offsetY)], rotation);
  78524. this.shapeChanged();
  78525. return shape;
  78526. },
  78527. /**
  78528. * Adds a Circle shape to this Body. You can control the offset from the center of the body and the rotation.
  78529. *
  78530. * @method Phaser.Physics.P2.Body#addCircle
  78531. * @param {number} radius - The radius of this circle (in pixels)
  78532. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78533. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78534. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78535. * @return {p2.Circle} The Circle shape that was added to the Body.
  78536. */
  78537. addCircle: function (radius, offsetX, offsetY, rotation) {
  78538. var shape = new p2.Circle({ radius: this.world.pxm(radius) });
  78539. return this.addShape(shape, offsetX, offsetY, rotation);
  78540. },
  78541. /**
  78542. * Adds a Rectangle shape to this Body. You can control the offset from the center of the body and the rotation.
  78543. *
  78544. * @method Phaser.Physics.P2.Body#addRectangle
  78545. * @param {number} width - The width of the rectangle in pixels.
  78546. * @param {number} height - The height of the rectangle in pixels.
  78547. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78548. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78549. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78550. * @return {p2.Box} The shape that was added to the Body.
  78551. */
  78552. addRectangle: function (width, height, offsetX, offsetY, rotation) {
  78553. var shape = new p2.Box({ width: this.world.pxm(width), height: this.world.pxm(height)});
  78554. return this.addShape(shape, offsetX, offsetY, rotation);
  78555. },
  78556. /**
  78557. * Adds a Plane shape to this Body. The plane is facing in the Y direction. You can control the offset from the center of the body and the rotation.
  78558. *
  78559. * @method Phaser.Physics.P2.Body#addPlane
  78560. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78561. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78562. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78563. * @return {p2.Plane} The Plane shape that was added to the Body.
  78564. */
  78565. addPlane: function (offsetX, offsetY, rotation) {
  78566. var shape = new p2.Plane();
  78567. return this.addShape(shape, offsetX, offsetY, rotation);
  78568. },
  78569. /**
  78570. * Adds a Particle shape to this Body. You can control the offset from the center of the body and the rotation.
  78571. *
  78572. * @method Phaser.Physics.P2.Body#addParticle
  78573. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78574. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78575. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78576. * @return {p2.Particle} The Particle shape that was added to the Body.
  78577. */
  78578. addParticle: function (offsetX, offsetY, rotation) {
  78579. var shape = new p2.Particle();
  78580. return this.addShape(shape, offsetX, offsetY, rotation);
  78581. },
  78582. /**
  78583. * Adds a Line shape to this Body.
  78584. * The line shape is along the x direction, and stretches from [-length/2, 0] to [length/2,0].
  78585. * You can control the offset from the center of the body and the rotation.
  78586. *
  78587. * @method Phaser.Physics.P2.Body#addLine
  78588. * @param {number} length - The length of this line (in pixels)
  78589. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78590. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78591. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78592. * @return {p2.Line} The Line shape that was added to the Body.
  78593. */
  78594. addLine: function (length, offsetX, offsetY, rotation) {
  78595. var shape = new p2.Line({ length: this.world.pxm(length)});
  78596. return this.addShape(shape, offsetX, offsetY, rotation);
  78597. },
  78598. /**
  78599. * Adds a Capsule shape to this Body.
  78600. * You can control the offset from the center of the body and the rotation.
  78601. *
  78602. * @method Phaser.Physics.P2.Body#addCapsule
  78603. * @param {number} length - The distance between the end points in pixels.
  78604. * @param {number} radius - Radius of the capsule in pixels.
  78605. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78606. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78607. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78608. * @return {p2.Capsule} The Capsule shape that was added to the Body.
  78609. */
  78610. addCapsule: function (length, radius, offsetX, offsetY, rotation) {
  78611. var shape = new p2.Capsule({ length: this.world.pxm(length), radius: this.world.pxm(radius) });
  78612. return this.addShape(shape, offsetX, offsetY, rotation);
  78613. },
  78614. /**
  78615. * Reads a polygon shape path, and assembles convex shapes from that and puts them at proper offset points. The shape must be simple and without holes.
  78616. * This function expects the x.y values to be given in pixels. If you want to provide them at p2 world scales then call Body.data.fromPolygon directly.
  78617. *
  78618. * @method Phaser.Physics.P2.Body#addPolygon
  78619. * @param {object} options - An object containing the build options:
  78620. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  78621. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  78622. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  78623. * @param {(number[]|...number)} points - An array of 2d vectors that form the convex or concave polygon.
  78624. * Either [[0,0], [0,1],...] or a flat array of numbers that will be interpreted as [x,y, x,y, ...]. In the first form **the array will mutate**.
  78625. * Or the arguments passed can be flat x,y values e.g. `setPolygon(options, x,y, x,y, x,y, ...)` where `x` and `y` are numbers.
  78626. * @return {boolean} True on success, else false.
  78627. */
  78628. addPolygon: function (options, points) {
  78629. options = options || {};
  78630. if (!Array.isArray(points))
  78631. {
  78632. points = Array.prototype.slice.call(arguments, 1);
  78633. }
  78634. var path = [];
  78635. // Did they pass in a single array of points?
  78636. if (points.length === 1 && Array.isArray(points[0]))
  78637. {
  78638. path = points[0].slice(0);
  78639. }
  78640. else if (Array.isArray(points[0]))
  78641. {
  78642. path = points.slice();
  78643. }
  78644. else if (typeof points[0] === 'number')
  78645. {
  78646. // We've a list of numbers
  78647. for (var i = 0, len = points.length; i < len; i += 2)
  78648. {
  78649. path.push([points[i], points[i + 1]]);
  78650. }
  78651. }
  78652. // top and tail
  78653. var idx = path.length - 1;
  78654. if (path[idx][0] === path[0][0] && path[idx][1] === path[0][1])
  78655. {
  78656. path.pop();
  78657. }
  78658. // Now process them into p2 values
  78659. for (var p = 0; p < path.length; p++)
  78660. {
  78661. path[p][0] = this.world.pxmi(path[p][0]);
  78662. path[p][1] = this.world.pxmi(path[p][1]);
  78663. }
  78664. var result = this.data.fromPolygon(path, options);
  78665. this.shapeChanged();
  78666. return result;
  78667. },
  78668. /**
  78669. * Remove a shape from the body. Will automatically update the mass properties and bounding radius.
  78670. *
  78671. * @method Phaser.Physics.P2.Body#removeShape
  78672. * @param {p2.Circle|p2.Rectangle|p2.Plane|p2.Line|p2.Particle} shape - The shape to remove from the body.
  78673. * @return {boolean} True if the shape was found and removed, else false.
  78674. */
  78675. removeShape: function (shape) {
  78676. var result = this.data.removeShape(shape);
  78677. this.shapeChanged();
  78678. return result;
  78679. },
  78680. /**
  78681. * Clears any previously set shapes. Then creates a new Circle shape and adds it to this Body.
  78682. * If this Body had a previously set Collision Group you will need to re-apply it to the new Shape this creates.
  78683. *
  78684. * @method Phaser.Physics.P2.Body#setCircle
  78685. * @param {number} radius - The radius of this circle (in pixels)
  78686. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78687. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78688. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78689. */
  78690. setCircle: function (radius, offsetX, offsetY, rotation) {
  78691. this.clearShapes();
  78692. return this.addCircle(radius, offsetX, offsetY, rotation);
  78693. },
  78694. /**
  78695. * Clears any previously set shapes. The creates a new Rectangle shape at the given size and offset, and adds it to this Body.
  78696. * If you wish to create a Rectangle to match the size of a Sprite or Image see Body.setRectangleFromSprite.
  78697. * If this Body had a previously set Collision Group you will need to re-apply it to the new Shape this creates.
  78698. *
  78699. * @method Phaser.Physics.P2.Body#setRectangle
  78700. * @param {number} [width=16] - The width of the rectangle in pixels.
  78701. * @param {number} [height=16] - The height of the rectangle in pixels.
  78702. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  78703. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  78704. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  78705. * @return {p2.Rectangle} The Rectangle shape that was added to the Body.
  78706. */
  78707. setRectangle: function (width, height, offsetX, offsetY, rotation) {
  78708. if (width === undefined) { width = 16; }
  78709. if (height === undefined) { height = 16; }
  78710. this.clearShapes();
  78711. return this.addRectangle(width, height, offsetX, offsetY, rotation);
  78712. },
  78713. /**
  78714. * Clears any previously set shapes.
  78715. * Then creates a Rectangle shape sized to match the dimensions and orientation of the Sprite given.
  78716. * If no Sprite is given it defaults to using the parent of this Body.
  78717. * If this Body had a previously set Collision Group you will need to re-apply it to the new Shape this creates.
  78718. *
  78719. * @method Phaser.Physics.P2.Body#setRectangleFromSprite
  78720. * @param {Phaser.Sprite|Phaser.Image} [sprite] - The Sprite on which the Rectangle will get its dimensions.
  78721. * @return {p2.Rectangle} The Rectangle shape that was added to the Body.
  78722. */
  78723. setRectangleFromSprite: function (sprite) {
  78724. if (sprite === undefined) { sprite = this.sprite; }
  78725. this.clearShapes();
  78726. return this.addRectangle(sprite.width, sprite.height, 0, 0, sprite.rotation);
  78727. },
  78728. /**
  78729. * Adds the given Material to all Shapes that belong to this Body.
  78730. * If you only wish to apply it to a specific Shape in this Body then provide that as the 2nd parameter.
  78731. *
  78732. * @method Phaser.Physics.P2.Body#setMaterial
  78733. * @param {Phaser.Physics.P2.Material} material - The Material that will be applied.
  78734. * @param {p2.Shape} [shape] - An optional Shape. If not provided the Material will be added to all Shapes in this Body.
  78735. */
  78736. setMaterial: function (material, shape) {
  78737. if (shape === undefined)
  78738. {
  78739. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  78740. {
  78741. this.data.shapes[i].material = material;
  78742. }
  78743. }
  78744. else
  78745. {
  78746. shape.material = material;
  78747. }
  78748. },
  78749. /**
  78750. * Updates the debug draw if any body shapes change.
  78751. *
  78752. * @method Phaser.Physics.P2.Body#shapeChanged
  78753. */
  78754. shapeChanged: function() {
  78755. if (this.debugBody)
  78756. {
  78757. this.debugBody.draw();
  78758. }
  78759. },
  78760. /**
  78761. * Reads the shape data from a physics data file stored in the Game.Cache and adds it as a polygon to this Body.
  78762. * The shape data format is based on the output of the
  78763. * {@link https://github.com/photonstorm/phaser/tree/master/resources/PhysicsEditor%20Exporter|custom phaser exporter} for
  78764. * {@link https://www.codeandweb.com/physicseditor|PhysicsEditor}
  78765. *
  78766. * @method Phaser.Physics.P2.Body#addPhaserPolygon
  78767. * @param {string} key - The key of the Physics Data file as stored in Game.Cache.
  78768. * @param {string} object - The key of the object within the Physics data file that you wish to load the shape data from.
  78769. * @returns {Array} A list of created fixtures to be used with Phaser.Physics.P2.FixtureList
  78770. */
  78771. addPhaserPolygon: function (key, object) {
  78772. var data = this.game.cache.getPhysicsData(key, object);
  78773. var createdFixtures = [];
  78774. // Cycle through the fixtures
  78775. for (var i = 0; i < data.length; i++)
  78776. {
  78777. var fixtureData = data[i];
  78778. var shapesOfFixture = this.addFixture(fixtureData);
  78779. // Always add to a group
  78780. createdFixtures[fixtureData.filter.group] = createdFixtures[fixtureData.filter.group] || [];
  78781. createdFixtures[fixtureData.filter.group] = createdFixtures[fixtureData.filter.group].concat(shapesOfFixture);
  78782. // if (unique) fixture key is provided
  78783. if (fixtureData.fixtureKey)
  78784. {
  78785. createdFixtures[fixtureData.fixtureKey] = shapesOfFixture;
  78786. }
  78787. }
  78788. this.data.aabbNeedsUpdate = true;
  78789. this.shapeChanged();
  78790. return createdFixtures;
  78791. },
  78792. /**
  78793. * Add a polygon fixture. This is used during #loadPolygon.
  78794. *
  78795. * @method Phaser.Physics.P2.Body#addFixture
  78796. * @param {string} fixtureData - The data for the fixture. It contains: isSensor, filter (collision) and the actual polygon shapes.
  78797. * @return {array} An array containing the generated shapes for the given polygon.
  78798. */
  78799. addFixture: function (fixtureData) {
  78800. var generatedShapes = [];
  78801. if (fixtureData.circle)
  78802. {
  78803. var shape = new p2.Circle({ radius: this.world.pxm(fixtureData.circle.radius) });
  78804. shape.collisionGroup = fixtureData.filter.categoryBits;
  78805. shape.collisionMask = fixtureData.filter.maskBits;
  78806. shape.sensor = fixtureData.isSensor;
  78807. var offset = p2.vec2.create();
  78808. offset[0] = this.world.pxmi(fixtureData.circle.position[0] - this.sprite.width/2);
  78809. offset[1] = this.world.pxmi(fixtureData.circle.position[1] - this.sprite.height/2);
  78810. this.data.addShape(shape, offset);
  78811. generatedShapes.push(shape);
  78812. }
  78813. else
  78814. {
  78815. var polygons = fixtureData.polygons;
  78816. var cm = p2.vec2.create();
  78817. for (var i = 0; i < polygons.length; i++)
  78818. {
  78819. var shapes = polygons[i];
  78820. var vertices = [];
  78821. for (var s = 0; s < shapes.length; s += 2)
  78822. {
  78823. vertices.push([ this.world.pxmi(shapes[s]), this.world.pxmi(shapes[s + 1]) ]);
  78824. }
  78825. var shape = new p2.Convex({ vertices: vertices });
  78826. // Move all vertices so its center of mass is in the local center of the convex
  78827. for (var j = 0; j !== shape.vertices.length; j++)
  78828. {
  78829. var v = shape.vertices[j];
  78830. p2.vec2.sub(v, v, shape.centerOfMass);
  78831. }
  78832. p2.vec2.scale(cm, shape.centerOfMass, 1);
  78833. cm[0] -= this.world.pxmi(this.sprite.width / 2);
  78834. cm[1] -= this.world.pxmi(this.sprite.height / 2);
  78835. shape.updateTriangles();
  78836. shape.updateCenterOfMass();
  78837. shape.updateBoundingRadius();
  78838. shape.collisionGroup = fixtureData.filter.categoryBits;
  78839. shape.collisionMask = fixtureData.filter.maskBits;
  78840. shape.sensor = fixtureData.isSensor;
  78841. this.data.addShape(shape, cm);
  78842. generatedShapes.push(shape);
  78843. }
  78844. }
  78845. return generatedShapes;
  78846. },
  78847. /**
  78848. * Reads the shape data from a physics data file stored in the Game.Cache and adds it as a polygon to this Body.
  78849. *
  78850. * As well as reading the data from the Cache you can also pass `null` as the first argument and a
  78851. * physics data object as the second. When doing this you must ensure the structure of the object is correct in advance.
  78852. *
  78853. * For more details see the format of the Lime / Corona Physics Editor export.
  78854. *
  78855. * @method Phaser.Physics.P2.Body#loadPolygon
  78856. * @param {string} key - The key of the Physics Data file as stored in Game.Cache. Alternatively set to `null` and pass the
  78857. * data as the 2nd argument.
  78858. * @param {string|object} object - The key of the object within the Physics data file that you wish to load the shape data from,
  78859. * or if key is null pass the actual physics data object itself as this parameter.
  78860. * @param {number} [scale=1] - Optionally resize the loaded polygon.
  78861. * @return {boolean} True on success, else false.
  78862. */
  78863. loadPolygon: function (key, object, scale) {
  78864. if (key === null)
  78865. {
  78866. var data = object;
  78867. }
  78868. else
  78869. {
  78870. var data = this.game.cache.getPhysicsData(key, object);
  78871. }
  78872. if (typeof scale !== "number")
  78873. {
  78874. scale = 1;
  78875. }
  78876. // We've multiple Convex shapes, they should be CCW automatically
  78877. var cm = p2.vec2.create();
  78878. for (var i = 0; i < data.length; i++)
  78879. {
  78880. var vertices = [];
  78881. for (var s = 0; s < data[i].shape.length; s += 2)
  78882. {
  78883. vertices.push([
  78884. this.world.pxmi(data[i].shape[s] * scale),
  78885. this.world.pxmi(data[i].shape[s + 1] * scale)
  78886. ]);
  78887. }
  78888. var c = new p2.Convex({ vertices: vertices });
  78889. // Move all vertices so its center of mass is in the local center of the convex
  78890. for (var j = 0; j !== c.vertices.length; j++)
  78891. {
  78892. var v = c.vertices[j];
  78893. p2.vec2.sub(v, v, c.centerOfMass);
  78894. }
  78895. p2.vec2.scale(cm, c.centerOfMass, 1);
  78896. cm[0] -= this.world.pxmi(this.sprite.width / 2);
  78897. cm[1] -= this.world.pxmi(this.sprite.height / 2);
  78898. c.updateTriangles();
  78899. c.updateCenterOfMass();
  78900. c.updateBoundingRadius();
  78901. this.data.addShape(c, cm);
  78902. }
  78903. this.data.aabbNeedsUpdate = true;
  78904. this.shapeChanged();
  78905. return true;
  78906. }
  78907. };
  78908. Phaser.Physics.P2.Body.prototype.constructor = Phaser.Physics.P2.Body;
  78909. /**
  78910. * Dynamic body. Dynamic bodies body can move and respond to collisions and forces.
  78911. * @property DYNAMIC
  78912. * @type {Number}
  78913. * @static
  78914. */
  78915. Phaser.Physics.P2.Body.DYNAMIC = 1;
  78916. /**
  78917. * Static body. Static bodies do not move, and they do not respond to forces or collision.
  78918. * @property STATIC
  78919. * @type {Number}
  78920. * @static
  78921. */
  78922. Phaser.Physics.P2.Body.STATIC = 2;
  78923. /**
  78924. * Kinematic body. Kinematic bodies only moves according to its .velocity, and does not respond to collisions or force.
  78925. * @property KINEMATIC
  78926. * @type {Number}
  78927. * @static
  78928. */
  78929. Phaser.Physics.P2.Body.KINEMATIC = 4;
  78930. /**
  78931. * @name Phaser.Physics.P2.Body#static
  78932. * @property {boolean} static - Returns true if the Body is static. Setting Body.static to 'false' will make it dynamic.
  78933. */
  78934. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "static", {
  78935. get: function () {
  78936. return (this.data.type === Phaser.Physics.P2.Body.STATIC);
  78937. },
  78938. set: function (value) {
  78939. if (value && this.data.type !== Phaser.Physics.P2.Body.STATIC)
  78940. {
  78941. this.data.type = Phaser.Physics.P2.Body.STATIC;
  78942. this.mass = 0;
  78943. }
  78944. else if (!value && this.data.type === Phaser.Physics.P2.Body.STATIC)
  78945. {
  78946. this.data.type = Phaser.Physics.P2.Body.DYNAMIC;
  78947. this.mass = 1;
  78948. }
  78949. }
  78950. });
  78951. /**
  78952. * @name Phaser.Physics.P2.Body#dynamic
  78953. * @property {boolean} dynamic - Returns true if the Body is dynamic. Setting Body.dynamic to 'false' will make it static.
  78954. */
  78955. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "dynamic", {
  78956. get: function () {
  78957. return (this.data.type === Phaser.Physics.P2.Body.DYNAMIC);
  78958. },
  78959. set: function (value) {
  78960. if (value && this.data.type !== Phaser.Physics.P2.Body.DYNAMIC)
  78961. {
  78962. this.data.type = Phaser.Physics.P2.Body.DYNAMIC;
  78963. this.mass = 1;
  78964. }
  78965. else if (!value && this.data.type === Phaser.Physics.P2.Body.DYNAMIC)
  78966. {
  78967. this.data.type = Phaser.Physics.P2.Body.STATIC;
  78968. this.mass = 0;
  78969. }
  78970. }
  78971. });
  78972. /**
  78973. * @name Phaser.Physics.P2.Body#kinematic
  78974. * @property {boolean} kinematic - Returns true if the Body is kinematic. Setting Body.kinematic to 'false' will make it static.
  78975. */
  78976. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "kinematic", {
  78977. get: function () {
  78978. return (this.data.type === Phaser.Physics.P2.Body.KINEMATIC);
  78979. },
  78980. set: function (value) {
  78981. if (value && this.data.type !== Phaser.Physics.P2.Body.KINEMATIC)
  78982. {
  78983. this.data.type = Phaser.Physics.P2.Body.KINEMATIC;
  78984. this.mass = 4;
  78985. }
  78986. else if (!value && this.data.type === Phaser.Physics.P2.Body.KINEMATIC)
  78987. {
  78988. this.data.type = Phaser.Physics.P2.Body.STATIC;
  78989. this.mass = 0;
  78990. }
  78991. }
  78992. });
  78993. /**
  78994. * @name Phaser.Physics.P2.Body#allowSleep
  78995. * @property {boolean} allowSleep -
  78996. */
  78997. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "allowSleep", {
  78998. get: function () {
  78999. return this.data.allowSleep;
  79000. },
  79001. set: function (value) {
  79002. if (value !== this.data.allowSleep)
  79003. {
  79004. this.data.allowSleep = value;
  79005. }
  79006. }
  79007. });
  79008. /**
  79009. * The angle of the Body in degrees from its original orientation. Values from 0 to 180 represent clockwise rotation; values from 0 to -180 represent counterclockwise rotation.
  79010. * Values outside this range are added to or subtracted from 360 to obtain a value within the range. For example, the statement Body.angle = 450 is the same as Body.angle = 90.
  79011. * If you wish to work in radians instead of degrees use the property Body.rotation instead. Working in radians is faster as it doesn't have to convert values.
  79012. *
  79013. * @name Phaser.Physics.P2.Body#angle
  79014. * @property {number} angle - The angle of this Body in degrees.
  79015. */
  79016. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angle", {
  79017. get: function() {
  79018. return Phaser.Math.wrapAngle(Phaser.Math.radToDeg(this.data.angle));
  79019. },
  79020. set: function(value) {
  79021. this.data.angle = Phaser.Math.degToRad(Phaser.Math.wrapAngle(value));
  79022. }
  79023. });
  79024. /**
  79025. * Damping is specified as a value between 0 and 1, which is the proportion of velocity lost per second.
  79026. * @name Phaser.Physics.P2.Body#angularDamping
  79027. * @property {number} angularDamping - The angular damping acting acting on the body.
  79028. */
  79029. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angularDamping", {
  79030. get: function () {
  79031. return this.data.angularDamping;
  79032. },
  79033. set: function (value) {
  79034. this.data.angularDamping = value;
  79035. }
  79036. });
  79037. /**
  79038. * @name Phaser.Physics.P2.Body#angularForce
  79039. * @property {number} angularForce - The angular force acting on the body.
  79040. */
  79041. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angularForce", {
  79042. get: function () {
  79043. return this.data.angularForce;
  79044. },
  79045. set: function (value) {
  79046. this.data.angularForce = value;
  79047. }
  79048. });
  79049. /**
  79050. * @name Phaser.Physics.P2.Body#angularVelocity
  79051. * @property {number} angularVelocity - The angular velocity of the body.
  79052. */
  79053. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angularVelocity", {
  79054. get: function () {
  79055. return this.data.angularVelocity;
  79056. },
  79057. set: function (value) {
  79058. this.data.angularVelocity = value;
  79059. }
  79060. });
  79061. /**
  79062. * Damping is specified as a value between 0 and 1, which is the proportion of velocity lost per second.
  79063. * @name Phaser.Physics.P2.Body#damping
  79064. * @property {number} damping - The linear damping acting on the body in the velocity direction.
  79065. */
  79066. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "damping", {
  79067. get: function () {
  79068. return this.data.damping;
  79069. },
  79070. set: function (value) {
  79071. this.data.damping = value;
  79072. }
  79073. });
  79074. /**
  79075. * @name Phaser.Physics.P2.Body#fixedRotation
  79076. * @property {boolean} fixedRotation -
  79077. */
  79078. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "fixedRotation", {
  79079. get: function () {
  79080. return this.data.fixedRotation;
  79081. },
  79082. set: function (value) {
  79083. if (value !== this.data.fixedRotation)
  79084. {
  79085. this.data.fixedRotation = value;
  79086. }
  79087. }
  79088. });
  79089. /**
  79090. * @name Phaser.Physics.P2.Body#inertia
  79091. * @property {number} inertia - The inertia of the body around the Z axis..
  79092. */
  79093. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "inertia", {
  79094. get: function () {
  79095. return this.data.inertia;
  79096. },
  79097. set: function (value) {
  79098. this.data.inertia = value;
  79099. }
  79100. });
  79101. /**
  79102. * @name Phaser.Physics.P2.Body#mass
  79103. * @property {number} mass - The mass of the body.
  79104. */
  79105. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "mass", {
  79106. get: function () {
  79107. return this.data.mass;
  79108. },
  79109. set: function (value) {
  79110. if (value !== this.data.mass)
  79111. {
  79112. this.data.mass = value;
  79113. this.data.updateMassProperties();
  79114. }
  79115. }
  79116. });
  79117. /**
  79118. * @name Phaser.Physics.P2.Body#motionState
  79119. * @property {number} motionState - The type of motion this body has. Should be one of: Body.STATIC (the body does not move), Body.DYNAMIC (body can move and respond to collisions) and Body.KINEMATIC (only moves according to its .velocity).
  79120. */
  79121. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "motionState", {
  79122. get: function () {
  79123. return this.data.type;
  79124. },
  79125. set: function (value) {
  79126. if (value !== this.data.type)
  79127. {
  79128. this.data.type = value;
  79129. }
  79130. }
  79131. });
  79132. /**
  79133. * The angle of the Body in radians.
  79134. * If you wish to work in degrees instead of radians use the Body.angle property instead. Working in radians is faster as it doesn't have to convert values.
  79135. *
  79136. * @name Phaser.Physics.P2.Body#rotation
  79137. * @property {number} rotation - The angle of this Body in radians.
  79138. */
  79139. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "rotation", {
  79140. get: function() {
  79141. return this.data.angle;
  79142. },
  79143. set: function(value) {
  79144. this.data.angle = value;
  79145. }
  79146. });
  79147. /**
  79148. * @name Phaser.Physics.P2.Body#sleepSpeedLimit
  79149. * @property {number} sleepSpeedLimit - .
  79150. */
  79151. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "sleepSpeedLimit", {
  79152. get: function () {
  79153. return this.data.sleepSpeedLimit;
  79154. },
  79155. set: function (value) {
  79156. this.data.sleepSpeedLimit = value;
  79157. }
  79158. });
  79159. /**
  79160. * @name Phaser.Physics.P2.Body#x
  79161. * @property {number} x - The x coordinate of this Body.
  79162. */
  79163. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "x", {
  79164. get: function () {
  79165. return this.world.mpxi(this.data.position[0]);
  79166. },
  79167. set: function (value) {
  79168. this.data.position[0] = this.world.pxmi(value);
  79169. }
  79170. });
  79171. /**
  79172. * @name Phaser.Physics.P2.Body#y
  79173. * @property {number} y - The y coordinate of this Body.
  79174. */
  79175. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "y", {
  79176. get: function () {
  79177. return this.world.mpxi(this.data.position[1]);
  79178. },
  79179. set: function (value) {
  79180. this.data.position[1] = this.world.pxmi(value);
  79181. }
  79182. });
  79183. /**
  79184. * @name Phaser.Physics.P2.Body#id
  79185. * @property {number} id - The Body ID. Each Body that has been added to the World has a unique ID.
  79186. * @readonly
  79187. */
  79188. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "id", {
  79189. get: function () {
  79190. return this.data.id;
  79191. }
  79192. });
  79193. /**
  79194. * @name Phaser.Physics.P2.Body#debug
  79195. * @property {boolean} debug - Enable or disable debug drawing of this body
  79196. */
  79197. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "debug", {
  79198. get: function () {
  79199. return (this.debugBody !== null);
  79200. },
  79201. set: function (value) {
  79202. if (value && !this.debugBody)
  79203. {
  79204. // This will be added to the global space
  79205. this.debugBody = new Phaser.Physics.P2.BodyDebug(this.game, this.data);
  79206. }
  79207. else if (!value && this.debugBody)
  79208. {
  79209. this.debugBody.destroy();
  79210. this.debugBody = null;
  79211. }
  79212. }
  79213. });
  79214. /**
  79215. * A Body can be set to collide against the World bounds automatically if this is set to true. Otherwise it will leave the World.
  79216. * Note that this only applies if your World has bounds! The response to the collision should be managed via CollisionMaterials.
  79217. * Also note that when you set this it will only affect Body shapes that already exist. If you then add further shapes to your Body
  79218. * after setting this it will *not* proactively set them to collide with the bounds.
  79219. *
  79220. * @name Phaser.Physics.P2.Body#collideWorldBounds
  79221. * @property {boolean} collideWorldBounds - Should the Body collide with the World bounds?
  79222. * @default true
  79223. */
  79224. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "collideWorldBounds", {
  79225. get: function () {
  79226. return this._collideWorldBounds;
  79227. },
  79228. set: function (value) {
  79229. if (value && !this._collideWorldBounds)
  79230. {
  79231. this._collideWorldBounds = true;
  79232. this.updateCollisionMask();
  79233. }
  79234. else if (!value && this._collideWorldBounds)
  79235. {
  79236. this._collideWorldBounds = false;
  79237. this.updateCollisionMask();
  79238. }
  79239. }
  79240. });
  79241. /**
  79242. * @author George https://github.com/georgiee
  79243. * @author Richard Davey <rich@photonstorm.com>
  79244. * @copyright 2016 Photon Storm Ltd.
  79245. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79246. */
  79247. /**
  79248. * Draws a P2 Body to a Graphics instance for visual debugging.
  79249. * Needless to say, for every body you enable debug drawing on, you are adding processor and graphical overhead.
  79250. * So use sparingly and rarely (if ever) in production code.
  79251. *
  79252. * Also be aware that the Debug body is only updated when the Sprite it is connected to changes position. If you
  79253. * manipulate the sprite in any other way (such as moving it to another Group or bringToTop, etc) then you will
  79254. * need to manually adjust its BodyDebug as well.
  79255. *
  79256. * @class Phaser.Physics.P2.BodyDebug
  79257. * @constructor
  79258. * @extends Phaser.Group
  79259. * @param {Phaser.Game} game - Game reference to the currently running game.
  79260. * @param {Phaser.Physics.P2.Body} body - The P2 Body to display debug data for.
  79261. * @param {object} settings - Settings object.
  79262. */
  79263. Phaser.Physics.P2.BodyDebug = function(game, body, settings) {
  79264. Phaser.Group.call(this, game);
  79265. /**
  79266. * @property {object} defaultSettings - Default debug settings.
  79267. * @private
  79268. */
  79269. var defaultSettings = {
  79270. pixelsPerLengthUnit: game.physics.p2.mpx(1),
  79271. debugPolygons: false,
  79272. lineWidth: 1,
  79273. alpha: 0.5
  79274. };
  79275. this.settings = Phaser.Utils.extend(defaultSettings, settings);
  79276. /**
  79277. * @property {number} ppu - Pixels per Length Unit.
  79278. */
  79279. this.ppu = this.settings.pixelsPerLengthUnit;
  79280. this.ppu = -1 * this.ppu;
  79281. /**
  79282. * @property {Phaser.Physics.P2.Body} body - The P2 Body to display debug data for.
  79283. */
  79284. this.body = body;
  79285. /**
  79286. * @property {Phaser.Graphics} canvas - The canvas to render the debug info to.
  79287. */
  79288. this.canvas = new Phaser.Graphics(game);
  79289. this.canvas.alpha = this.settings.alpha;
  79290. this.add(this.canvas);
  79291. this.draw();
  79292. this.updateSpriteTransform();
  79293. };
  79294. Phaser.Physics.P2.BodyDebug.prototype = Object.create(Phaser.Group.prototype);
  79295. Phaser.Physics.P2.BodyDebug.prototype.constructor = Phaser.Physics.P2.BodyDebug;
  79296. Phaser.Utils.extend(Phaser.Physics.P2.BodyDebug.prototype, {
  79297. /**
  79298. * Core update.
  79299. *
  79300. * @method Phaser.Physics.P2.BodyDebug#updateSpriteTransform
  79301. */
  79302. updateSpriteTransform: function() {
  79303. this.position.x = this.body.position[0] * this.ppu;
  79304. this.position.y = this.body.position[1] * this.ppu;
  79305. this.rotation = this.body.angle;
  79306. },
  79307. /**
  79308. * Draws the P2 shapes to the Graphics object.
  79309. *
  79310. * @method Phaser.Physics.P2.BodyDebug#draw
  79311. */
  79312. draw: function() {
  79313. var angle, child, color, i, j, lineColor, lw, obj, offset, sprite, v, verts, vrot, _j, _ref1;
  79314. obj = this.body;
  79315. sprite = this.canvas;
  79316. sprite.clear();
  79317. color = parseInt(this.randomPastelHex(), 16);
  79318. lineColor = 0xff0000;
  79319. lw = this.lineWidth;
  79320. if (obj instanceof p2.Body && obj.shapes.length)
  79321. {
  79322. var l = obj.shapes.length;
  79323. i = 0;
  79324. while (i !== l)
  79325. {
  79326. child = obj.shapes[i];
  79327. offset = child.position || 0;
  79328. angle = child.angle || 0;
  79329. if (child instanceof p2.Circle)
  79330. {
  79331. this.drawCircle(sprite, offset[0] * this.ppu, offset[1] * this.ppu, angle, child.radius * this.ppu, color, lw);
  79332. }
  79333. else if (child instanceof p2.Capsule)
  79334. {
  79335. this.drawCapsule(sprite, offset[0] * this.ppu, offset[1] * this.ppu, angle, child.length * this.ppu, child.radius * this.ppu, lineColor, color, lw);
  79336. }
  79337. else if (child instanceof p2.Plane)
  79338. {
  79339. this.drawPlane(sprite, offset[0] * this.ppu, -offset[1] * this.ppu, color, lineColor, lw * 5, lw * 10, lw * 10, this.ppu * 100, angle);
  79340. }
  79341. else if (child instanceof p2.Line)
  79342. {
  79343. this.drawLine(sprite, child.length * this.ppu, lineColor, lw);
  79344. }
  79345. else if (child instanceof p2.Box)
  79346. {
  79347. this.drawRectangle(sprite, offset[0] * this.ppu, offset[1] * this.ppu, angle, child.width * this.ppu, child.height * this.ppu, lineColor, color, lw);
  79348. }
  79349. else if (child instanceof p2.Convex)
  79350. {
  79351. verts = [];
  79352. vrot = p2.vec2.create();
  79353. for (j = _j = 0, _ref1 = child.vertices.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; j = 0 <= _ref1 ? ++_j : --_j)
  79354. {
  79355. v = child.vertices[j];
  79356. p2.vec2.rotate(vrot, v, angle);
  79357. verts.push([(vrot[0] + offset[0]) * this.ppu, -(vrot[1] + offset[1]) * this.ppu]);
  79358. }
  79359. this.drawConvex(sprite, verts, child.triangles, lineColor, color, lw, this.settings.debugPolygons, [offset[0] * this.ppu, -offset[1] * this.ppu]);
  79360. }
  79361. i++;
  79362. }
  79363. }
  79364. },
  79365. /**
  79366. * Draws a p2.Box to the Graphics object.
  79367. *
  79368. * @method Phaser.Physics.P2.BodyDebug#drawRectangle
  79369. * @private
  79370. */
  79371. drawRectangle: function(g, x, y, angle, w, h, color, fillColor, lineWidth) {
  79372. if (lineWidth === undefined) { lineWidth = 1; }
  79373. if (color === undefined) { color = 0x000000; }
  79374. g.lineStyle(lineWidth, color, 1);
  79375. g.beginFill(fillColor);
  79376. g.drawRect(x - w / 2, y - h / 2, w, h);
  79377. },
  79378. /**
  79379. * Draws a p2.Circle to the Graphics object.
  79380. *
  79381. * @method Phaser.Physics.P2.BodyDebug#drawCircle
  79382. * @private
  79383. */
  79384. drawCircle: function(g, x, y, angle, radius, color, lineWidth) {
  79385. if (lineWidth === undefined) { lineWidth = 1; }
  79386. if (color === undefined) { color = 0xffffff; }
  79387. g.lineStyle(lineWidth, 0x000000, 1);
  79388. g.beginFill(color, 1.0);
  79389. g.drawCircle(x, y, -radius*2);
  79390. g.endFill();
  79391. g.moveTo(x, y);
  79392. g.lineTo(x + radius * Math.cos(-angle), y + radius * Math.sin(-angle));
  79393. },
  79394. /**
  79395. * Draws a p2.Line to the Graphics object.
  79396. *
  79397. * @method Phaser.Physics.P2.BodyDebug#drawLine
  79398. * @private
  79399. */
  79400. drawLine: function(g, len, color, lineWidth) {
  79401. if (lineWidth === undefined) { lineWidth = 1; }
  79402. if (color === undefined) { color = 0x000000; }
  79403. g.lineStyle(lineWidth * 5, color, 1);
  79404. g.moveTo(-len / 2, 0);
  79405. g.lineTo(len / 2, 0);
  79406. },
  79407. /**
  79408. * Draws a p2.Convex to the Graphics object.
  79409. *
  79410. * @method Phaser.Physics.P2.BodyDebug#drawConvex
  79411. * @private
  79412. */
  79413. drawConvex: function(g, verts, triangles, color, fillColor, lineWidth, debug, offset) {
  79414. var colors, i, v, v0, v1, x, x0, x1, y, y0, y1;
  79415. if (lineWidth === undefined) { lineWidth = 1; }
  79416. if (color === undefined) { color = 0x000000; }
  79417. if (!debug)
  79418. {
  79419. g.lineStyle(lineWidth, color, 1);
  79420. g.beginFill(fillColor);
  79421. i = 0;
  79422. while (i !== verts.length)
  79423. {
  79424. v = verts[i];
  79425. x = v[0];
  79426. y = v[1];
  79427. if (i === 0)
  79428. {
  79429. g.moveTo(x, -y);
  79430. }
  79431. else
  79432. {
  79433. g.lineTo(x, -y);
  79434. }
  79435. i++;
  79436. }
  79437. g.endFill();
  79438. if (verts.length > 2)
  79439. {
  79440. g.moveTo(verts[verts.length - 1][0], -verts[verts.length - 1][1]);
  79441. return g.lineTo(verts[0][0], -verts[0][1]);
  79442. }
  79443. }
  79444. else
  79445. {
  79446. colors = [0xff0000, 0x00ff00, 0x0000ff];
  79447. i = 0;
  79448. while (i !== verts.length + 1)
  79449. {
  79450. v0 = verts[i % verts.length];
  79451. v1 = verts[(i + 1) % verts.length];
  79452. x0 = v0[0];
  79453. y0 = v0[1];
  79454. x1 = v1[0];
  79455. y1 = v1[1];
  79456. g.lineStyle(lineWidth, colors[i % colors.length], 1);
  79457. g.moveTo(x0, -y0);
  79458. g.lineTo(x1, -y1);
  79459. g.drawCircle(x0, -y0, lineWidth * 2);
  79460. i++;
  79461. }
  79462. g.lineStyle(lineWidth, 0x000000, 1);
  79463. return g.drawCircle(offset[0], offset[1], lineWidth * 2);
  79464. }
  79465. },
  79466. /**
  79467. * Draws a p2.Path to the Graphics object.
  79468. *
  79469. * @method Phaser.Physics.P2.BodyDebug#drawPath
  79470. * @private
  79471. */
  79472. drawPath: function(g, path, color, fillColor, lineWidth) {
  79473. var area, i, lastx, lasty, p1x, p1y, p2x, p2y, p3x, p3y, v, x, y;
  79474. if (lineWidth === undefined) { lineWidth = 1; }
  79475. if (color === undefined) { color = 0x000000; }
  79476. g.lineStyle(lineWidth, color, 1);
  79477. if (typeof fillColor === "number")
  79478. {
  79479. g.beginFill(fillColor);
  79480. }
  79481. lastx = null;
  79482. lasty = null;
  79483. i = 0;
  79484. while (i < path.length)
  79485. {
  79486. v = path[i];
  79487. x = v[0];
  79488. y = v[1];
  79489. if (x !== lastx || y !== lasty)
  79490. {
  79491. if (i === 0)
  79492. {
  79493. g.moveTo(x, y);
  79494. }
  79495. else
  79496. {
  79497. p1x = lastx;
  79498. p1y = lasty;
  79499. p2x = x;
  79500. p2y = y;
  79501. p3x = path[(i + 1) % path.length][0];
  79502. p3y = path[(i + 1) % path.length][1];
  79503. area = ((p2x - p1x) * (p3y - p1y)) - ((p3x - p1x) * (p2y - p1y));
  79504. if (area !== 0)
  79505. {
  79506. g.lineTo(x, y);
  79507. }
  79508. }
  79509. lastx = x;
  79510. lasty = y;
  79511. }
  79512. i++;
  79513. }
  79514. if (typeof fillColor === "number")
  79515. {
  79516. g.endFill();
  79517. }
  79518. if (path.length > 2 && typeof fillColor === "number")
  79519. {
  79520. g.moveTo(path[path.length - 1][0], path[path.length - 1][1]);
  79521. g.lineTo(path[0][0], path[0][1]);
  79522. }
  79523. },
  79524. /**
  79525. * Draws a p2.Plane to the Graphics object.
  79526. *
  79527. * @method Phaser.Physics.P2.BodyDebug#drawPlane
  79528. * @private
  79529. */
  79530. drawPlane: function(g, x0, x1, color, lineColor, lineWidth, diagMargin, diagSize, maxLength, angle) {
  79531. var max, xd, yd;
  79532. if (lineWidth === undefined) { lineWidth = 1; }
  79533. if (color === undefined) { color = 0xffffff; }
  79534. g.lineStyle(lineWidth, lineColor, 11);
  79535. g.beginFill(color);
  79536. max = maxLength;
  79537. g.moveTo(x0, -x1);
  79538. xd = x0 + Math.cos(angle) * this.game.width;
  79539. yd = x1 + Math.sin(angle) * this.game.height;
  79540. g.lineTo(xd, -yd);
  79541. g.moveTo(x0, -x1);
  79542. xd = x0 + Math.cos(angle) * -this.game.width;
  79543. yd = x1 + Math.sin(angle) * -this.game.height;
  79544. g.lineTo(xd, -yd);
  79545. },
  79546. /**
  79547. * Draws a p2.Capsule to the Graphics object.
  79548. *
  79549. * @method Phaser.Physics.P2.BodyDebug#drawCapsule
  79550. * @private
  79551. */
  79552. drawCapsule: function(g, x, y, angle, len, radius, color, fillColor, lineWidth) {
  79553. if (lineWidth === undefined) { lineWidth = 1; }
  79554. if (color === undefined) { color = 0x000000; }
  79555. g.lineStyle(lineWidth, color, 1);
  79556. // Draw circles at ends
  79557. var c = Math.cos(angle);
  79558. var s = Math.sin(angle);
  79559. g.beginFill(fillColor, 1);
  79560. g.drawCircle(-len/2*c + x, -len/2*s + y, -radius * 2);
  79561. g.drawCircle( len/2*c + x, len/2*s + y, -radius * 2);
  79562. g.endFill();
  79563. // Draw rectangle
  79564. g.lineStyle(lineWidth, color, 0);
  79565. g.beginFill(fillColor, 1);
  79566. g.moveTo(-len/2*c + radius*s + x, -len/2*s + radius*c + y);
  79567. g.lineTo( len/2*c + radius*s + x, len/2*s + radius*c + y);
  79568. g.lineTo( len/2*c - radius*s + x, len/2*s - radius*c + y);
  79569. g.lineTo(-len/2*c - radius*s + x, -len/2*s - radius*c + y);
  79570. g.endFill();
  79571. // Draw lines in between
  79572. g.lineStyle(lineWidth, color, 1);
  79573. g.moveTo(-len/2*c + radius*s + x, -len/2*s + radius*c + y);
  79574. g.lineTo( len/2*c + radius*s + x, len/2*s + radius*c + y);
  79575. g.moveTo(-len/2*c - radius*s + x, -len/2*s - radius*c + y);
  79576. g.lineTo( len/2*c - radius*s + x, len/2*s - radius*c + y);
  79577. },
  79578. /**
  79579. * Picks a random pastel color.
  79580. *
  79581. * @method Phaser.Physics.P2.BodyDebug#randomPastelHex
  79582. * @private
  79583. */
  79584. randomPastelHex: function() {
  79585. var blue, green, mix, red;
  79586. mix = [255, 255, 255];
  79587. red = Math.floor(Math.random() * 256);
  79588. green = Math.floor(Math.random() * 256);
  79589. blue = Math.floor(Math.random() * 256);
  79590. red = Math.floor((red + 3 * mix[0]) / 4);
  79591. green = Math.floor((green + 3 * mix[1]) / 4);
  79592. blue = Math.floor((blue + 3 * mix[2]) / 4);
  79593. return this.rgbToHex(red, green, blue);
  79594. },
  79595. /**
  79596. * Converts from RGB to Hex.
  79597. *
  79598. * @method Phaser.Physics.P2.BodyDebug#rgbToHex
  79599. * @private
  79600. */
  79601. rgbToHex: function(r, g, b) {
  79602. return this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b);
  79603. },
  79604. /**
  79605. * Component to hex conversion.
  79606. *
  79607. * @method Phaser.Physics.P2.BodyDebug#componentToHex
  79608. * @private
  79609. */
  79610. componentToHex: function(c) {
  79611. var hex;
  79612. hex = c.toString(16);
  79613. if (hex.length === 2)
  79614. {
  79615. return hex;
  79616. }
  79617. else
  79618. {
  79619. return hex + '0';
  79620. }
  79621. }
  79622. });
  79623. /**
  79624. * @author Richard Davey <rich@photonstorm.com>
  79625. * @copyright 2016 Photon Storm Ltd.
  79626. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79627. */
  79628. /**
  79629. * Creates a linear spring, connecting two bodies. A spring can have a resting length, a stiffness and damping.
  79630. *
  79631. * @class Phaser.Physics.P2.Spring
  79632. * @constructor
  79633. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  79634. * @param {p2.Body} bodyA - First connected body.
  79635. * @param {p2.Body} bodyB - Second connected body.
  79636. * @param {number} [restLength=1] - Rest length of the spring. A number > 0.
  79637. * @param {number} [stiffness=100] - Stiffness of the spring. A number >= 0.
  79638. * @param {number} [damping=1] - Damping of the spring. A number >= 0.
  79639. * @param {Array} [worldA] - Where to hook the spring to body A in world coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  79640. * @param {Array} [worldB] - Where to hook the spring to body B in world coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  79641. * @param {Array} [localA] - Where to hook the spring to body A in local body coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  79642. * @param {Array} [localB] - Where to hook the spring to body B in local body coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  79643. */
  79644. Phaser.Physics.P2.Spring = function (world, bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB) {
  79645. /**
  79646. * @property {Phaser.Game} game - Local reference to game.
  79647. */
  79648. this.game = world.game;
  79649. /**
  79650. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  79651. */
  79652. this.world = world;
  79653. if (restLength === undefined) { restLength = 1; }
  79654. if (stiffness === undefined) { stiffness = 100; }
  79655. if (damping === undefined) { damping = 1; }
  79656. restLength = world.pxm(restLength);
  79657. var options = {
  79658. restLength: restLength,
  79659. stiffness: stiffness,
  79660. damping: damping
  79661. };
  79662. if (typeof worldA !== 'undefined' && worldA !== null)
  79663. {
  79664. options.worldAnchorA = [ world.pxm(worldA[0]), world.pxm(worldA[1]) ];
  79665. }
  79666. if (typeof worldB !== 'undefined' && worldB !== null)
  79667. {
  79668. options.worldAnchorB = [ world.pxm(worldB[0]), world.pxm(worldB[1]) ];
  79669. }
  79670. if (typeof localA !== 'undefined' && localA !== null)
  79671. {
  79672. options.localAnchorA = [ world.pxm(localA[0]), world.pxm(localA[1]) ];
  79673. }
  79674. if (typeof localB !== 'undefined' && localB !== null)
  79675. {
  79676. options.localAnchorB = [ world.pxm(localB[0]), world.pxm(localB[1]) ];
  79677. }
  79678. /**
  79679. * @property {p2.LinearSpring} data - The actual p2 spring object.
  79680. */
  79681. this.data = new p2.LinearSpring(bodyA, bodyB, options);
  79682. this.data.parent = this;
  79683. };
  79684. Phaser.Physics.P2.Spring.prototype.constructor = Phaser.Physics.P2.Spring;
  79685. /**
  79686. * @author Richard Davey <rich@photonstorm.com>
  79687. * @copyright 2016 Photon Storm Ltd.
  79688. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79689. */
  79690. /**
  79691. * Creates a rotational spring, connecting two bodies. A spring can have a resting length, a stiffness and damping.
  79692. *
  79693. * @class Phaser.Physics.P2.RotationalSpring
  79694. * @constructor
  79695. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  79696. * @param {p2.Body} bodyA - First connected body.
  79697. * @param {p2.Body} bodyB - Second connected body.
  79698. * @param {number} [restAngle] - The relative angle of bodies at which the spring is at rest. If not given, it's set to the current relative angle between the bodies.
  79699. * @param {number} [stiffness=100] - Stiffness of the spring. A number >= 0.
  79700. * @param {number} [damping=1] - Damping of the spring. A number >= 0.
  79701. */
  79702. Phaser.Physics.P2.RotationalSpring = function (world, bodyA, bodyB, restAngle, stiffness, damping) {
  79703. /**
  79704. * @property {Phaser.Game} game - Local reference to game.
  79705. */
  79706. this.game = world.game;
  79707. /**
  79708. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  79709. */
  79710. this.world = world;
  79711. if (restAngle === undefined) { restAngle = null; }
  79712. if (stiffness === undefined) { stiffness = 100; }
  79713. if (damping === undefined) { damping = 1; }
  79714. if (restAngle)
  79715. {
  79716. restAngle = world.pxm(restAngle);
  79717. }
  79718. var options = {
  79719. restAngle: restAngle,
  79720. stiffness: stiffness,
  79721. damping: damping
  79722. };
  79723. /**
  79724. * @property {p2.RotationalSpring} data - The actual p2 spring object.
  79725. */
  79726. this.data = new p2.RotationalSpring(bodyA, bodyB, options);
  79727. this.data.parent = this;
  79728. };
  79729. Phaser.Physics.P2.Spring.prototype.constructor = Phaser.Physics.P2.Spring;
  79730. /**
  79731. * @author Richard Davey <rich@photonstorm.com>
  79732. * @copyright 2016 Photon Storm Ltd.
  79733. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79734. */
  79735. /**
  79736. * A P2 Material.
  79737. *
  79738. * \o/ ~ "Because I'm a Material girl"
  79739. *
  79740. * @class Phaser.Physics.P2.Material
  79741. * @constructor
  79742. * @param {string} name - The user defined name given to this Material.
  79743. */
  79744. Phaser.Physics.P2.Material = function (name) {
  79745. /**
  79746. * @property {string} name - The user defined name given to this Material.
  79747. * @default
  79748. */
  79749. this.name = name;
  79750. p2.Material.call(this);
  79751. };
  79752. Phaser.Physics.P2.Material.prototype = Object.create(p2.Material.prototype);
  79753. Phaser.Physics.P2.Material.prototype.constructor = Phaser.Physics.P2.Material;
  79754. /**
  79755. * @author Richard Davey <rich@photonstorm.com>
  79756. * @copyright 2016 Photon Storm Ltd.
  79757. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79758. */
  79759. /**
  79760. * Defines a physics material
  79761. *
  79762. * @class Phaser.Physics.P2.ContactMaterial
  79763. * @constructor
  79764. * @param {Phaser.Physics.P2.Material} materialA - First material participating in the contact material.
  79765. * @param {Phaser.Physics.P2.Material} materialB - Second material participating in the contact material.
  79766. * @param {object} [options] - Additional configuration options.
  79767. */
  79768. Phaser.Physics.P2.ContactMaterial = function (materialA, materialB, options) {
  79769. /**
  79770. * @property {number} id - The contact material identifier.
  79771. */
  79772. /**
  79773. * @property {Phaser.Physics.P2.Material} materialA - First material participating in the contact material.
  79774. */
  79775. /**
  79776. * @property {Phaser.Physics.P2.Material} materialB - Second material participating in the contact material.
  79777. */
  79778. /**
  79779. * @property {number} [friction=0.3] - Friction to use in the contact of these two materials.
  79780. */
  79781. /**
  79782. * @property {number} [restitution=0.0] - Restitution to use in the contact of these two materials.
  79783. */
  79784. /**
  79785. * @property {number} [stiffness=1e7] - Stiffness of the resulting ContactEquation that this ContactMaterial generates.
  79786. */
  79787. /**
  79788. * @property {number} [relaxation=3] - Relaxation of the resulting ContactEquation that this ContactMaterial generates.
  79789. */
  79790. /**
  79791. * @property {number} [frictionStiffness=1e7] - Stiffness of the resulting FrictionEquation that this ContactMaterial generates.
  79792. */
  79793. /**
  79794. * @property {number} [frictionRelaxation=3] - Relaxation of the resulting FrictionEquation that this ContactMaterial generates.
  79795. */
  79796. /**
  79797. * @property {number} [surfaceVelocity=0] - Will add surface velocity to this material. If bodyA rests on top if bodyB, and the surface velocity is positive, bodyA will slide to the right.
  79798. */
  79799. p2.ContactMaterial.call(this, materialA, materialB, options);
  79800. };
  79801. Phaser.Physics.P2.ContactMaterial.prototype = Object.create(p2.ContactMaterial.prototype);
  79802. Phaser.Physics.P2.ContactMaterial.prototype.constructor = Phaser.Physics.P2.ContactMaterial;
  79803. /**
  79804. * @author Richard Davey <rich@photonstorm.com>
  79805. * @copyright 2016 Photon Storm Ltd.
  79806. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79807. */
  79808. /**
  79809. * Collision Group
  79810. *
  79811. * @class Phaser.Physics.P2.CollisionGroup
  79812. * @constructor
  79813. * @param {number} bitmask - The CollisionGroup bitmask.
  79814. */
  79815. Phaser.Physics.P2.CollisionGroup = function (bitmask) {
  79816. /**
  79817. * @property {number} mask - The CollisionGroup bitmask.
  79818. */
  79819. this.mask = bitmask;
  79820. };
  79821. /**
  79822. * @author Richard Davey <rich@photonstorm.com>
  79823. * @copyright 2016 Photon Storm Ltd.
  79824. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79825. */
  79826. /**
  79827. * A constraint that tries to keep the distance between two bodies constant.
  79828. *
  79829. * @class Phaser.Physics.P2.DistanceConstraint
  79830. * @constructor
  79831. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  79832. * @param {p2.Body} bodyA - First connected body.
  79833. * @param {p2.Body} bodyB - Second connected body.
  79834. * @param {number} distance - The distance to keep between the bodies.
  79835. * @param {Array} [localAnchorA] - The anchor point for bodyA, defined locally in bodyA frame. Defaults to [0,0].
  79836. * @param {Array} [localAnchorB] - The anchor point for bodyB, defined locally in bodyB frame. Defaults to [0,0].
  79837. * @param {object} [maxForce=Number.MAX_VALUE] - Maximum force to apply.
  79838. */
  79839. Phaser.Physics.P2.DistanceConstraint = function (world, bodyA, bodyB, distance, localAnchorA, localAnchorB, maxForce) {
  79840. if (distance === undefined) { distance = 100; }
  79841. if (localAnchorA === undefined) { localAnchorA = [0, 0]; }
  79842. if (localAnchorB === undefined) { localAnchorB = [0, 0]; }
  79843. if (maxForce === undefined) { maxForce = Number.MAX_VALUE; }
  79844. /**
  79845. * @property {Phaser.Game} game - Local reference to game.
  79846. */
  79847. this.game = world.game;
  79848. /**
  79849. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  79850. */
  79851. this.world = world;
  79852. distance = world.pxm(distance);
  79853. localAnchorA = [ world.pxmi(localAnchorA[0]), world.pxmi(localAnchorA[1]) ];
  79854. localAnchorB = [ world.pxmi(localAnchorB[0]), world.pxmi(localAnchorB[1]) ];
  79855. var options = { distance: distance, localAnchorA: localAnchorA, localAnchorB: localAnchorB, maxForce: maxForce };
  79856. p2.DistanceConstraint.call(this, bodyA, bodyB, options);
  79857. };
  79858. Phaser.Physics.P2.DistanceConstraint.prototype = Object.create(p2.DistanceConstraint.prototype);
  79859. Phaser.Physics.P2.DistanceConstraint.prototype.constructor = Phaser.Physics.P2.DistanceConstraint;
  79860. /**
  79861. * @author Richard Davey <rich@photonstorm.com>
  79862. * @copyright 2016 Photon Storm Ltd.
  79863. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79864. */
  79865. /**
  79866. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  79867. *
  79868. * @class Phaser.Physics.P2.GearConstraint
  79869. * @constructor
  79870. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  79871. * @param {p2.Body} bodyA - First connected body.
  79872. * @param {p2.Body} bodyB - Second connected body.
  79873. * @param {number} [angle=0] - The relative angle
  79874. * @param {number} [ratio=1] - The gear ratio.
  79875. */
  79876. Phaser.Physics.P2.GearConstraint = function (world, bodyA, bodyB, angle, ratio) {
  79877. if (angle === undefined) { angle = 0; }
  79878. if (ratio === undefined) { ratio = 1; }
  79879. /**
  79880. * @property {Phaser.Game} game - Local reference to game.
  79881. */
  79882. this.game = world.game;
  79883. /**
  79884. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  79885. */
  79886. this.world = world;
  79887. var options = { angle: angle, ratio: ratio };
  79888. p2.GearConstraint.call(this, bodyA, bodyB, options);
  79889. };
  79890. Phaser.Physics.P2.GearConstraint.prototype = Object.create(p2.GearConstraint.prototype);
  79891. Phaser.Physics.P2.GearConstraint.prototype.constructor = Phaser.Physics.P2.GearConstraint;
  79892. /**
  79893. * @author Richard Davey <rich@photonstorm.com>
  79894. * @copyright 2016 Photon Storm Ltd.
  79895. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79896. */
  79897. /**
  79898. * Locks the relative position between two bodies.
  79899. *
  79900. * @class Phaser.Physics.P2.LockConstraint
  79901. * @constructor
  79902. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  79903. * @param {p2.Body} bodyA - First connected body.
  79904. * @param {p2.Body} bodyB - Second connected body.
  79905. * @param {Array} [offset] - The offset of bodyB in bodyA's frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  79906. * @param {number} [angle=0] - The angle of bodyB in bodyA's frame.
  79907. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  79908. */
  79909. Phaser.Physics.P2.LockConstraint = function (world, bodyA, bodyB, offset, angle, maxForce) {
  79910. if (offset === undefined) { offset = [0, 0]; }
  79911. if (angle === undefined) { angle = 0; }
  79912. if (maxForce === undefined) { maxForce = Number.MAX_VALUE; }
  79913. /**
  79914. * @property {Phaser.Game} game - Local reference to game.
  79915. */
  79916. this.game = world.game;
  79917. /**
  79918. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  79919. */
  79920. this.world = world;
  79921. offset = [ world.pxm(offset[0]), world.pxm(offset[1]) ];
  79922. var options = { localOffsetB: offset, localAngleB: angle, maxForce: maxForce };
  79923. p2.LockConstraint.call(this, bodyA, bodyB, options);
  79924. };
  79925. Phaser.Physics.P2.LockConstraint.prototype = Object.create(p2.LockConstraint.prototype);
  79926. Phaser.Physics.P2.LockConstraint.prototype.constructor = Phaser.Physics.P2.LockConstraint;
  79927. /**
  79928. * @author Richard Davey <rich@photonstorm.com>
  79929. * @copyright 2016 Photon Storm Ltd.
  79930. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79931. */
  79932. /**
  79933. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  79934. *
  79935. * @class Phaser.Physics.P2.PrismaticConstraint
  79936. * @constructor
  79937. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  79938. * @param {p2.Body} bodyA - First connected body.
  79939. * @param {p2.Body} bodyB - Second connected body.
  79940. * @param {boolean} [lockRotation=true] - If set to false, bodyB will be free to rotate around its anchor point.
  79941. * @param {Array} [anchorA] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  79942. * @param {Array} [anchorB] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  79943. * @param {Array} [axis] - An axis, defined in body A frame, that body B's anchor point may slide along. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  79944. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  79945. */
  79946. Phaser.Physics.P2.PrismaticConstraint = function (world, bodyA, bodyB, lockRotation, anchorA, anchorB, axis, maxForce) {
  79947. if (lockRotation === undefined) { lockRotation = true; }
  79948. if (anchorA === undefined) { anchorA = [0, 0]; }
  79949. if (anchorB === undefined) { anchorB = [0, 0]; }
  79950. if (axis === undefined) { axis = [0, 0]; }
  79951. if (maxForce === undefined) { maxForce = Number.MAX_VALUE; }
  79952. /**
  79953. * @property {Phaser.Game} game - Local reference to game.
  79954. */
  79955. this.game = world.game;
  79956. /**
  79957. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  79958. */
  79959. this.world = world;
  79960. anchorA = [ world.pxmi(anchorA[0]), world.pxmi(anchorA[1]) ];
  79961. anchorB = [ world.pxmi(anchorB[0]), world.pxmi(anchorB[1]) ];
  79962. var options = { localAnchorA: anchorA, localAnchorB: anchorB, localAxisA: axis, maxForce: maxForce, disableRotationalLock: !lockRotation };
  79963. p2.PrismaticConstraint.call(this, bodyA, bodyB, options);
  79964. };
  79965. Phaser.Physics.P2.PrismaticConstraint.prototype = Object.create(p2.PrismaticConstraint.prototype);
  79966. Phaser.Physics.P2.PrismaticConstraint.prototype.constructor = Phaser.Physics.P2.PrismaticConstraint;
  79967. /**
  79968. * @author Richard Davey <rich@photonstorm.com>
  79969. * @copyright 2016 Photon Storm Ltd.
  79970. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  79971. */
  79972. /**
  79973. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  79974. * The pivot points are given in world (pixel) coordinates.
  79975. *
  79976. * @class Phaser.Physics.P2.RevoluteConstraint
  79977. * @constructor
  79978. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  79979. * @param {p2.Body} bodyA - First connected body.
  79980. * @param {Float32Array} pivotA - The point relative to the center of mass of bodyA which bodyA is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  79981. * @param {p2.Body} bodyB - Second connected body.
  79982. * @param {Float32Array} pivotB - The point relative to the center of mass of bodyB which bodyB is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  79983. * @param {number} [maxForce=0] - The maximum force that should be applied to constrain the bodies.
  79984. * @param {Float32Array} [worldPivot=null] - A pivot point given in world coordinates. If specified, localPivotA and localPivotB are automatically computed from this value.
  79985. */
  79986. Phaser.Physics.P2.RevoluteConstraint = function (world, bodyA, pivotA, bodyB, pivotB, maxForce, worldPivot) {
  79987. if (maxForce === undefined) { maxForce = Number.MAX_VALUE; }
  79988. if (worldPivot === undefined) { worldPivot = null; }
  79989. /**
  79990. * @property {Phaser.Game} game - Local reference to game.
  79991. */
  79992. this.game = world.game;
  79993. /**
  79994. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  79995. */
  79996. this.world = world;
  79997. pivotA = [ world.pxmi(pivotA[0]), world.pxmi(pivotA[1]) ];
  79998. pivotB = [ world.pxmi(pivotB[0]), world.pxmi(pivotB[1]) ];
  79999. if (worldPivot)
  80000. {
  80001. worldPivot = [ world.pxmi(worldPivot[0]), world.pxmi(worldPivot[1]) ];
  80002. }
  80003. var options = { worldPivot: worldPivot, localPivotA: pivotA, localPivotB: pivotB, maxForce: maxForce };
  80004. p2.RevoluteConstraint.call(this, bodyA, bodyB, options);
  80005. };
  80006. Phaser.Physics.P2.RevoluteConstraint.prototype = Object.create(p2.RevoluteConstraint.prototype);
  80007. Phaser.Physics.P2.RevoluteConstraint.prototype.constructor = Phaser.Physics.P2.RevoluteConstraint;
  80008. /**
  80009. * @author Richard Davey <rich@photonstorm.com>
  80010. * @copyright 2016 Photon Storm Ltd.
  80011. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  80012. */
  80013. /**
  80014. * An Image Collection is a special tileset containing mulitple images, with no slicing into each image.
  80015. *
  80016. * Image Collections are normally created automatically when Tiled data is loaded.
  80017. *
  80018. * @class Phaser.ImageCollection
  80019. * @constructor
  80020. * @param {string} name - The name of the image collection in the map data.
  80021. * @param {integer} firstgid - The first image index this image collection contains.
  80022. * @param {integer} [width=32] - Width of widest image (in pixels).
  80023. * @param {integer} [height=32] - Height of tallest image (in pixels).
  80024. * @param {integer} [margin=0] - The margin around all images in the collection (in pixels).
  80025. * @param {integer} [spacing=0] - The spacing between each image in the collection (in pixels).
  80026. * @param {object} [properties={}] - Custom Image Collection properties.
  80027. */
  80028. Phaser.ImageCollection = function (name, firstgid, width, height, margin, spacing, properties) {
  80029. if (width === undefined || width <= 0) { width = 32; }
  80030. if (height === undefined || height <= 0) { height = 32; }
  80031. if (margin === undefined) { margin = 0; }
  80032. if (spacing === undefined) { spacing = 0; }
  80033. /**
  80034. * The name of the Image Collection.
  80035. * @property {string} name
  80036. */
  80037. this.name = name;
  80038. /**
  80039. * The Tiled firstgid value.
  80040. * This is the starting index of the first image index this Image Collection contains.
  80041. * @property {integer} firstgid
  80042. */
  80043. this.firstgid = firstgid | 0;
  80044. /**
  80045. * The width of the widest image (in pixels).
  80046. * @property {integer} imageWidth
  80047. * @readonly
  80048. */
  80049. this.imageWidth = width | 0;
  80050. /**
  80051. * The height of the tallest image (in pixels).
  80052. * @property {integer} imageHeight
  80053. * @readonly
  80054. */
  80055. this.imageHeight = height | 0;
  80056. /**
  80057. * The margin around the images in the collection (in pixels).
  80058. * Use `setSpacing` to change.
  80059. * @property {integer} imageMarge
  80060. * @readonly
  80061. */
  80062. // Modified internally
  80063. this.imageMargin = margin | 0;
  80064. /**
  80065. * The spacing between each image in the collection (in pixels).
  80066. * Use `setSpacing` to change.
  80067. * @property {integer} imageSpacing
  80068. * @readonly
  80069. */
  80070. this.imageSpacing = spacing | 0;
  80071. /**
  80072. * Image Collection-specific properties that are typically defined in the Tiled editor.
  80073. * @property {object} properties
  80074. */
  80075. this.properties = properties || {};
  80076. /**
  80077. * The cached images that are a part of this collection.
  80078. * @property {array} images
  80079. * @readonly
  80080. */
  80081. // Modified internally
  80082. this.images = [];
  80083. /**
  80084. * The total number of images in the image collection.
  80085. * @property {integer} total
  80086. * @readonly
  80087. */
  80088. // Modified internally
  80089. this.total = 0;
  80090. };
  80091. Phaser.ImageCollection.prototype = {
  80092. /**
  80093. * Returns true if and only if this image collection contains the given image index.
  80094. *
  80095. * @method Phaser.ImageCollection#containsImageIndex
  80096. * @param {integer} imageIndex - The image index to search for.
  80097. * @return {boolean} True if this Image Collection contains the given index.
  80098. */
  80099. containsImageIndex: function (imageIndex) {
  80100. return (
  80101. imageIndex >= this.firstgid &&
  80102. imageIndex < (this.firstgid + this.total)
  80103. );
  80104. },
  80105. /**
  80106. * Add an image to this Image Collection.
  80107. *
  80108. * @method Phaser.ImageCollection#addImage
  80109. * @param {integer} gid - The gid of the image in the Image Collection.
  80110. * @param {string} image - The the key of the image in the Image Collection and in the cache.
  80111. */
  80112. addImage: function (gid, image) {
  80113. this.images.push({ gid: gid, image: image });
  80114. this.total++;
  80115. }
  80116. };
  80117. Phaser.ImageCollection.prototype.constructor = Phaser.ImageCollection;
  80118. /**
  80119. * @author Richard Davey <rich@photonstorm.com>
  80120. * @copyright 2016 Photon Storm Ltd.
  80121. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  80122. */
  80123. /**
  80124. * A Tile is a representation of a single tile within the Tilemap.
  80125. *
  80126. * @class Phaser.Tile
  80127. * @constructor
  80128. * @param {object} layer - The layer in the Tilemap data that this tile belongs to.
  80129. * @param {number} index - The index of this tile type in the core map data.
  80130. * @param {number} x - The x coordinate of this tile.
  80131. * @param {number} y - The y coordinate of this tile.
  80132. * @param {number} width - Width of the tile.
  80133. * @param {number} height - Height of the tile.
  80134. */
  80135. Phaser.Tile = function (layer, index, x, y, width, height) {
  80136. /**
  80137. * @property {object} layer - The layer in the Tilemap data that this tile belongs to.
  80138. */
  80139. this.layer = layer;
  80140. /**
  80141. * @property {number} index - The index of this tile within the map data corresponding to the tileset, or -1 if this represents a blank/null tile.
  80142. */
  80143. this.index = index;
  80144. /**
  80145. * @property {number} x - The x map coordinate of this tile.
  80146. */
  80147. this.x = x;
  80148. /**
  80149. * @property {number} y - The y map coordinate of this tile.
  80150. */
  80151. this.y = y;
  80152. /**
  80153. * @property {number} rotation - The rotation angle of this tile.
  80154. */
  80155. this.rotation = 0;
  80156. /**
  80157. * @property {boolean} flipped - Whether this tile is flipped (mirrored) or not.
  80158. */
  80159. this.flipped = false;
  80160. /**
  80161. * @property {number} x - The x map coordinate of this tile.
  80162. */
  80163. this.worldX = x * width;
  80164. /**
  80165. * @property {number} y - The y map coordinate of this tile.
  80166. */
  80167. this.worldY = y * height;
  80168. /**
  80169. * @property {number} width - The width of the tile in pixels.
  80170. */
  80171. this.width = width;
  80172. /**
  80173. * @property {number} height - The height of the tile in pixels.
  80174. */
  80175. this.height = height;
  80176. /**
  80177. * @property {number} width - The width of the tile in pixels.
  80178. */
  80179. this.centerX = Math.abs(width / 2);
  80180. /**
  80181. * @property {number} height - The height of the tile in pixels.
  80182. */
  80183. this.centerY = Math.abs(height / 2);
  80184. /**
  80185. * @property {number} alpha - The alpha value at which this tile is drawn to the canvas.
  80186. */
  80187. this.alpha = 1;
  80188. /**
  80189. * @property {object} properties - Tile specific properties.
  80190. */
  80191. this.properties = {};
  80192. /**
  80193. * @property {boolean} scanned - Has this tile been walked / turned into a poly?
  80194. */
  80195. this.scanned = false;
  80196. /**
  80197. * @property {boolean} faceTop - Is the top of this tile an interesting edge?
  80198. */
  80199. this.faceTop = false;
  80200. /**
  80201. * @property {boolean} faceBottom - Is the bottom of this tile an interesting edge?
  80202. */
  80203. this.faceBottom = false;
  80204. /**
  80205. * @property {boolean} faceLeft - Is the left of this tile an interesting edge?
  80206. */
  80207. this.faceLeft = false;
  80208. /**
  80209. * @property {boolean} faceRight - Is the right of this tile an interesting edge?
  80210. */
  80211. this.faceRight = false;
  80212. /**
  80213. * @property {boolean} collideLeft - Indicating collide with any object on the left.
  80214. * @default
  80215. */
  80216. this.collideLeft = false;
  80217. /**
  80218. * @property {boolean} collideRight - Indicating collide with any object on the right.
  80219. * @default
  80220. */
  80221. this.collideRight = false;
  80222. /**
  80223. * @property {boolean} collideUp - Indicating collide with any object on the top.
  80224. * @default
  80225. */
  80226. this.collideUp = false;
  80227. /**
  80228. * @property {boolean} collideDown - Indicating collide with any object on the bottom.
  80229. * @default
  80230. */
  80231. this.collideDown = false;
  80232. /**
  80233. * @property {function} collisionCallback - Tile collision callback.
  80234. * @default
  80235. */
  80236. this.collisionCallback = null;
  80237. /**
  80238. * @property {object} collisionCallbackContext - The context in which the collision callback will be called.
  80239. * @default
  80240. */
  80241. this.collisionCallbackContext = this;
  80242. };
  80243. Phaser.Tile.prototype = {
  80244. /**
  80245. * Check if the given x and y world coordinates are within this Tile.
  80246. *
  80247. * @method Phaser.Tile#containsPoint
  80248. * @param {number} x - The x coordinate to test.
  80249. * @param {number} y - The y coordinate to test.
  80250. * @return {boolean} True if the coordinates are within this Tile, otherwise false.
  80251. */
  80252. containsPoint: function (x, y) {
  80253. return !(x < this.worldX || y < this.worldY || x > this.right || y > this.bottom);
  80254. },
  80255. /**
  80256. * Check for intersection with this tile.
  80257. *
  80258. * @method Phaser.Tile#intersects
  80259. * @param {number} x - The x axis in pixels.
  80260. * @param {number} y - The y axis in pixels.
  80261. * @param {number} right - The right point.
  80262. * @param {number} bottom - The bottom point.
  80263. */
  80264. intersects: function (x, y, right, bottom) {
  80265. if (right <= this.worldX)
  80266. {
  80267. return false;
  80268. }
  80269. if (bottom <= this.worldY)
  80270. {
  80271. return false;
  80272. }
  80273. if (x >= this.worldX + this.width)
  80274. {
  80275. return false;
  80276. }
  80277. if (y >= this.worldY + this.height)
  80278. {
  80279. return false;
  80280. }
  80281. return true;
  80282. },
  80283. /**
  80284. * Set a callback to be called when this tile is hit by an object.
  80285. * The callback must true true for collision processing to take place.
  80286. *
  80287. * @method Phaser.Tile#setCollisionCallback
  80288. * @param {function} callback - Callback function.
  80289. * @param {object} context - Callback will be called within this context.
  80290. */
  80291. setCollisionCallback: function (callback, context) {
  80292. this.collisionCallback = callback;
  80293. this.collisionCallbackContext = context;
  80294. },
  80295. /**
  80296. * Clean up memory.
  80297. *
  80298. * @method Phaser.Tile#destroy
  80299. */
  80300. destroy: function () {
  80301. this.collisionCallback = null;
  80302. this.collisionCallbackContext = null;
  80303. this.properties = null;
  80304. },
  80305. /**
  80306. * Sets the collision flags for each side of this tile and updates the interesting faces list.
  80307. *
  80308. * @method Phaser.Tile#setCollision
  80309. * @param {boolean} left - Indicating collide with any object on the left.
  80310. * @param {boolean} right - Indicating collide with any object on the right.
  80311. * @param {boolean} up - Indicating collide with any object on the top.
  80312. * @param {boolean} down - Indicating collide with any object on the bottom.
  80313. */
  80314. setCollision: function (left, right, up, down) {
  80315. this.collideLeft = left;
  80316. this.collideRight = right;
  80317. this.collideUp = up;
  80318. this.collideDown = down;
  80319. this.faceLeft = left;
  80320. this.faceRight = right;
  80321. this.faceTop = up;
  80322. this.faceBottom = down;
  80323. },
  80324. /**
  80325. * Reset collision status flags.
  80326. *
  80327. * @method Phaser.Tile#resetCollision
  80328. */
  80329. resetCollision: function () {
  80330. this.collideLeft = false;
  80331. this.collideRight = false;
  80332. this.collideUp = false;
  80333. this.collideDown = false;
  80334. this.faceTop = false;
  80335. this.faceBottom = false;
  80336. this.faceLeft = false;
  80337. this.faceRight = false;
  80338. },
  80339. /**
  80340. * Is this tile interesting?
  80341. *
  80342. * @method Phaser.Tile#isInteresting
  80343. * @param {boolean} collides - If true will check any collides value.
  80344. * @param {boolean} faces - If true will check any face value.
  80345. * @return {boolean} True if the Tile is interesting, otherwise false.
  80346. */
  80347. isInteresting: function (collides, faces) {
  80348. if (collides && faces)
  80349. {
  80350. // Does this tile have any collide flags OR interesting face?
  80351. return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown || this.faceTop || this.faceBottom || this.faceLeft || this.faceRight || this.collisionCallback);
  80352. }
  80353. else if (collides)
  80354. {
  80355. // Does this tile collide?
  80356. return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown);
  80357. }
  80358. else if (faces)
  80359. {
  80360. // Does this tile have an interesting face?
  80361. return (this.faceTop || this.faceBottom || this.faceLeft || this.faceRight);
  80362. }
  80363. return false;
  80364. },
  80365. /**
  80366. * Copies the tile data and properties from the given tile to this tile.
  80367. *
  80368. * @method Phaser.Tile#copy
  80369. * @param {Phaser.Tile} tile - The tile to copy from.
  80370. */
  80371. copy: function (tile) {
  80372. this.index = tile.index;
  80373. this.alpha = tile.alpha;
  80374. this.properties = tile.properties;
  80375. this.collideUp = tile.collideUp;
  80376. this.collideDown = tile.collideDown;
  80377. this.collideLeft = tile.collideLeft;
  80378. this.collideRight = tile.collideRight;
  80379. this.collisionCallback = tile.collisionCallback;
  80380. this.collisionCallbackContext = tile.collisionCallbackContext;
  80381. }
  80382. };
  80383. Phaser.Tile.prototype.constructor = Phaser.Tile;
  80384. /**
  80385. * @name Phaser.Tile#collides
  80386. * @property {boolean} collides - True if this tile can collide on any of its faces.
  80387. * @readonly
  80388. */
  80389. Object.defineProperty(Phaser.Tile.prototype, "collides", {
  80390. get: function () {
  80391. return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown);
  80392. }
  80393. });
  80394. /**
  80395. * @name Phaser.Tile#canCollide
  80396. * @property {boolean} canCollide - True if this tile can collide on any of its faces or has a collision callback set.
  80397. * @readonly
  80398. */
  80399. Object.defineProperty(Phaser.Tile.prototype, "canCollide", {
  80400. get: function () {
  80401. return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown || this.collisionCallback);
  80402. }
  80403. });
  80404. /**
  80405. * @name Phaser.Tile#left
  80406. * @property {number} left - The x value in pixels.
  80407. * @readonly
  80408. */
  80409. Object.defineProperty(Phaser.Tile.prototype, "left", {
  80410. get: function () {
  80411. return this.worldX;
  80412. }
  80413. });
  80414. /**
  80415. * @name Phaser.Tile#right
  80416. * @property {number} right - The sum of the x and width properties.
  80417. * @readonly
  80418. */
  80419. Object.defineProperty(Phaser.Tile.prototype, "right", {
  80420. get: function () {
  80421. return this.worldX + this.width;
  80422. }
  80423. });
  80424. /**
  80425. * @name Phaser.Tile#top
  80426. * @property {number} top - The y value.
  80427. * @readonly
  80428. */
  80429. Object.defineProperty(Phaser.Tile.prototype, "top", {
  80430. get: function () {
  80431. return this.worldY;
  80432. }
  80433. });
  80434. /**
  80435. * @name Phaser.Tile#bottom
  80436. * @property {number} bottom - The sum of the y and height properties.
  80437. * @readonly
  80438. */
  80439. Object.defineProperty(Phaser.Tile.prototype, "bottom", {
  80440. get: function () {
  80441. return this.worldY + this.height;
  80442. }
  80443. });
  80444. /**
  80445. * @author Richard Davey <rich@photonstorm.com>
  80446. * @copyright 2016 Photon Storm Ltd.
  80447. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  80448. */
  80449. /**
  80450. * Creates a new Phaser.Tilemap object. The map can either be populated with data from a Tiled JSON file or from a CSV file.
  80451. *
  80452. * Tiled is a free software package specifically for creating tile maps, and is available from http://www.mapeditor.org
  80453. *
  80454. * To do this pass the Cache key as the first parameter. When using Tiled data you need only provide the key.
  80455. * When using CSV data you must provide the key and the tileWidth and tileHeight parameters.
  80456. * If creating a blank tilemap to be populated later, you can either specify no parameters at all and then use `Tilemap.create` or pass the map and tile dimensions here.
  80457. * Note that all Tilemaps use a base tile size to calculate dimensions from, but that a TilemapLayer may have its own unique tile size that overrides it.
  80458. * A Tile map is rendered to the display using a TilemapLayer. It is not added to the display list directly itself.
  80459. * A map may have multiple layers. You can perform operations on the map data such as copying, pasting, filling and shuffling the tiles around.
  80460. *
  80461. * @class Phaser.Tilemap
  80462. * @constructor
  80463. * @param {Phaser.Game} game - Game reference to the currently running game.
  80464. * @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map either leave this parameter out or pass `null`.
  80465. * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  80466. * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  80467. * @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  80468. * @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  80469. */
  80470. Phaser.Tilemap = function (game, key, tileWidth, tileHeight, width, height) {
  80471. /**
  80472. * @property {Phaser.Game} game - A reference to the currently running Game.
  80473. */
  80474. this.game = game;
  80475. /**
  80476. * @property {string} key - The key of this map data in the Phaser.Cache.
  80477. */
  80478. this.key = key;
  80479. var data = Phaser.TilemapParser.parse(this.game, key, tileWidth, tileHeight, width, height);
  80480. if (data === null)
  80481. {
  80482. return;
  80483. }
  80484. /**
  80485. * @property {number} width - The width of the map (in tiles).
  80486. */
  80487. this.width = data.width;
  80488. /**
  80489. * @property {number} height - The height of the map (in tiles).
  80490. */
  80491. this.height = data.height;
  80492. /**
  80493. * @property {number} tileWidth - The base width of the tiles in the map (in pixels).
  80494. */
  80495. this.tileWidth = data.tileWidth;
  80496. /**
  80497. * @property {number} tileHeight - The base height of the tiles in the map (in pixels).
  80498. */
  80499. this.tileHeight = data.tileHeight;
  80500. /**
  80501. * @property {string} orientation - The orientation of the map data (as specified in Tiled), usually 'orthogonal'.
  80502. */
  80503. this.orientation = data.orientation;
  80504. /**
  80505. * @property {number} format - The format of the map data, either Phaser.Tilemap.CSV or Phaser.Tilemap.TILED_JSON.
  80506. */
  80507. this.format = data.format;
  80508. /**
  80509. * @property {number} version - The version of the map data (as specified in Tiled, usually 1).
  80510. */
  80511. this.version = data.version;
  80512. /**
  80513. * @property {object} properties - Map specific properties as specified in Tiled.
  80514. */
  80515. this.properties = data.properties;
  80516. /**
  80517. * @property {number} widthInPixels - The width of the map in pixels based on width * tileWidth.
  80518. */
  80519. this.widthInPixels = data.widthInPixels;
  80520. /**
  80521. * @property {number} heightInPixels - The height of the map in pixels based on height * tileHeight.
  80522. */
  80523. this.heightInPixels = data.heightInPixels;
  80524. /**
  80525. * @property {array} layers - An array of Tilemap layer data.
  80526. */
  80527. this.layers = data.layers;
  80528. /**
  80529. * @property {array} tilesets - An array of Tilesets.
  80530. */
  80531. this.tilesets = data.tilesets;
  80532. /**
  80533. * @property {array} imagecollections - An array of Image Collections.
  80534. */
  80535. this.imagecollections = data.imagecollections;
  80536. /**
  80537. * @property {array} tiles - The super array of Tiles.
  80538. */
  80539. this.tiles = data.tiles;
  80540. /**
  80541. * @property {array} objects - An array of Tiled Object Layers.
  80542. */
  80543. this.objects = data.objects;
  80544. /**
  80545. * @property {array} collideIndexes - An array of tile indexes that collide.
  80546. */
  80547. this.collideIndexes = [];
  80548. /**
  80549. * @property {array} collision - An array of collision data (polylines, etc).
  80550. */
  80551. this.collision = data.collision;
  80552. /**
  80553. * @property {array} images - An array of Tiled Image Layers.
  80554. */
  80555. this.images = data.images;
  80556. /**
  80557. * @property {boolean} enableDebug - If set then console.log is used to dump out useful layer creation debug data.
  80558. */
  80559. this.enableDebug = false;
  80560. /**
  80561. * @property {number} currentLayer - The current layer.
  80562. */
  80563. this.currentLayer = 0;
  80564. /**
  80565. * @property {array} debugMap - Map data used for debug values only.
  80566. */
  80567. this.debugMap = [];
  80568. /**
  80569. * @property {array} _results - Internal var.
  80570. * @private
  80571. */
  80572. this._results = [];
  80573. /**
  80574. * @property {number} _tempA - Internal var.
  80575. * @private
  80576. */
  80577. this._tempA = 0;
  80578. /**
  80579. * @property {number} _tempB - Internal var.
  80580. * @private
  80581. */
  80582. this._tempB = 0;
  80583. };
  80584. /**
  80585. * @constant
  80586. * @type {number}
  80587. */
  80588. Phaser.Tilemap.CSV = 0;
  80589. /**
  80590. * @constant
  80591. * @type {number}
  80592. */
  80593. Phaser.Tilemap.TILED_JSON = 1;
  80594. /**
  80595. * @constant
  80596. * @type {number}
  80597. */
  80598. Phaser.Tilemap.NORTH = 0;
  80599. /**
  80600. * @constant
  80601. * @type {number}
  80602. */
  80603. Phaser.Tilemap.EAST = 1;
  80604. /**
  80605. * @constant
  80606. * @type {number}
  80607. */
  80608. Phaser.Tilemap.SOUTH = 2;
  80609. /**
  80610. * @constant
  80611. * @type {number}
  80612. */
  80613. Phaser.Tilemap.WEST = 3;
  80614. Phaser.Tilemap.prototype = {
  80615. /**
  80616. * Creates an empty map of the given dimensions and one blank layer. If layers already exist they are erased.
  80617. *
  80618. * @method Phaser.Tilemap#create
  80619. * @param {string} name - The name of the default layer of the map.
  80620. * @param {number} width - The width of the map in tiles.
  80621. * @param {number} height - The height of the map in tiles.
  80622. * @param {number} tileWidth - The width of the tiles the map uses for calculations.
  80623. * @param {number} tileHeight - The height of the tiles the map uses for calculations.
  80624. * @param {Phaser.Group} [group] - Optional Group to add the layer to. If not specified it will be added to the World group.
  80625. * @return {Phaser.TilemapLayer} The TilemapLayer object. This is an extension of Phaser.Image and can be moved around the display list accordingly.
  80626. */
  80627. create: function (name, width, height, tileWidth, tileHeight, group) {
  80628. if (group === undefined) { group = this.game.world; }
  80629. this.width = width;
  80630. this.height = height;
  80631. this.setTileSize(tileWidth, tileHeight);
  80632. this.layers.length = 0;
  80633. return this.createBlankLayer(name, width, height, tileWidth, tileHeight, group);
  80634. },
  80635. /**
  80636. * Sets the base tile size for the map.
  80637. *
  80638. * @method Phaser.Tilemap#setTileSize
  80639. * @param {number} tileWidth - The width of the tiles the map uses for calculations.
  80640. * @param {number} tileHeight - The height of the tiles the map uses for calculations.
  80641. */
  80642. setTileSize: function (tileWidth, tileHeight) {
  80643. this.tileWidth = tileWidth;
  80644. this.tileHeight = tileHeight;
  80645. this.widthInPixels = this.width * tileWidth;
  80646. this.heightInPixels = this.height * tileHeight;
  80647. },
  80648. /**
  80649. * Adds an image to the map to be used as a tileset. A single map may use multiple tilesets.
  80650. * Note that the tileset name can be found in the JSON file exported from Tiled, or in the Tiled editor.
  80651. *
  80652. * @method Phaser.Tilemap#addTilesetImage
  80653. * @param {string} tileset - The name of the tileset as specified in the map data.
  80654. * @param {string|Phaser.BitmapData} [key] - The key of the Phaser.Cache image used for this tileset.
  80655. * If `undefined` or `null` it will look for an image with a key matching the tileset parameter.
  80656. * You can also pass in a BitmapData which can be used instead of an Image.
  80657. * @param {number} [tileWidth=32] - The width of the tiles in the Tileset Image. If not given it will default to the map.tileWidth value, if that isn't set then 32.
  80658. * @param {number} [tileHeight=32] - The height of the tiles in the Tileset Image. If not given it will default to the map.tileHeight value, if that isn't set then 32.
  80659. * @param {number} [tileMargin=0] - The width of the tiles in the Tileset Image.
  80660. * @param {number} [tileSpacing=0] - The height of the tiles in the Tileset Image.
  80661. * @param {number} [gid=0] - If adding multiple tilesets to a blank/dynamic map, specify the starting GID the set will use here.
  80662. * @return {Phaser.Tileset} Returns the Tileset object that was created or updated, or null if it failed.
  80663. */
  80664. addTilesetImage: function (tileset, key, tileWidth, tileHeight, tileMargin, tileSpacing, gid) {
  80665. if (tileset === undefined) { return null; }
  80666. if (tileWidth === undefined) { tileWidth = this.tileWidth; }
  80667. if (tileHeight === undefined) { tileHeight = this.tileHeight; }
  80668. if (tileMargin === undefined) { tileMargin = 0; }
  80669. if (tileSpacing === undefined) { tileSpacing = 0; }
  80670. if (gid === undefined) { gid = 0; }
  80671. // In-case we're working from a blank map
  80672. if (tileWidth === 0)
  80673. {
  80674. tileWidth = 32;
  80675. }
  80676. if (tileHeight === 0)
  80677. {
  80678. tileHeight = 32;
  80679. }
  80680. var img = null;
  80681. if (key === undefined || key === null)
  80682. {
  80683. key = tileset;
  80684. }
  80685. if (key instanceof Phaser.BitmapData)
  80686. {
  80687. img = key.canvas;
  80688. }
  80689. else
  80690. {
  80691. if (!this.game.cache.checkImageKey(key))
  80692. {
  80693. console.warn('Phaser.Tilemap.addTilesetImage: Invalid image key given: "' + key + '"');
  80694. return null;
  80695. }
  80696. img = this.game.cache.getImage(key);
  80697. }
  80698. var idx = this.getTilesetIndex(tileset);
  80699. if (idx === null && this.format === Phaser.Tilemap.TILED_JSON)
  80700. {
  80701. console.warn('Phaser.Tilemap.addTilesetImage: No data found in the JSON matching the tileset name: "' + tileset + '"');
  80702. return null;
  80703. }
  80704. if (this.tilesets[idx])
  80705. {
  80706. this.tilesets[idx].setImage(img);
  80707. return this.tilesets[idx];
  80708. }
  80709. else
  80710. {
  80711. var newSet = new Phaser.Tileset(tileset, gid, tileWidth, tileHeight, tileMargin, tileSpacing, {});
  80712. newSet.setImage(img);
  80713. this.tilesets.push(newSet);
  80714. var i = this.tilesets.length - 1;
  80715. var x = tileMargin;
  80716. var y = tileMargin;
  80717. var count = 0;
  80718. var countX = 0;
  80719. var countY = 0;
  80720. for (var t = gid; t < gid + newSet.total; t++)
  80721. {
  80722. this.tiles[t] = [x, y, i];
  80723. x += tileWidth + tileSpacing;
  80724. count++;
  80725. if (count === newSet.total)
  80726. {
  80727. break;
  80728. }
  80729. countX++;
  80730. if (countX === newSet.columns)
  80731. {
  80732. x = tileMargin;
  80733. y += tileHeight + tileSpacing;
  80734. countX = 0;
  80735. countY++;
  80736. if (countY === newSet.rows)
  80737. {
  80738. break;
  80739. }
  80740. }
  80741. }
  80742. return newSet;
  80743. }
  80744. return null;
  80745. },
  80746. /**
  80747. * Creates a Sprite for every {@link http://doc.mapeditor.org/reference/tmx-map-format/#object object} matching the `gid` argument. You can optionally specify the group that the Sprite will be created in. If none is
  80748. * given it will be created in the World. All properties from the map data objectgroup are copied across to the Sprite, so you can use this as an easy way to
  80749. * configure Sprite properties from within the map editor. For example giving an object a property of `alpha: 0.5` in the map editor will duplicate that when the
  80750. * Sprite is created. You could also give it a value like: `body.velocity.x: 100` to set it moving automatically.
  80751. *
  80752. * The `gid` argument is matched against:
  80753. *
  80754. * 1. For a tile object, the tile identifier (`gid`); or
  80755. * 2. The object's unique ID (`id`); or
  80756. * 3. The object's `name` (a string)
  80757. *
  80758. * @method Phaser.Tilemap#createFromObjects
  80759. * @param {string} name - The name of the Object Group to create Sprites from.
  80760. * @param {number|string} gid - The object's tile reference (gid), unique ID (id) or name.
  80761. * @param {string} key - The Game.cache key of the image that this Sprite will use.
  80762. * @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here.
  80763. * @param {boolean} [exists=true] - The default exists state of the Sprite.
  80764. * @param {boolean} [autoCull=false] - The default autoCull state of the Sprite. Sprites that are autoCulled are culled from the camera if out of its range.
  80765. * @param {Phaser.Group} [group=Phaser.World] - Group to add the Sprite to. If not specified it will be added to the World group.
  80766. * @param {object} [CustomClass=Phaser.Sprite] - If you wish to create your own class, rather than Phaser.Sprite, pass the class here. Your class must extend Phaser.Sprite and have the same constructor parameters.
  80767. * @param {boolean} [adjustY=true] - By default the Tiled map editor uses a bottom-left coordinate system. Phaser uses top-left. So most objects will appear too low down. This parameter moves them up by their height.
  80768. */
  80769. createFromObjects: function (name, gid, key, frame, exists, autoCull, group, CustomClass, adjustY) {
  80770. if (exists === undefined) { exists = true; }
  80771. if (autoCull === undefined) { autoCull = false; }
  80772. if (group === undefined) { group = this.game.world; }
  80773. if (CustomClass === undefined) { CustomClass = Phaser.Sprite; }
  80774. if (adjustY === undefined) { adjustY = true; }
  80775. if (!this.objects[name])
  80776. {
  80777. console.warn('Tilemap.createFromObjects: Invalid objectgroup name given: ' + name);
  80778. return;
  80779. }
  80780. for (var i = 0; i < this.objects[name].length; i++)
  80781. {
  80782. var found = false;
  80783. var obj = this.objects[name][i];
  80784. if (obj.gid !== undefined && typeof gid === 'number' && obj.gid === gid)
  80785. {
  80786. found = true;
  80787. }
  80788. else if (obj.id !== undefined && typeof gid === 'number' && obj.id === gid)
  80789. {
  80790. found = true;
  80791. }
  80792. else if (obj.name !== undefined && typeof gid === 'string' && obj.name === gid)
  80793. {
  80794. found = true;
  80795. }
  80796. if (found)
  80797. {
  80798. var sprite = new CustomClass(this.game, parseFloat(obj.x, 10), parseFloat(obj.y, 10), key, frame);
  80799. sprite.name = obj.name;
  80800. sprite.autoCull = autoCull;
  80801. sprite.exists = exists;
  80802. sprite.visible = obj.visible;
  80803. if (obj.width)
  80804. {
  80805. sprite.width = obj.width;
  80806. }
  80807. if (obj.height)
  80808. {
  80809. sprite.height = obj.height;
  80810. }
  80811. if (obj.rotation)
  80812. {
  80813. sprite.angle = obj.rotation;
  80814. }
  80815. if (adjustY)
  80816. {
  80817. sprite.y -= sprite.height;
  80818. }
  80819. group.add(sprite);
  80820. for (var property in obj.properties)
  80821. {
  80822. group.set(sprite, property, obj.properties[property], false, false, 0, true);
  80823. }
  80824. }
  80825. }
  80826. },
  80827. /**
  80828. * Creates a Sprite for every object matching the given tile indexes in the map data.
  80829. * You can specify the group that the Sprite will be created in. If none is given it will be created in the World.
  80830. * You can optional specify if the tile will be replaced with another after the Sprite is created. This is useful if you want to lay down special
  80831. * tiles in a level that are converted to Sprites, but want to replace the tile itself with a floor tile or similar once converted.
  80832. *
  80833. * @method Phaser.Tilemap#createFromTiles
  80834. * @param {integer|Array} tiles - The tile index, or array of indexes, to create Sprites from.
  80835. * @param {integer|Array} replacements - The tile index, or array of indexes, to change a converted tile to. Set to `null` to not change.
  80836. * @param {string} key - The Game.cache key of the image that this Sprite will use.
  80837. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on.
  80838. * @param {Phaser.Group} [group=Phaser.World] - Group to add the Sprite to. If not specified it will be added to the World group.
  80839. * @param {object} [properties] - An object that contains the default properties for your newly created Sprite. This object will be iterated and any matching Sprite property will be set.
  80840. * @return {integer} The number of Sprites that were created.
  80841. */
  80842. createFromTiles: function (tiles, replacements, key, layer, group, properties) {
  80843. if (typeof tiles === 'number') { tiles = [tiles]; }
  80844. if (replacements === undefined || replacements === null)
  80845. {
  80846. replacements = [];
  80847. }
  80848. else if (typeof replacements === 'number')
  80849. {
  80850. replacements = [replacements];
  80851. }
  80852. layer = this.getLayer(layer);
  80853. if (group === undefined) { group = this.game.world; }
  80854. if (properties === undefined) { properties = {}; }
  80855. if (properties.customClass === undefined)
  80856. {
  80857. properties.customClass = Phaser.Sprite;
  80858. }
  80859. if (properties.adjustY === undefined)
  80860. {
  80861. properties.adjustY = true;
  80862. }
  80863. var lw = this.layers[layer].width;
  80864. var lh = this.layers[layer].height;
  80865. this.copy(0, 0, lw, lh, layer);
  80866. if (this._results.length < 2)
  80867. {
  80868. return 0;
  80869. }
  80870. var total = 0;
  80871. var sprite;
  80872. for (var i = 1, len = this._results.length; i < len; i++)
  80873. {
  80874. if (tiles.indexOf(this._results[i].index) !== -1)
  80875. {
  80876. sprite = new properties.customClass(this.game, this._results[i].worldX, this._results[i].worldY, key);
  80877. for (var property in properties)
  80878. {
  80879. sprite[property] = properties[property];
  80880. }
  80881. group.add(sprite);
  80882. total++;
  80883. }
  80884. }
  80885. if (replacements.length === 1)
  80886. {
  80887. // Assume 1 replacement for all types of tile given
  80888. for (i = 0; i < tiles.length; i++)
  80889. {
  80890. this.replace(tiles[i], replacements[0], 0, 0, lw, lh, layer);
  80891. }
  80892. }
  80893. else if (replacements.length > 1)
  80894. {
  80895. // Assume 1 for 1 mapping
  80896. for (i = 0; i < tiles.length; i++)
  80897. {
  80898. this.replace(tiles[i], replacements[i], 0, 0, lw, lh, layer);
  80899. }
  80900. }
  80901. return total;
  80902. },
  80903. /**
  80904. * Creates a new TilemapLayer object. By default TilemapLayers are fixed to the camera.
  80905. * The `layer` parameter is important. If you've created your map in Tiled then you can get this by looking in Tiled and looking at the Layer name.
  80906. * Or you can open the JSON file it exports and look at the layers[].name value. Either way it must match.
  80907. * If you wish to create a blank layer to put your own tiles on then see Tilemap.createBlankLayer.
  80908. *
  80909. * @method Phaser.Tilemap#createLayer
  80910. * @param {number|string} layer - The layer array index value, or if a string is given the layer name, within the map data that this TilemapLayer represents.
  80911. * @param {number} [width] - The rendered width of the layer, should never be wider than Game.width. If not given it will be set to Game.width.
  80912. * @param {number} [height] - The rendered height of the layer, should never be wider than Game.height. If not given it will be set to Game.height.
  80913. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  80914. * @return {Phaser.TilemapLayer} The TilemapLayer object. This is an extension of Phaser.Sprite and can be moved around the display list accordingly.
  80915. */
  80916. createLayer: function (layer, width, height, group) {
  80917. // Add Buffer support for the left of the canvas
  80918. if (width === undefined) { width = this.game.width; }
  80919. if (height === undefined) { height = this.game.height; }
  80920. if (group === undefined) { group = this.game.world; }
  80921. var index = layer;
  80922. if (typeof layer === 'string')
  80923. {
  80924. index = this.getLayerIndex(layer);
  80925. }
  80926. if (index === null || index > this.layers.length)
  80927. {
  80928. console.warn('Tilemap.createLayer: Invalid layer ID given: "' + layer + '"');
  80929. return;
  80930. }
  80931. // Sort out the display dimensions, so they never render too much, or too little.
  80932. if (width === undefined || width <= 0)
  80933. {
  80934. width = Math.min(this.game.width, this.layers[index].widthInPixels);
  80935. }
  80936. else if (width > this.game.width)
  80937. {
  80938. width = this.game.width;
  80939. }
  80940. if (height === undefined || height <= 0)
  80941. {
  80942. height = Math.min(this.game.height, this.layers[index].heightInPixels);
  80943. }
  80944. else if (height > this.game.height)
  80945. {
  80946. height = this.game.height;
  80947. }
  80948. if (this.enableDebug)
  80949. {
  80950. console.group('Tilemap.createLayer');
  80951. console.log('Name:', this.layers[index].name);
  80952. console.log('Size:', width, 'x', height);
  80953. console.log('Tileset:', this.tilesets[0].name, 'index:', index);
  80954. }
  80955. var rootLayer = group.add(new Phaser.TilemapLayer(this.game, this, index, width, height));
  80956. if (this.enableDebug)
  80957. {
  80958. console.groupEnd();
  80959. }
  80960. return rootLayer;
  80961. },
  80962. /**
  80963. * Creates a new and empty layer on this Tilemap. By default TilemapLayers are fixed to the camera.
  80964. *
  80965. * @method Phaser.Tilemap#createBlankLayer
  80966. * @param {string} name - The name of this layer. Must be unique within the map.
  80967. * @param {number} width - The width of the layer in tiles.
  80968. * @param {number} height - The height of the layer in tiles.
  80969. * @param {number} tileWidth - The width of the tiles the layer uses for calculations.
  80970. * @param {number} tileHeight - The height of the tiles the layer uses for calculations.
  80971. * @param {Phaser.Group} [group] - Optional Group to add the layer to. If not specified it will be added to the World group.
  80972. * @return {Phaser.TilemapLayer} The TilemapLayer object. This is an extension of Phaser.Image and can be moved around the display list accordingly.
  80973. */
  80974. createBlankLayer: function (name, width, height, tileWidth, tileHeight, group) {
  80975. if (group === undefined) { group = this.game.world; }
  80976. if (this.getLayerIndex(name) !== null)
  80977. {
  80978. console.warn('Tilemap.createBlankLayer: Layer with matching name already exists: ' + name);
  80979. return;
  80980. }
  80981. var layer = {
  80982. name: name,
  80983. x: 0,
  80984. y: 0,
  80985. width: width,
  80986. height: height,
  80987. widthInPixels: width * tileWidth,
  80988. heightInPixels: height * tileHeight,
  80989. alpha: 1,
  80990. visible: true,
  80991. properties: {},
  80992. indexes: [],
  80993. callbacks: [],
  80994. bodies: [],
  80995. data: null
  80996. };
  80997. var row;
  80998. var output = [];
  80999. for (var y = 0; y < height; y++)
  81000. {
  81001. row = [];
  81002. for (var x = 0; x < width; x++)
  81003. {
  81004. row.push(new Phaser.Tile(layer, -1, x, y, tileWidth, tileHeight));
  81005. }
  81006. output.push(row);
  81007. }
  81008. layer.data = output;
  81009. this.layers.push(layer);
  81010. this.currentLayer = this.layers.length - 1;
  81011. var w = layer.widthInPixels;
  81012. var h = layer.heightInPixels;
  81013. if (w > this.game.width)
  81014. {
  81015. w = this.game.width;
  81016. }
  81017. if (h > this.game.height)
  81018. {
  81019. h = this.game.height;
  81020. }
  81021. var output = new Phaser.TilemapLayer(this.game, this, this.layers.length - 1, w, h);
  81022. output.name = name;
  81023. return group.add(output);
  81024. },
  81025. /**
  81026. * Gets the layer index based on the layers name.
  81027. *
  81028. * @method Phaser.Tilemap#getIndex
  81029. * @protected
  81030. * @param {array} location - The local array to search.
  81031. * @param {string} name - The name of the array element to get.
  81032. * @return {number} The index of the element in the array, or null if not found.
  81033. */
  81034. getIndex: function (location, name) {
  81035. for (var i = 0; i < location.length; i++)
  81036. {
  81037. if (location[i].name === name)
  81038. {
  81039. return i;
  81040. }
  81041. }
  81042. return null;
  81043. },
  81044. /**
  81045. * Gets the layer index based on its name.
  81046. *
  81047. * @method Phaser.Tilemap#getLayerIndex
  81048. * @param {string} name - The name of the layer to get.
  81049. * @return {number} The index of the layer in this tilemap, or null if not found.
  81050. */
  81051. getLayerIndex: function (name) {
  81052. return this.getIndex(this.layers, name);
  81053. },
  81054. /**
  81055. * Gets the tileset index based on its name.
  81056. *
  81057. * @method Phaser.Tilemap#getTilesetIndex
  81058. * @param {string} name - The name of the tileset to get.
  81059. * @return {number} The index of the tileset in this tilemap, or null if not found.
  81060. */
  81061. getTilesetIndex: function (name) {
  81062. return this.getIndex(this.tilesets, name);
  81063. },
  81064. /**
  81065. * Gets the image index based on its name.
  81066. *
  81067. * @method Phaser.Tilemap#getImageIndex
  81068. * @param {string} name - The name of the image to get.
  81069. * @return {number} The index of the image in this tilemap, or null if not found.
  81070. */
  81071. getImageIndex: function (name) {
  81072. return this.getIndex(this.images, name);
  81073. },
  81074. /**
  81075. * Sets a global collision callback for the given tile index within the layer. This will affect all tiles on this layer that have the same index.
  81076. * If a callback is already set for the tile index it will be replaced. Set the callback to null to remove it.
  81077. * If you want to set a callback for a tile at a specific location on the map then see setTileLocationCallback.
  81078. *
  81079. * Return `true` from the callback to continue separating the tile and colliding object, or `false` to cancel the collision for the current tile (see {@link Phaser.Physics.Arcade#separateTile}).
  81080. *
  81081. * @method Phaser.Tilemap#setTileIndexCallback
  81082. * @param {number|array} indexes - Either a single tile index, or an array of tile indexes to have a collision callback set for.
  81083. * @param {function} callback - The callback that will be invoked when the tile is collided with (via {@link Phaser.Physics.Arcade#collide}).
  81084. * @param {object} callbackContext - The context under which the callback is called.
  81085. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
  81086. */
  81087. setTileIndexCallback: function (indexes, callback, callbackContext, layer) {
  81088. layer = this.getLayer(layer);
  81089. if (typeof indexes === 'number')
  81090. {
  81091. if (callback === null)
  81092. {
  81093. delete this.layers[layer].callbacks[indexes];
  81094. }
  81095. else
  81096. {
  81097. // This may seem a bit wasteful, because it will cause empty array elements to be created, but the look-up cost is much
  81098. // less than having to iterate through the callbacks array hunting down tile indexes each frame, so I'll take the small memory hit.
  81099. this.layers[layer].callbacks[indexes] = { callback: callback, callbackContext: callbackContext };
  81100. }
  81101. }
  81102. else
  81103. {
  81104. for (var i = 0, len = indexes.length; i < len; i++)
  81105. {
  81106. if (callback === null)
  81107. {
  81108. delete this.layers[layer].callbacks[indexes[i]];
  81109. }
  81110. else
  81111. {
  81112. this.layers[layer].callbacks[indexes[i]] = { callback: callback, callbackContext: callbackContext };
  81113. }
  81114. }
  81115. }
  81116. },
  81117. /**
  81118. * Sets a global collision callback for the given map location within the layer. This will affect all tiles on this layer found in the given area.
  81119. * If a callback is already set for the tile index it will be replaced. Set the callback to null to remove it.
  81120. * If you want to set a callback for a tile at a specific location on the map then see setTileLocationCallback.
  81121. *
  81122. * Return `true` from the callback to continue separating the tile and colliding object, or `false` to cancel the collision for the current tile (see {@link Phaser.Physics.Arcade#separateTile}).
  81123. *
  81124. * @method Phaser.Tilemap#setTileLocationCallback
  81125. * @param {number} x - X position of the top left of the area to copy (given in tiles, not pixels)
  81126. * @param {number} y - Y position of the top left of the area to copy (given in tiles, not pixels)
  81127. * @param {number} width - The width of the area to copy (given in tiles, not pixels)
  81128. * @param {number} height - The height of the area to copy (given in tiles, not pixels)
  81129. * @param {function} callback - The callback that will be invoked when the tile is collided with (via {@link Phaser.Physics.Arcade#collide}).
  81130. * @param {object} callbackContext - The context under which the callback is called.
  81131. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
  81132. */
  81133. setTileLocationCallback: function (x, y, width, height, callback, callbackContext, layer) {
  81134. layer = this.getLayer(layer);
  81135. this.copy(x, y, width, height, layer);
  81136. if (this._results.length < 2)
  81137. {
  81138. return;
  81139. }
  81140. for (var i = 1; i < this._results.length; i++)
  81141. {
  81142. this._results[i].setCollisionCallback(callback, callbackContext);
  81143. }
  81144. },
  81145. /**
  81146. * Sets collision on the given tile or tiles. You can pass in either a single numeric index or an array of indexes: [2, 3, 15, 20].
  81147. * The `collides` parameter controls if collision will be enabled (true) or disabled (false).
  81148. *
  81149. * Collision-enabled tiles can be collided against Sprites using {@link Phaser.Physics.Arcade#collide}.
  81150. *
  81151. * @method Phaser.Tilemap#setCollision
  81152. * @param {number|array} indexes - Either a single tile index, or an array of tile IDs to be checked for collision.
  81153. * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision.
  81154. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
  81155. * @param {boolean} [recalculate=true] - Recalculates the tile faces after the update.
  81156. */
  81157. setCollision: function (indexes, collides, layer, recalculate) {
  81158. if (collides === undefined) { collides = true; }
  81159. if (recalculate === undefined) { recalculate = true; }
  81160. layer = this.getLayer(layer);
  81161. if (typeof indexes === 'number')
  81162. {
  81163. return this.setCollisionByIndex(indexes, collides, layer, true);
  81164. }
  81165. else if (Array.isArray(indexes))
  81166. {
  81167. // Collide all of the IDs given in the indexes array
  81168. for (var i = 0; i < indexes.length; i++)
  81169. {
  81170. this.setCollisionByIndex(indexes[i], collides, layer, false);
  81171. }
  81172. if (recalculate)
  81173. {
  81174. // Now re-calculate interesting faces
  81175. this.calculateFaces(layer);
  81176. }
  81177. }
  81178. },
  81179. /**
  81180. * Sets collision on a range of tiles where the tile IDs increment sequentially.
  81181. * Calling this with a start value of 10 and a stop value of 14 would set collision for tiles 10, 11, 12, 13 and 14.
  81182. * The `collides` parameter controls if collision will be enabled (true) or disabled (false).
  81183. *
  81184. * @method Phaser.Tilemap#setCollisionBetween
  81185. * @param {number} start - The first index of the tile to be set for collision.
  81186. * @param {number} stop - The last index of the tile to be set for collision.
  81187. * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision.
  81188. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
  81189. * @param {boolean} [recalculate=true] - Recalculates the tile faces after the update.
  81190. */
  81191. setCollisionBetween: function (start, stop, collides, layer, recalculate) {
  81192. if (collides === undefined) { collides = true; }
  81193. if (recalculate === undefined) { recalculate = true; }
  81194. layer = this.getLayer(layer);
  81195. if (start > stop)
  81196. {
  81197. return;
  81198. }
  81199. for (var index = start; index <= stop; index++)
  81200. {
  81201. this.setCollisionByIndex(index, collides, layer, false);
  81202. }
  81203. if (recalculate)
  81204. {
  81205. // Now re-calculate interesting faces
  81206. this.calculateFaces(layer);
  81207. }
  81208. },
  81209. /**
  81210. * Sets collision on all tiles in the given layer, except for the IDs of those in the given array.
  81211. * The `collides` parameter controls if collision will be enabled (true) or disabled (false).
  81212. *
  81213. * @method Phaser.Tilemap#setCollisionByExclusion
  81214. * @param {array} indexes - An array of the tile IDs to not be counted for collision.
  81215. * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision.
  81216. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
  81217. * @param {boolean} [recalculate=true] - Recalculates the tile faces after the update.
  81218. */
  81219. setCollisionByExclusion: function (indexes, collides, layer, recalculate) {
  81220. if (collides === undefined) { collides = true; }
  81221. if (recalculate === undefined) { recalculate = true; }
  81222. layer = this.getLayer(layer);
  81223. // Collide everything, except the IDs given in the indexes array
  81224. for (var i = 0, len = this.tiles.length; i < len; i++)
  81225. {
  81226. if (indexes.indexOf(i) === -1)
  81227. {
  81228. this.setCollisionByIndex(i, collides, layer, false);
  81229. }
  81230. }
  81231. if (recalculate)
  81232. {
  81233. // Now re-calculate interesting faces
  81234. this.calculateFaces(layer);
  81235. }
  81236. },
  81237. /**
  81238. * Sets collision values on a tile in the set.
  81239. * You shouldn't usually call this method directly, instead use setCollision, setCollisionBetween or setCollisionByExclusion.
  81240. *
  81241. * @method Phaser.Tilemap#setCollisionByIndex
  81242. * @protected
  81243. * @param {number} index - The index of the tile on the layer.
  81244. * @param {boolean} [collides=true] - If true it will enable collision on the tile. If false it will clear collision values from the tile.
  81245. * @param {number} [layer] - The layer to operate on. If not given will default to this.currentLayer.
  81246. * @param {boolean} [recalculate=true] - Recalculates the tile faces after the update.
  81247. */
  81248. setCollisionByIndex: function (index, collides, layer, recalculate) {
  81249. if (collides === undefined) { collides = true; }
  81250. if (layer === undefined) { layer = this.currentLayer; }
  81251. if (recalculate === undefined) { recalculate = true; }
  81252. if (collides)
  81253. {
  81254. this.collideIndexes.push(index);
  81255. }
  81256. else
  81257. {
  81258. var i = this.collideIndexes.indexOf(index);
  81259. if (i > -1)
  81260. {
  81261. this.collideIndexes.splice(i, 1);
  81262. }
  81263. }
  81264. for (var y = 0; y < this.layers[layer].height; y++)
  81265. {
  81266. for (var x = 0; x < this.layers[layer].width; x++)
  81267. {
  81268. var tile = this.layers[layer].data[y][x];
  81269. if (tile && tile.index === index)
  81270. {
  81271. if (collides)
  81272. {
  81273. tile.setCollision(true, true, true, true);
  81274. }
  81275. else
  81276. {
  81277. tile.resetCollision();
  81278. }
  81279. tile.faceTop = collides;
  81280. tile.faceBottom = collides;
  81281. tile.faceLeft = collides;
  81282. tile.faceRight = collides;
  81283. }
  81284. }
  81285. }
  81286. if (recalculate)
  81287. {
  81288. // Now re-calculate interesting faces
  81289. this.calculateFaces(layer);
  81290. }
  81291. return layer;
  81292. },
  81293. /**
  81294. * Gets the TilemapLayer index as used in the setCollision calls.
  81295. *
  81296. * @method Phaser.Tilemap#getLayer
  81297. * @protected
  81298. * @param {number|string|Phaser.TilemapLayer} layer - The layer to operate on. If not given will default to this.currentLayer.
  81299. * @return {number} The TilemapLayer index.
  81300. */
  81301. getLayer: function (layer) {
  81302. if (layer === undefined)
  81303. {
  81304. layer = this.currentLayer;
  81305. }
  81306. else if (typeof layer === 'string')
  81307. {
  81308. layer = this.getLayerIndex(layer);
  81309. }
  81310. else if (layer instanceof Phaser.TilemapLayer)
  81311. {
  81312. layer = layer.index;
  81313. }
  81314. return layer;
  81315. },
  81316. /**
  81317. * Turn off/on the recalculation of faces for tile or collision updates.
  81318. * `setPreventRecalculate(true)` puts recalculation on hold while `setPreventRecalculate(false)` recalculates all the changed layers.
  81319. *
  81320. * @method Phaser.Tilemap#setPreventRecalculate
  81321. * @param {boolean} value - If true it will put the recalculation on hold.
  81322. */
  81323. setPreventRecalculate: function (value) {
  81324. if (value === true && this.preventingRecalculate !== true)
  81325. {
  81326. this.preventingRecalculate = true;
  81327. this.needToRecalculate = {};
  81328. }
  81329. if (value === false && this.preventingRecalculate === true)
  81330. {
  81331. this.preventingRecalculate = false;
  81332. for (var i in this.needToRecalculate)
  81333. {
  81334. this.calculateFaces(i);
  81335. }
  81336. this.needToRecalculate = false;
  81337. }
  81338. },
  81339. /**
  81340. * Internal function.
  81341. *
  81342. * @method Phaser.Tilemap#calculateFaces
  81343. * @protected
  81344. * @param {number} layer - The index of the TilemapLayer to operate on.
  81345. */
  81346. calculateFaces: function (layer) {
  81347. if (this.preventingRecalculate)
  81348. {
  81349. this.needToRecalculate[layer] = true;
  81350. return;
  81351. }
  81352. var above = null;
  81353. var below = null;
  81354. var left = null;
  81355. var right = null;
  81356. for (var y = 0, h = this.layers[layer].height; y < h; y++)
  81357. {
  81358. for (var x = 0, w = this.layers[layer].width; x < w; x++)
  81359. {
  81360. var tile = this.layers[layer].data[y][x];
  81361. if (tile)
  81362. {
  81363. above = this.getTileAbove(layer, x, y);
  81364. below = this.getTileBelow(layer, x, y);
  81365. left = this.getTileLeft(layer, x, y);
  81366. right = this.getTileRight(layer, x, y);
  81367. if (tile.collides)
  81368. {
  81369. tile.faceTop = true;
  81370. tile.faceBottom = true;
  81371. tile.faceLeft = true;
  81372. tile.faceRight = true;
  81373. }
  81374. if (above && above.collides)
  81375. {
  81376. // There is a tile above this one that also collides, so the top of this tile is no longer interesting
  81377. tile.faceTop = false;
  81378. }
  81379. if (below && below.collides)
  81380. {
  81381. // There is a tile below this one that also collides, so the bottom of this tile is no longer interesting
  81382. tile.faceBottom = false;
  81383. }
  81384. if (left && left.collides)
  81385. {
  81386. // There is a tile left this one that also collides, so the left of this tile is no longer interesting
  81387. tile.faceLeft = false;
  81388. }
  81389. if (right && right.collides)
  81390. {
  81391. // There is a tile right this one that also collides, so the right of this tile is no longer interesting
  81392. tile.faceRight = false;
  81393. }
  81394. }
  81395. }
  81396. }
  81397. },
  81398. /**
  81399. * Gets the tile above the tile coordinates given.
  81400. * Mostly used as an internal function by calculateFaces.
  81401. *
  81402. * @method Phaser.Tilemap#getTileAbove
  81403. * @param {number} layer - The local layer index to get the tile from. Can be determined by Tilemap.getLayer().
  81404. * @param {number} x - The x coordinate to get the tile from. In tiles, not pixels.
  81405. * @param {number} y - The y coordinate to get the tile from. In tiles, not pixels.
  81406. */
  81407. getTileAbove: function (layer, x, y) {
  81408. if (y > 0)
  81409. {
  81410. return this.layers[layer].data[y - 1][x];
  81411. }
  81412. return null;
  81413. },
  81414. /**
  81415. * Gets the tile below the tile coordinates given.
  81416. * Mostly used as an internal function by calculateFaces.
  81417. *
  81418. * @method Phaser.Tilemap#getTileBelow
  81419. * @param {number} layer - The local layer index to get the tile from. Can be determined by Tilemap.getLayer().
  81420. * @param {number} x - The x coordinate to get the tile from. In tiles, not pixels.
  81421. * @param {number} y - The y coordinate to get the tile from. In tiles, not pixels.
  81422. */
  81423. getTileBelow: function (layer, x, y) {
  81424. if (y < this.layers[layer].height - 1)
  81425. {
  81426. return this.layers[layer].data[y + 1][x];
  81427. }
  81428. return null;
  81429. },
  81430. /**
  81431. * Gets the tile to the left of the tile coordinates given.
  81432. * Mostly used as an internal function by calculateFaces.
  81433. *
  81434. * @method Phaser.Tilemap#getTileLeft
  81435. * @param {number} layer - The local layer index to get the tile from. Can be determined by Tilemap.getLayer().
  81436. * @param {number} x - The x coordinate to get the tile from. In tiles, not pixels.
  81437. * @param {number} y - The y coordinate to get the tile from. In tiles, not pixels.
  81438. */
  81439. getTileLeft: function (layer, x, y) {
  81440. if (x > 0)
  81441. {
  81442. return this.layers[layer].data[y][x - 1];
  81443. }
  81444. return null;
  81445. },
  81446. /**
  81447. * Gets the tile to the right of the tile coordinates given.
  81448. * Mostly used as an internal function by calculateFaces.
  81449. *
  81450. * @method Phaser.Tilemap#getTileRight
  81451. * @param {number} layer - The local layer index to get the tile from. Can be determined by Tilemap.getLayer().
  81452. * @param {number} x - The x coordinate to get the tile from. In tiles, not pixels.
  81453. * @param {number} y - The y coordinate to get the tile from. In tiles, not pixels.
  81454. */
  81455. getTileRight: function (layer, x, y) {
  81456. if (x < this.layers[layer].width - 1)
  81457. {
  81458. return this.layers[layer].data[y][x + 1];
  81459. }
  81460. return null;
  81461. },
  81462. /**
  81463. * Sets the current layer to the given index.
  81464. *
  81465. * @method Phaser.Tilemap#setLayer
  81466. * @param {number|string|Phaser.TilemapLayer} layer - The layer to set as current.
  81467. */
  81468. setLayer: function (layer) {
  81469. layer = this.getLayer(layer);
  81470. if (this.layers[layer])
  81471. {
  81472. this.currentLayer = layer;
  81473. }
  81474. },
  81475. /**
  81476. * Checks if there is a tile at the given location.
  81477. *
  81478. * @method Phaser.Tilemap#hasTile
  81479. * @param {number} x - X position to check if a tile exists at (given in tile units, not pixels)
  81480. * @param {number} y - Y position to check if a tile exists at (given in tile units, not pixels)
  81481. * @param {number|string|Phaser.TilemapLayer} layer - The layer to set as current.
  81482. * @return {boolean} True if there is a tile at the given location, otherwise false.
  81483. */
  81484. hasTile: function (x, y, layer) {
  81485. layer = this.getLayer(layer);
  81486. if (this.layers[layer].data[y] === undefined || this.layers[layer].data[y][x] === undefined)
  81487. {
  81488. return false;
  81489. }
  81490. return (this.layers[layer].data[y][x].index > -1);
  81491. },
  81492. /**
  81493. * Removes the tile located at the given coordinates and updates the collision data.
  81494. *
  81495. * @method Phaser.Tilemap#removeTile
  81496. * @param {number} x - X position to place the tile (given in tile units, not pixels)
  81497. * @param {number} y - Y position to place the tile (given in tile units, not pixels)
  81498. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to modify.
  81499. * @return {Phaser.Tile} The Tile object that was removed from this map.
  81500. */
  81501. removeTile: function (x, y, layer) {
  81502. layer = this.getLayer(layer);
  81503. if (x >= 0 && x < this.layers[layer].width && y >= 0 && y < this.layers[layer].height)
  81504. {
  81505. if (this.hasTile(x, y, layer))
  81506. {
  81507. var tile = this.layers[layer].data[y][x];
  81508. this.layers[layer].data[y][x] = new Phaser.Tile(this.layers[layer], -1, x, y, this.tileWidth, this.tileHeight);
  81509. this.layers[layer].dirty = true;
  81510. this.calculateFaces(layer);
  81511. return tile;
  81512. }
  81513. }
  81514. },
  81515. /**
  81516. * Removes the tile located at the given coordinates and updates the collision data. The coordinates are given in pixel values.
  81517. *
  81518. * @method Phaser.Tilemap#removeTileWorldXY
  81519. * @param {number} x - X position to insert the tile (given in pixels)
  81520. * @param {number} y - Y position to insert the tile (given in pixels)
  81521. * @param {number} tileWidth - The width of the tile in pixels.
  81522. * @param {number} tileHeight - The height of the tile in pixels.
  81523. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to modify.
  81524. * @return {Phaser.Tile} The Tile object that was removed from this map.
  81525. */
  81526. removeTileWorldXY: function (x, y, tileWidth, tileHeight, layer) {
  81527. layer = this.getLayer(layer);
  81528. x = this.game.math.snapToFloor(x, tileWidth) / tileWidth;
  81529. y = this.game.math.snapToFloor(y, tileHeight) / tileHeight;
  81530. return this.removeTile(x, y, layer);
  81531. },
  81532. /**
  81533. * Puts a tile of the given index value at the coordinate specified.
  81534. * If you pass `null` as the tile it will pass your call over to Tilemap.removeTile instead.
  81535. *
  81536. * @method Phaser.Tilemap#putTile
  81537. * @param {Phaser.Tile|number|null} tile - The index of this tile to set or a Phaser.Tile object. If null the tile is removed from the map.
  81538. * @param {number} x - X position to place the tile (given in tile units, not pixels)
  81539. * @param {number} y - Y position to place the tile (given in tile units, not pixels)
  81540. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to modify.
  81541. * @return {Phaser.Tile} The Tile object that was created or added to this map.
  81542. */
  81543. putTile: function (tile, x, y, layer) {
  81544. if (tile === null)
  81545. {
  81546. return this.removeTile(x, y, layer);
  81547. }
  81548. layer = this.getLayer(layer);
  81549. if (x >= 0 && x < this.layers[layer].width && y >= 0 && y < this.layers[layer].height)
  81550. {
  81551. var index;
  81552. if (tile instanceof Phaser.Tile)
  81553. {
  81554. index = tile.index;
  81555. if (this.hasTile(x, y, layer))
  81556. {
  81557. this.layers[layer].data[y][x].copy(tile);
  81558. }
  81559. else
  81560. {
  81561. this.layers[layer].data[y][x] = new Phaser.Tile(layer, index, x, y, tile.width, tile.height);
  81562. }
  81563. }
  81564. else
  81565. {
  81566. index = tile;
  81567. if (this.hasTile(x, y, layer))
  81568. {
  81569. this.layers[layer].data[y][x].index = index;
  81570. }
  81571. else
  81572. {
  81573. this.layers[layer].data[y][x] = new Phaser.Tile(this.layers[layer], index, x, y, this.tileWidth, this.tileHeight);
  81574. }
  81575. }
  81576. if (this.collideIndexes.indexOf(index) > -1)
  81577. {
  81578. this.layers[layer].data[y][x].setCollision(true, true, true, true);
  81579. }
  81580. else
  81581. {
  81582. this.layers[layer].data[y][x].resetCollision();
  81583. }
  81584. this.layers[layer].dirty = true;
  81585. this.calculateFaces(layer);
  81586. return this.layers[layer].data[y][x];
  81587. }
  81588. return null;
  81589. },
  81590. /**
  81591. * Puts a tile into the Tilemap layer. The coordinates are given in pixel values.
  81592. *
  81593. * @method Phaser.Tilemap#putTileWorldXY
  81594. * @param {Phaser.Tile|number} tile - The index of this tile to set or a Phaser.Tile object.
  81595. * @param {number} x - X position to insert the tile (given in pixels)
  81596. * @param {number} y - Y position to insert the tile (given in pixels)
  81597. * @param {number} tileWidth - The width of the tile in pixels.
  81598. * @param {number} tileHeight - The height of the tile in pixels.
  81599. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to modify.
  81600. * @return {Phaser.Tile} The Tile object that was created or added to this map.
  81601. */
  81602. putTileWorldXY: function (tile, x, y, tileWidth, tileHeight, layer) {
  81603. layer = this.getLayer(layer);
  81604. x = this.game.math.snapToFloor(x, tileWidth) / tileWidth;
  81605. y = this.game.math.snapToFloor(y, tileHeight) / tileHeight;
  81606. return this.putTile(tile, x, y, layer);
  81607. },
  81608. /**
  81609. * Searches the entire map layer for the first tile matching the given index, then returns that Phaser.Tile object.
  81610. * If no match is found it returns null.
  81611. * The search starts from the top-left tile and continues horizontally until it hits the end of the row, then it drops down to the next column.
  81612. * If the reverse boolean is true, it scans starting from the bottom-right corner traveling up to the top-left.
  81613. *
  81614. * @method Phaser.Tilemap#searchTileIndex
  81615. * @param {number} index - The tile index value to search for.
  81616. * @param {number} [skip=0] - The number of times to skip a matching tile before returning.
  81617. * @param {number} [reverse=false] - If true it will scan the layer in reverse, starting at the bottom-right. Otherwise it scans from the top-left.
  81618. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to get the tile from.
  81619. * @return {Phaser.Tile} The first (or n skipped) tile with the matching index.
  81620. */
  81621. searchTileIndex: function (index, skip, reverse, layer) {
  81622. if (skip === undefined) { skip = 0; }
  81623. if (reverse === undefined) { reverse = false; }
  81624. layer = this.getLayer(layer);
  81625. var c = 0;
  81626. if (reverse)
  81627. {
  81628. for (var y = this.layers[layer].height - 1; y >= 0; y--)
  81629. {
  81630. for (var x = this.layers[layer].width - 1; x >= 0; x--)
  81631. {
  81632. if (this.layers[layer].data[y][x].index === index)
  81633. {
  81634. if (c === skip)
  81635. {
  81636. return this.layers[layer].data[y][x];
  81637. }
  81638. else
  81639. {
  81640. c++;
  81641. }
  81642. }
  81643. }
  81644. }
  81645. }
  81646. else
  81647. {
  81648. for (var y = 0; y < this.layers[layer].height; y++)
  81649. {
  81650. for (var x = 0; x < this.layers[layer].width; x++)
  81651. {
  81652. if (this.layers[layer].data[y][x].index === index)
  81653. {
  81654. if (c === skip)
  81655. {
  81656. return this.layers[layer].data[y][x];
  81657. }
  81658. else
  81659. {
  81660. c++;
  81661. }
  81662. }
  81663. }
  81664. }
  81665. }
  81666. return null;
  81667. },
  81668. /**
  81669. * Gets a tile from the Tilemap Layer. The coordinates are given in tile values.
  81670. *
  81671. * @method Phaser.Tilemap#getTile
  81672. * @param {number} x - X position to get the tile from (given in tile units, not pixels)
  81673. * @param {number} y - Y position to get the tile from (given in tile units, not pixels)
  81674. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to get the tile from.
  81675. * @param {boolean} [nonNull=false] - If true getTile won't return null for empty tiles, but a Tile object with an index of -1.
  81676. * @return {Phaser.Tile} The tile at the given coordinates or null if no tile was found or the coordinates were invalid.
  81677. */
  81678. getTile: function (x, y, layer, nonNull) {
  81679. if (nonNull === undefined) { nonNull = false; }
  81680. layer = this.getLayer(layer);
  81681. if (x >= 0 && x < this.layers[layer].width && y >= 0 && y < this.layers[layer].height)
  81682. {
  81683. if (this.layers[layer].data[y][x].index === -1)
  81684. {
  81685. if (nonNull)
  81686. {
  81687. return this.layers[layer].data[y][x];
  81688. }
  81689. else
  81690. {
  81691. return null;
  81692. }
  81693. }
  81694. else
  81695. {
  81696. return this.layers[layer].data[y][x];
  81697. }
  81698. }
  81699. else
  81700. {
  81701. return null;
  81702. }
  81703. },
  81704. /**
  81705. * Gets a tile from the Tilemap layer. The coordinates are given in pixel values.
  81706. *
  81707. * @method Phaser.Tilemap#getTileWorldXY
  81708. * @param {number} x - X position to get the tile from (given in pixels)
  81709. * @param {number} y - Y position to get the tile from (given in pixels)
  81710. * @param {number} [tileWidth] - The width of the tiles. If not given the map default is used.
  81711. * @param {number} [tileHeight] - The height of the tiles. If not given the map default is used.
  81712. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to get the tile from.
  81713. * @param {boolean} [nonNull=false] - If true getTile won't return null for empty tiles, but a Tile object with an index of -1.
  81714. * @return {Phaser.Tile} The tile at the given coordinates.
  81715. */
  81716. getTileWorldXY: function (x, y, tileWidth, tileHeight, layer, nonNull) {
  81717. if (tileWidth === undefined) { tileWidth = this.tileWidth; }
  81718. if (tileHeight === undefined) { tileHeight = this.tileHeight; }
  81719. layer = this.getLayer(layer);
  81720. x = this.game.math.snapToFloor(x, tileWidth) / tileWidth;
  81721. y = this.game.math.snapToFloor(y, tileHeight) / tileHeight;
  81722. return this.getTile(x, y, layer, nonNull);
  81723. },
  81724. /**
  81725. * Copies all of the tiles in the given rectangular block into the tilemap data buffer.
  81726. *
  81727. * @method Phaser.Tilemap#copy
  81728. * @param {integer} x - X position of the top left of the area to copy (given in tiles, not pixels)
  81729. * @param {integer} y - Y position of the top left of the area to copy (given in tiles, not pixels)
  81730. * @param {integer} width - The width of the area to copy (given in tiles, not pixels)
  81731. * @param {integer} height - The height of the area to copy (given in tiles, not pixels)
  81732. * @param {integer|string|Phaser.TilemapLayer} [layer] - The layer to copy the tiles from.
  81733. * @return {array} An array of the tiles that were copied.
  81734. */
  81735. copy: function (x, y, width, height, layer) {
  81736. layer = this.getLayer(layer);
  81737. if (!this.layers[layer])
  81738. {
  81739. this._results.length = 0;
  81740. return;
  81741. }
  81742. if (x === undefined) { x = 0; }
  81743. if (y === undefined) { y = 0; }
  81744. if (width === undefined) { width = this.layers[layer].width; }
  81745. if (height === undefined) { height = this.layers[layer].height; }
  81746. if (x < 0)
  81747. {
  81748. x = 0;
  81749. }
  81750. if (y < 0)
  81751. {
  81752. y = 0;
  81753. }
  81754. if (width > this.layers[layer].width)
  81755. {
  81756. width = this.layers[layer].width;
  81757. }
  81758. if (height > this.layers[layer].height)
  81759. {
  81760. height = this.layers[layer].height;
  81761. }
  81762. this._results.length = 0;
  81763. this._results.push({ x: x, y: y, width: width, height: height, layer: layer });
  81764. for (var ty = y; ty < y + height; ty++)
  81765. {
  81766. for (var tx = x; tx < x + width; tx++)
  81767. {
  81768. this._results.push(this.layers[layer].data[ty][tx]);
  81769. }
  81770. }
  81771. return this._results;
  81772. },
  81773. /**
  81774. * Pastes a previously copied block of tile data into the given x/y coordinates. Data should have been prepared with Tilemap.copy.
  81775. *
  81776. * @method Phaser.Tilemap#paste
  81777. * @param {number} x - X position of the top left of the area to paste to (given in tiles, not pixels)
  81778. * @param {number} y - Y position of the top left of the area to paste to (given in tiles, not pixels)
  81779. * @param {array} tileblock - The block of tiles to paste.
  81780. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to paste the tiles into.
  81781. */
  81782. paste: function (x, y, tileblock, layer) {
  81783. if (x === undefined) { x = 0; }
  81784. if (y === undefined) { y = 0; }
  81785. layer = this.getLayer(layer);
  81786. if (!tileblock || tileblock.length < 2)
  81787. {
  81788. return;
  81789. }
  81790. // Find out the difference between tileblock[1].x/y and x/y and use it as an offset, as it's the top left of the block to paste
  81791. var diffX = x - tileblock[1].x;
  81792. var diffY = y - tileblock[1].y;
  81793. for (var i = 1; i < tileblock.length; i++)
  81794. {
  81795. this.layers[layer].data[ diffY + tileblock[i].y ][ diffX + tileblock[i].x ].copy(tileblock[i]);
  81796. }
  81797. this.layers[layer].dirty = true;
  81798. this.calculateFaces(layer);
  81799. },
  81800. /**
  81801. * Scans the given area for tiles with an index matching tileA and swaps them with tileB.
  81802. *
  81803. * @method Phaser.Tilemap#swap
  81804. * @param {number} tileA - First tile index.
  81805. * @param {number} tileB - Second tile index.
  81806. * @param {number} x - X position of the top left of the area to operate one, given in tiles, not pixels.
  81807. * @param {number} y - Y position of the top left of the area to operate one, given in tiles, not pixels.
  81808. * @param {number} width - The width in tiles of the area to operate on.
  81809. * @param {number} height - The height in tiles of the area to operate on.
  81810. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on.
  81811. */
  81812. swap: function (tileA, tileB, x, y, width, height, layer) {
  81813. layer = this.getLayer(layer);
  81814. this.copy(x, y, width, height, layer);
  81815. if (this._results.length < 2)
  81816. {
  81817. return;
  81818. }
  81819. this._tempA = tileA;
  81820. this._tempB = tileB;
  81821. this._results.forEach(this.swapHandler, this);
  81822. this.paste(x, y, this._results, layer);
  81823. },
  81824. /**
  81825. * Internal function that handles the swapping of tiles.
  81826. *
  81827. * @method Phaser.Tilemap#swapHandler
  81828. * @private
  81829. * @param {number} value
  81830. */
  81831. swapHandler: function (value) {
  81832. if (value.index === this._tempA)
  81833. {
  81834. // Swap A with B
  81835. value.index = this._tempB;
  81836. }
  81837. else if (value.index === this._tempB)
  81838. {
  81839. // Swap B with A
  81840. value.index = this._tempA;
  81841. }
  81842. },
  81843. /**
  81844. * For each tile in the given area defined by x/y and width/height run the given callback.
  81845. *
  81846. * @method Phaser.Tilemap#forEach
  81847. * @param {number} callback - The callback. Each tile in the given area will be passed to this callback as the first and only parameter.
  81848. * @param {number} context - The context under which the callback should be run.
  81849. * @param {number} x - X position of the top left of the area to operate one, given in tiles, not pixels.
  81850. * @param {number} y - Y position of the top left of the area to operate one, given in tiles, not pixels.
  81851. * @param {number} width - The width in tiles of the area to operate on.
  81852. * @param {number} height - The height in tiles of the area to operate on.
  81853. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on.
  81854. */
  81855. forEach: function (callback, context, x, y, width, height, layer) {
  81856. layer = this.getLayer(layer);
  81857. this.copy(x, y, width, height, layer);
  81858. if (this._results.length < 2)
  81859. {
  81860. return;
  81861. }
  81862. this._results.forEach(callback, context);
  81863. this.paste(x, y, this._results, layer);
  81864. },
  81865. /**
  81866. * Scans the given area for tiles with an index matching `source` and updates their index to match `dest`.
  81867. *
  81868. * @method Phaser.Tilemap#replace
  81869. * @param {number} source - The tile index value to scan for.
  81870. * @param {number} dest - The tile index value to replace found tiles with.
  81871. * @param {number} x - X position of the top left of the area to operate one, given in tiles, not pixels.
  81872. * @param {number} y - Y position of the top left of the area to operate one, given in tiles, not pixels.
  81873. * @param {number} width - The width in tiles of the area to operate on.
  81874. * @param {number} height - The height in tiles of the area to operate on.
  81875. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on.
  81876. */
  81877. replace: function (source, dest, x, y, width, height, layer) {
  81878. layer = this.getLayer(layer);
  81879. this.copy(x, y, width, height, layer);
  81880. if (this._results.length < 2)
  81881. {
  81882. return;
  81883. }
  81884. for (var i = 1; i < this._results.length; i++)
  81885. {
  81886. if (this._results[i].index === source)
  81887. {
  81888. this._results[i].index = dest;
  81889. }
  81890. }
  81891. this.paste(x, y, this._results, layer);
  81892. },
  81893. /**
  81894. * Randomises a set of tiles in a given area.
  81895. *
  81896. * @method Phaser.Tilemap#random
  81897. * @param {number} x - X position of the top left of the area to operate one, given in tiles, not pixels.
  81898. * @param {number} y - Y position of the top left of the area to operate one, given in tiles, not pixels.
  81899. * @param {number} width - The width in tiles of the area to operate on.
  81900. * @param {number} height - The height in tiles of the area to operate on.
  81901. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on.
  81902. */
  81903. random: function (x, y, width, height, layer) {
  81904. layer = this.getLayer(layer);
  81905. this.copy(x, y, width, height, layer);
  81906. if (this._results.length < 2)
  81907. {
  81908. return;
  81909. }
  81910. var indexes = [];
  81911. for (var t = 1; t < this._results.length; t++)
  81912. {
  81913. if (this._results[t].index)
  81914. {
  81915. var idx = this._results[t].index;
  81916. if (indexes.indexOf(idx) === -1)
  81917. {
  81918. indexes.push(idx);
  81919. }
  81920. }
  81921. }
  81922. for (var i = 1; i < this._results.length; i++)
  81923. {
  81924. this._results[i].index = this.game.rnd.pick(indexes);
  81925. }
  81926. this.paste(x, y, this._results, layer);
  81927. },
  81928. /**
  81929. * Shuffles a set of tiles in a given area. It will only randomise the tiles in that area, so if they're all the same nothing will appear to have changed!
  81930. *
  81931. * @method Phaser.Tilemap#shuffle
  81932. * @param {number} x - X position of the top left of the area to operate one, given in tiles, not pixels.
  81933. * @param {number} y - Y position of the top left of the area to operate one, given in tiles, not pixels.
  81934. * @param {number} width - The width in tiles of the area to operate on.
  81935. * @param {number} height - The height in tiles of the area to operate on.
  81936. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on.
  81937. */
  81938. shuffle: function (x, y, width, height, layer) {
  81939. layer = this.getLayer(layer);
  81940. this.copy(x, y, width, height, layer);
  81941. if (this._results.length < 2)
  81942. {
  81943. return;
  81944. }
  81945. var indexes = [];
  81946. for (var t = 1; t < this._results.length; t++)
  81947. {
  81948. if (this._results[t].index)
  81949. {
  81950. indexes.push(this._results[t].index);
  81951. }
  81952. }
  81953. Phaser.ArrayUtils.shuffle(indexes);
  81954. for (var i = 1; i < this._results.length; i++)
  81955. {
  81956. this._results[i].index = indexes[i - 1];
  81957. }
  81958. this.paste(x, y, this._results, layer);
  81959. },
  81960. /**
  81961. * Fills the given area with the specified tile.
  81962. *
  81963. * @method Phaser.Tilemap#fill
  81964. * @param {number} index - The index of the tile that the area will be filled with.
  81965. * @param {number} x - X position of the top left of the area to operate one, given in tiles, not pixels.
  81966. * @param {number} y - Y position of the top left of the area to operate one, given in tiles, not pixels.
  81967. * @param {number} width - The width in tiles of the area to operate on.
  81968. * @param {number} height - The height in tiles of the area to operate on.
  81969. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on.
  81970. */
  81971. fill: function (index, x, y, width, height, layer) {
  81972. layer = this.getLayer(layer);
  81973. this.copy(x, y, width, height, layer);
  81974. if (this._results.length < 2)
  81975. {
  81976. return;
  81977. }
  81978. for (var i = 1; i < this._results.length; i++)
  81979. {
  81980. this._results[i].index = index;
  81981. }
  81982. this.paste(x, y, this._results, layer);
  81983. },
  81984. /**
  81985. * Removes all layers from this tile map.
  81986. *
  81987. * @method Phaser.Tilemap#removeAllLayers
  81988. */
  81989. removeAllLayers: function () {
  81990. this.layers.length = 0;
  81991. this.currentLayer = 0;
  81992. },
  81993. /**
  81994. * Dumps the tilemap data out to the console.
  81995. *
  81996. * @method Phaser.Tilemap#dump
  81997. */
  81998. dump: function () {
  81999. var txt = '';
  82000. var args = [''];
  82001. for (var y = 0; y < this.layers[this.currentLayer].height; y++)
  82002. {
  82003. for (var x = 0; x < this.layers[this.currentLayer].width; x++)
  82004. {
  82005. txt += "%c ";
  82006. if (this.layers[this.currentLayer].data[y][x] > 1)
  82007. {
  82008. if (this.debugMap[this.layers[this.currentLayer].data[y][x]])
  82009. {
  82010. args.push("background: " + this.debugMap[this.layers[this.currentLayer].data[y][x]]);
  82011. }
  82012. else
  82013. {
  82014. args.push("background: #ffffff");
  82015. }
  82016. }
  82017. else
  82018. {
  82019. args.push("background: rgb(0, 0, 0)");
  82020. }
  82021. }
  82022. txt += "\n";
  82023. }
  82024. args[0] = txt;
  82025. console.log.apply(console, args);
  82026. },
  82027. /**
  82028. * Removes all layer data from this tile map and nulls the game reference.
  82029. * Note: You are responsible for destroying any TilemapLayer objects you generated yourself, as Tilemap doesn't keep a reference to them.
  82030. *
  82031. * @method Phaser.Tilemap#destroy
  82032. */
  82033. destroy: function () {
  82034. this.removeAllLayers();
  82035. this.data = [];
  82036. this.game = null;
  82037. }
  82038. };
  82039. Phaser.Tilemap.prototype.constructor = Phaser.Tilemap;
  82040. /**
  82041. * @name Phaser.Tilemap#layer
  82042. * @property {number|string|Phaser.TilemapLayer} layer - The current layer object.
  82043. */
  82044. Object.defineProperty(Phaser.Tilemap.prototype, "layer", {
  82045. get: function () {
  82046. return this.layers[this.currentLayer];
  82047. },
  82048. set: function (value) {
  82049. if (value !== this.currentLayer)
  82050. {
  82051. this.setLayer(value);
  82052. }
  82053. }
  82054. });
  82055. /**
  82056. * @author Richard Davey <rich@photonstorm.com>
  82057. * @copyright 2016 Photon Storm Ltd.
  82058. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  82059. */
  82060. /**
  82061. * A TilemapLayer is a Phaser.Image/Sprite that renders a specific TileLayer of a Tilemap.
  82062. *
  82063. * Since a TilemapLayer is a Sprite it can be moved around the display, added to other groups or display objects, etc.
  82064. *
  82065. * By default TilemapLayers have fixedToCamera set to `true`. Changing this will break Camera follow and scrolling behavior.
  82066. *
  82067. * @class Phaser.TilemapLayer
  82068. * @extends Phaser.Sprite
  82069. * @constructor
  82070. * @param {Phaser.Game} game - Game reference to the currently running game.
  82071. * @param {Phaser.Tilemap} tilemap - The tilemap to which this layer belongs.
  82072. * @param {integer} index - The index of the TileLayer to render within the Tilemap.
  82073. * @param {integer} width - Width of the renderable area of the layer (in pixels).
  82074. * @param {integer} height - Height of the renderable area of the layer (in pixels).
  82075. */
  82076. Phaser.TilemapLayer = function (game, tilemap, index, width, height) {
  82077. width |= 0;
  82078. height |= 0;
  82079. Phaser.Sprite.call(this, game, 0, 0);
  82080. /**
  82081. * The Tilemap to which this layer is bound.
  82082. * @property {Phaser.Tilemap} map
  82083. * @protected
  82084. * @readonly
  82085. */
  82086. this.map = tilemap;
  82087. /**
  82088. * The index of this layer within the Tilemap.
  82089. * @property {number} index
  82090. * @protected
  82091. * @readonly
  82092. */
  82093. this.index = index;
  82094. /**
  82095. * The layer object within the Tilemap that this layer represents.
  82096. * @property {object} layer
  82097. * @protected
  82098. * @readonly
  82099. */
  82100. this.layer = tilemap.layers[index];
  82101. /**
  82102. * The canvas to which this TilemapLayer draws.
  82103. * @property {HTMLCanvasElement} canvas
  82104. * @protected
  82105. */
  82106. this.canvas = Phaser.CanvasPool.create(this, width, height);
  82107. /**
  82108. * The 2d context of the canvas.
  82109. * @property {CanvasRenderingContext2D} context
  82110. * @private
  82111. */
  82112. this.context = this.canvas.getContext('2d');
  82113. this.setTexture(new PIXI.Texture(new PIXI.BaseTexture(this.canvas, null, this.game.resolution)));
  82114. /**
  82115. * The const type of this object.
  82116. * @property {number} type
  82117. * @readonly
  82118. * @protected
  82119. * @default Phaser.TILEMAPLAYER
  82120. */
  82121. this.type = Phaser.TILEMAPLAYER;
  82122. /**
  82123. * @property {number} physicsType - The const physics body type of this object.
  82124. * @readonly
  82125. */
  82126. this.physicsType = Phaser.TILEMAPLAYER;
  82127. /**
  82128. * Settings that control standard (non-diagnostic) rendering.
  82129. *
  82130. * @property {boolean} [enableScrollDelta=true] - Delta scroll rendering only draws tiles/edges as they come into view.
  82131. * This can greatly improve scrolling rendering performance, especially when there are many small tiles.
  82132. * It should only be disabled in rare cases.
  82133. *
  82134. * @property {?DOMCanvasElement} [copyCanvas=(auto)] - [Internal] If set, force using a separate (shared) copy canvas.
  82135. * Using a canvas bitblt/copy when the source and destinations region overlap produces unexpected behavior
  82136. * in some browsers, notably Safari.
  82137. *
  82138. * @default
  82139. */
  82140. this.renderSettings = {
  82141. enableScrollDelta: true,
  82142. overdrawRatio: 0.20,
  82143. copyCanvas: null
  82144. };
  82145. /**
  82146. * Enable an additional "debug rendering" pass to display collision information.
  82147. *
  82148. * @property {boolean} debug
  82149. * @default
  82150. */
  82151. this.debug = false;
  82152. /**
  82153. * @property {boolean} exists - Controls if the core game loop and physics update this game object or not.
  82154. */
  82155. this.exists = true;
  82156. /**
  82157. * Settings used for debugging and diagnostics.
  82158. *
  82159. * @property {?string} missingImageFill - A tile is rendered as a rectangle using the following fill if a valid tileset/image cannot be found. A value of `null` prevents additional rendering for tiles without a valid tileset image. _This takes effect even when debug rendering for the layer is not enabled._
  82160. *
  82161. * @property {?string} debuggedTileOverfill - If a Tile has `Tile#debug` true then, after normal tile image rendering, a rectangle with the following fill is drawn above/over it. _This takes effect even when debug rendering for the layer is not enabled._
  82162. *
  82163. * @property {boolean} forceFullRedraw - When debug rendering (`debug` is true), and this option is enabled, the a full redraw is forced and rendering optimization is suppressed.
  82164. *
  82165. * @property {number} debugAlpha - When debug rendering (`debug` is true), the tileset is initially rendered with this alpha level. This can make the tile edges clearer.
  82166. *
  82167. * @property {?string} facingEdgeStroke - When debug rendering (`debug` is true), this color/stroke is used to draw "face" edges. A value of `null` disables coloring facing edges.
  82168. *
  82169. * @property {?string} collidingTileOverfill - When debug rendering (`debug` is true), this fill is used for tiles that are collidable. A value of `null` disables applying the additional overfill.
  82170. *
  82171. */
  82172. this.debugSettings = {
  82173. missingImageFill: 'rgb(255,255,255)',
  82174. debuggedTileOverfill: 'rgba(0,255,0,0.4)',
  82175. forceFullRedraw: true,
  82176. debugAlpha: 0.5,
  82177. facingEdgeStroke: 'rgba(0,255,0,1)',
  82178. collidingTileOverfill: 'rgba(0,255,0,0.2)'
  82179. };
  82180. /**
  82181. * Speed at which this layer scrolls horizontally, relative to the camera (e.g. scrollFactorX of 0.5 scrolls half as quickly as the 'normal' camera-locked layers do).
  82182. * @property {number} scrollFactorX
  82183. * @public
  82184. * @default
  82185. */
  82186. this.scrollFactorX = 1;
  82187. /**
  82188. * Speed at which this layer scrolls vertically, relative to the camera (e.g. scrollFactorY of 0.5 scrolls half as quickly as the 'normal' camera-locked layers do)
  82189. * @property {number} scrollFactorY
  82190. * @public
  82191. * @default
  82192. */
  82193. this.scrollFactorY = 1;
  82194. /**
  82195. * If true tiles will be force rendered, even if such is not believed to be required.
  82196. * @property {boolean} dirty
  82197. * @protected
  82198. */
  82199. this.dirty = true;
  82200. /**
  82201. * When ray-casting against tiles this is the number of steps it will jump. For larger tile sizes you can increase this to improve performance.
  82202. * @property {integer} rayStepRate
  82203. * @default
  82204. */
  82205. this.rayStepRate = 4;
  82206. /**
  82207. * Flag controlling if the layer tiles wrap at the edges.
  82208. * @property {boolean} _wrap
  82209. * @private
  82210. */
  82211. this._wrap = false;
  82212. /**
  82213. * Local map data and calculation cache.
  82214. * @property {object} _mc
  82215. * @private
  82216. */
  82217. this._mc = {
  82218. // Used to bypass rendering without reliance on `dirty` and detect changes.
  82219. scrollX: 0,
  82220. scrollY: 0,
  82221. renderWidth: 0,
  82222. renderHeight: 0,
  82223. tileWidth: tilemap.tileWidth,
  82224. tileHeight: tilemap.tileHeight,
  82225. // Collision width/height (pixels)
  82226. // What purpose do these have? Most things use tile width/height directly.
  82227. // This also only extends collisions right and down.
  82228. cw: tilemap.tileWidth,
  82229. ch: tilemap.tileHeight,
  82230. // Cached tilesets from index -> Tileset
  82231. tilesets: []
  82232. };
  82233. /**
  82234. * The current canvas left after scroll is applied.
  82235. * @property {number} _scrollX
  82236. * @private
  82237. */
  82238. this._scrollX = 0;
  82239. /**
  82240. * The current canvas top after scroll is applied.
  82241. * @property {number} _scrollY
  82242. * @private
  82243. */
  82244. this._scrollY = 0;
  82245. /**
  82246. * The position offset of the layer's tiles.
  82247. * @property {Phaser.Point}
  82248. */
  82249. this.tileOffset = new Phaser.Point(this.layer.offsetX || 0, this.layer.offsetY || 0);
  82250. /**
  82251. * Used for caching the tiles / array of tiles.
  82252. * @property {Phaser.Tile[]} _results
  82253. * @private
  82254. */
  82255. this._results = [];
  82256. if (!game.device.canvasBitBltShift)
  82257. {
  82258. this.renderSettings.copyCanvas = Phaser.TilemapLayer.ensureSharedCopyCanvas();
  82259. }
  82260. this.fixedToCamera = true;
  82261. };
  82262. Phaser.TilemapLayer.prototype = Object.create(Phaser.Sprite.prototype);
  82263. Phaser.TilemapLayer.prototype.constructor = Phaser.TilemapLayer;
  82264. Phaser.TilemapLayer.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
  82265. /**
  82266. * The shared double-copy canvas, created as needed.
  82267. *
  82268. * @private
  82269. * @static
  82270. */
  82271. Phaser.TilemapLayer.sharedCopyCanvas = null;
  82272. /**
  82273. * Create if needed (and return) a shared copy canvas that is shared across all TilemapLayers.
  82274. *
  82275. * Code that uses the canvas is responsible to ensure the dimensions and save/restore state as appropriate.
  82276. *
  82277. * @method Phaser.TilemapLayer#ensureSharedCopyCanvas
  82278. * @protected
  82279. * @static
  82280. */
  82281. Phaser.TilemapLayer.ensureSharedCopyCanvas = function () {
  82282. if (!this.sharedCopyCanvas)
  82283. {
  82284. this.sharedCopyCanvas = Phaser.CanvasPool.create(this, 2, 2);
  82285. }
  82286. return this.sharedCopyCanvas;
  82287. };
  82288. /**
  82289. * Automatically called by World.preUpdate.
  82290. *
  82291. * @method Phaser.TilemapLayer#preUpdate
  82292. */
  82293. Phaser.TilemapLayer.prototype.preUpdate = function() {
  82294. return this.preUpdateCore();
  82295. };
  82296. /**
  82297. * Automatically called by World.postUpdate. Handles cache updates.
  82298. *
  82299. * @method Phaser.TilemapLayer#postUpdate
  82300. * @protected
  82301. */
  82302. Phaser.TilemapLayer.prototype.postUpdate = function () {
  82303. if (this.fixedToCamera)
  82304. {
  82305. this.position.x = (this.game.camera.view.x + this.cameraOffset.x) / this.game.camera.scale.x;
  82306. this.position.y = (this.game.camera.view.y + this.cameraOffset.y) / this.game.camera.scale.y;
  82307. }
  82308. this._scrollX = (this.game.camera.view.x - this.tileOffset.x) * this.scrollFactorX / this.scale.x;
  82309. this._scrollY = (this.game.camera.view.y - this.tileOffset.y) * this.scrollFactorY / this.scale.y;
  82310. };
  82311. /**
  82312. * Automatically called by the Canvas Renderer.
  82313. * Overrides the Sprite._renderCanvas function.
  82314. *
  82315. * @method Phaser.TilemapLayer#_renderCanvas
  82316. * @private
  82317. */
  82318. Phaser.TilemapLayer.prototype._renderCanvas = function (renderSession) {
  82319. if (this.fixedToCamera)
  82320. {
  82321. this.position.x = (this.game.camera.view.x + this.cameraOffset.x) / this.game.camera.scale.x;
  82322. this.position.y = (this.game.camera.view.y + this.cameraOffset.y) / this.game.camera.scale.y;
  82323. }
  82324. this._scrollX = (this.game.camera.view.x - this.tileOffset.x) * this.scrollFactorX / this.scale.x;
  82325. this._scrollY = (this.game.camera.view.y - this.tileOffset.y) * this.scrollFactorY / this.scale.y;
  82326. this.render();
  82327. PIXI.Sprite.prototype._renderCanvas.call(this, renderSession);
  82328. };
  82329. /**
  82330. * Automatically called by the Canvas Renderer.
  82331. * Overrides the Sprite._renderWebGL function.
  82332. *
  82333. * @method Phaser.TilemapLayer#_renderWebGL
  82334. * @private
  82335. */
  82336. Phaser.TilemapLayer.prototype._renderWebGL = function (renderSession) {
  82337. if (this.fixedToCamera)
  82338. {
  82339. this.position.x = (this.game.camera.view.x + this.cameraOffset.x) / this.game.camera.scale.x;
  82340. this.position.y = (this.game.camera.view.y + this.cameraOffset.y) / this.game.camera.scale.y;
  82341. }
  82342. this._scrollX = (this.game.camera.view.x - this.tileOffset.x) * this.scrollFactorX / this.scale.x;
  82343. this._scrollY = (this.game.camera.view.y - this.tileOffset.y) * this.scrollFactorY / this.scale.y;
  82344. this.render();
  82345. PIXI.Sprite.prototype._renderWebGL.call(this, renderSession);
  82346. };
  82347. /**
  82348. * Destroys this TilemapLayer.
  82349. *
  82350. * @method Phaser.TilemapLayer#destroy
  82351. */
  82352. Phaser.TilemapLayer.prototype.destroy = function() {
  82353. Phaser.CanvasPool.remove(this);
  82354. Phaser.Component.Destroy.prototype.destroy.call(this);
  82355. };
  82356. /**
  82357. * Resizes the internal canvas and texture frame used by this TilemapLayer.
  82358. *
  82359. * This is an expensive call, so don't bind it to a window resize event! But instead call it at carefully
  82360. * selected times.
  82361. *
  82362. * Be aware that no validation of the new sizes takes place and the current map scroll coordinates are not
  82363. * modified either. You will have to handle both of these things from your game code if required.
  82364. *
  82365. * @method Phaser.TilemapLayer#resize
  82366. * @param {number} width - The new width of the TilemapLayer
  82367. * @param {number} height - The new height of the TilemapLayer
  82368. */
  82369. Phaser.TilemapLayer.prototype.resize = function (width, height) {
  82370. this.canvas.width = width;
  82371. this.canvas.height = height;
  82372. this.texture.frame.resize(width, height);
  82373. this.texture.width = width;
  82374. this.texture.height = height;
  82375. this.texture.crop.width = width;
  82376. this.texture.crop.height = height;
  82377. this.texture.baseTexture.width = width;
  82378. this.texture.baseTexture.height = height;
  82379. this.texture.baseTexture.dirty();
  82380. this.texture.requiresUpdate = true;
  82381. this.texture._updateUvs();
  82382. this.dirty = true;
  82383. };
  82384. /**
  82385. * Sets the world size to match the size of this layer.
  82386. *
  82387. * @method Phaser.TilemapLayer#resizeWorld
  82388. * @public
  82389. */
  82390. Phaser.TilemapLayer.prototype.resizeWorld = function () {
  82391. this.game.world.setBounds(0, 0, this.layer.widthInPixels * this.scale.x, this.layer.heightInPixels * this.scale.y);
  82392. };
  82393. /**
  82394. * Get the X axis position offset of this layer's tiles.
  82395. *
  82396. * @method Phaser.TilemapLayer#getLayerOffsetX
  82397. * @public
  82398. * @return {number}
  82399. */
  82400. Phaser.TilemapLayer.prototype.getTileOffsetX = function () {
  82401. return this.tileOffset.x || ((!this.fixedToCamera) ? this.position.x : 0);
  82402. };
  82403. /**
  82404. * Get the Y axis position offset of this layer's tiles.
  82405. *
  82406. * @method Phaser.TilemapLayer#getTileOffsetY
  82407. * @public
  82408. * @return {number}
  82409. */
  82410. Phaser.TilemapLayer.prototype.getTileOffsetY = function () {
  82411. return this.tileOffset.y || ((!this.fixedToCamera) ? this.position.y : 0);
  82412. };
  82413. /**
  82414. * Take an x coordinate that doesn't account for scrollFactorX and 'fix' it into a scrolled local space.
  82415. *
  82416. * @method Phaser.TilemapLayer#_fixX
  82417. * @private
  82418. * @param {number} x - x coordinate in camera space
  82419. * @return {number} x coordinate in scrollFactor-adjusted dimensions
  82420. */
  82421. Phaser.TilemapLayer.prototype._fixX = function (x) {
  82422. if (this.scrollFactorX === 1 || (this.scrollFactorX === 0 && this.position.x === 0))
  82423. {
  82424. return x;
  82425. }
  82426. // This executes if the scrollFactorX is 0 and the x position of the tilemap is off from standard.
  82427. if (this.scrollFactorX === 0 && this.position.x !== 0)
  82428. {
  82429. return x - this.position.x;
  82430. }
  82431. return this._scrollX + (x - (this._scrollX / this.scrollFactorX));
  82432. };
  82433. /**
  82434. * Take an x coordinate that _does_ account for scrollFactorX and 'unfix' it back to camera space.
  82435. *
  82436. * @method Phaser.TilemapLayer#_unfixX
  82437. * @private
  82438. * @param {number} x - x coordinate in scrollFactor-adjusted dimensions
  82439. * @return {number} x coordinate in camera space
  82440. */
  82441. Phaser.TilemapLayer.prototype._unfixX = function (x) {
  82442. if (this.scrollFactorX === 1)
  82443. {
  82444. return x;
  82445. }
  82446. return (this._scrollX / this.scrollFactorX) + (x - this._scrollX);
  82447. };
  82448. /**
  82449. * Take a y coordinate that doesn't account for scrollFactorY and 'fix' it into a scrolled local space.
  82450. *
  82451. * @method Phaser.TilemapLayer#_fixY
  82452. * @private
  82453. * @param {number} y - y coordinate in camera space
  82454. * @return {number} y coordinate in scrollFactor-adjusted dimensions
  82455. */
  82456. Phaser.TilemapLayer.prototype._fixY = function (y) {
  82457. if (this.scrollFactorY === 1 || (this.scrollFactorY === 0 && this.position.y === 0))
  82458. {
  82459. return y;
  82460. }
  82461. // This executes if the scrollFactorY is 0 and the y position of the tilemap is off from standard.
  82462. if (this.scrollFactorY === 0 && this.position.y !== 0)
  82463. {
  82464. return y - this.position.y;
  82465. }
  82466. return this._scrollY + (y - (this._scrollY / this.scrollFactorY));
  82467. };
  82468. /**
  82469. * Take a y coordinate that _does_ account for scrollFactorY and 'unfix' it back to camera space.
  82470. *
  82471. * @method Phaser.TilemapLayer#_unfixY
  82472. * @private
  82473. * @param {number} y - y coordinate in scrollFactor-adjusted dimensions
  82474. * @return {number} y coordinate in camera space
  82475. */
  82476. Phaser.TilemapLayer.prototype._unfixY = function (y) {
  82477. if (this.scrollFactorY === 1)
  82478. {
  82479. return y;
  82480. }
  82481. return (this._scrollY / this.scrollFactorY) + (y - this._scrollY);
  82482. };
  82483. /**
  82484. * Convert a pixel value to a tile coordinate.
  82485. *
  82486. * @method Phaser.TilemapLayer#getTileX
  82487. * @public
  82488. * @param {number} x - X position of the point in target tile (in pixels).
  82489. * @return {integer} The X map location of the tile.
  82490. */
  82491. Phaser.TilemapLayer.prototype.getTileX = function (x) {
  82492. // var tileWidth = this.tileWidth * this.scale.x;
  82493. return Math.floor(this._fixX(x) / this._mc.tileWidth);
  82494. };
  82495. /**
  82496. * Convert a pixel value to a tile coordinate.
  82497. *
  82498. * @method Phaser.TilemapLayer#getTileY
  82499. * @public
  82500. * @param {number} y - Y position of the point in target tile (in pixels).
  82501. * @return {integer} The Y map location of the tile.
  82502. */
  82503. Phaser.TilemapLayer.prototype.getTileY = function (y) {
  82504. // var tileHeight = this.tileHeight * this.scale.y;
  82505. return Math.floor(this._fixY(y) / this._mc.tileHeight);
  82506. };
  82507. /**
  82508. * Convert a pixel coordinate to a tile coordinate.
  82509. *
  82510. * @method Phaser.TilemapLayer#getTileXY
  82511. * @public
  82512. * @param {number} x - X position of the point in target tile (in pixels).
  82513. * @param {number} y - Y position of the point in target tile (in pixels).
  82514. * @param {(Phaser.Point|object)} point - The Point/object to update.
  82515. * @return {(Phaser.Point|object)} A Point/object with its `x` and `y` properties set.
  82516. */
  82517. Phaser.TilemapLayer.prototype.getTileXY = function (x, y, point) {
  82518. point.x = this.getTileX(x);
  82519. point.y = this.getTileY(y);
  82520. return point;
  82521. };
  82522. /**
  82523. * Gets all tiles that intersect with the given line.
  82524. *
  82525. * @method Phaser.TilemapLayer#getRayCastTiles
  82526. * @public
  82527. * @param {Phaser.Line} line - The line used to determine which tiles to return.
  82528. * @param {integer} [stepRate=(rayStepRate)] - How many steps through the ray will we check? Defaults to `rayStepRate`.
  82529. * @param {boolean} [collides=false] - If true, _only_ return tiles that collide on one or more faces.
  82530. * @param {boolean} [interestingFace=false] - If true, _only_ return tiles that have interesting faces.
  82531. * @return {Phaser.Tile[]} An array of Phaser.Tiles.
  82532. */
  82533. Phaser.TilemapLayer.prototype.getRayCastTiles = function (line, stepRate, collides, interestingFace) {
  82534. if (!stepRate) { stepRate = this.rayStepRate; }
  82535. if (collides === undefined) { collides = false; }
  82536. if (interestingFace === undefined) { interestingFace = false; }
  82537. // First get all tiles that touch the bounds of the line
  82538. var tiles = this.getTiles(line.x, line.y, line.width, line.height, collides, interestingFace);
  82539. if (tiles.length === 0)
  82540. {
  82541. return [];
  82542. }
  82543. // Now we only want the tiles that intersect with the points on this line
  82544. var coords = line.coordinatesOnLine(stepRate);
  82545. var results = [];
  82546. for (var i = 0; i < tiles.length; i++)
  82547. {
  82548. for (var t = 0; t < coords.length; t++)
  82549. {
  82550. var tile = tiles[i];
  82551. var coord = coords[t];
  82552. if (tile.containsPoint(coord[0], coord[1]))
  82553. {
  82554. results.push(tile);
  82555. break;
  82556. }
  82557. }
  82558. }
  82559. return results;
  82560. };
  82561. /**
  82562. * Get all tiles that exist within the given area, defined by the top-left corner, width and height. Values given are in pixels, not tiles.
  82563. *
  82564. * @method Phaser.TilemapLayer#getTiles
  82565. * @public
  82566. * @param {number} x - X position of the top left corner (in pixels).
  82567. * @param {number} y - Y position of the top left corner (in pixels).
  82568. * @param {number} width - Width of the area to get (in pixels).
  82569. * @param {number} height - Height of the area to get (in pixels).
  82570. * @param {boolean} [collides=false] - If true, _only_ return tiles that collide on one or more faces.
  82571. * @param {boolean} [interestingFace=false] - If true, _only_ return tiles that have interesting faces.
  82572. * @return {array<Phaser.Tile>} An array of Tiles.
  82573. */
  82574. Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides, interestingFace) {
  82575. // Should we only get tiles that have at least one of their collision flags set? (true = yes, false = no just get them all)
  82576. if (collides === undefined) { collides = false; }
  82577. if (interestingFace === undefined) { interestingFace = false; }
  82578. var fetchAll = !(collides || interestingFace);
  82579. // Adjust the x,y coordinates for scrollFactor
  82580. x = this._fixX(x);
  82581. y = this._fixY(y);
  82582. // Convert the pixel values into tile coordinates
  82583. var tx = Math.floor(x / (this._mc.cw * this.scale.x));
  82584. var ty = Math.floor(y / (this._mc.ch * this.scale.y));
  82585. // Don't just use ceil(width/cw) to allow account for x/y diff within cell
  82586. var tw = Math.ceil((x + width) / (this._mc.cw * this.scale.x)) - tx;
  82587. var th = Math.ceil((y + height) / (this._mc.ch * this.scale.y)) - ty;
  82588. while (this._results.length)
  82589. {
  82590. this._results.pop();
  82591. }
  82592. for (var wy = ty; wy < ty + th; wy++)
  82593. {
  82594. for (var wx = tx; wx < tx + tw; wx++)
  82595. {
  82596. var row = this.layer.data[wy];
  82597. if (row && row[wx])
  82598. {
  82599. if (fetchAll || row[wx].isInteresting(collides, interestingFace))
  82600. {
  82601. this._results.push(row[wx]);
  82602. }
  82603. }
  82604. }
  82605. }
  82606. return this._results.slice();
  82607. };
  82608. /**
  82609. * Returns the appropriate tileset for the index, updating the internal cache as required.
  82610. * This should only be called if `tilesets[index]` evaluates to undefined.
  82611. *
  82612. * @method Phaser.TilemapLayer#resolveTileset
  82613. * @private
  82614. * @param {integer} Tile index
  82615. * @return {Phaser.Tileset|null} Returns the associated tileset or null if there is no such mapping.
  82616. */
  82617. Phaser.TilemapLayer.prototype.resolveTileset = function (tileIndex) {
  82618. var tilesets = this._mc.tilesets;
  82619. // Try for dense array if reasonable
  82620. if (tileIndex < 2000)
  82621. {
  82622. while (tilesets.length < tileIndex)
  82623. {
  82624. tilesets.push(undefined);
  82625. }
  82626. }
  82627. var setIndex = this.map.tiles[tileIndex] && this.map.tiles[tileIndex][2];
  82628. if (setIndex !== null)
  82629. {
  82630. var tileset = this.map.tilesets[setIndex];
  82631. if (tileset && tileset.containsTileIndex(tileIndex))
  82632. {
  82633. return (tilesets[tileIndex] = tileset);
  82634. }
  82635. }
  82636. return (tilesets[tileIndex] = null);
  82637. };
  82638. /**
  82639. * The TilemapLayer caches tileset look-ups.
  82640. *
  82641. * Call this method of clear the cache if tilesets have been added or updated after the layer has been rendered.
  82642. *
  82643. * @method Phaser.TilemapLayer#resetTilesetCache
  82644. * @public
  82645. */
  82646. Phaser.TilemapLayer.prototype.resetTilesetCache = function () {
  82647. var tilesets = this._mc.tilesets;
  82648. while (tilesets.length)
  82649. {
  82650. tilesets.pop();
  82651. }
  82652. };
  82653. /**
  82654. * This method will set the scale of the tilemap as well as update the underlying block data of this layer.
  82655. *
  82656. * @method Phaser.TilemapLayer#setScale
  82657. * @param {number} [xScale=1] - The scale factor along the X-plane
  82658. * @param {number} [yScale] - The scale factor along the Y-plane
  82659. */
  82660. Phaser.TilemapLayer.prototype.setScale = function (xScale, yScale) {
  82661. xScale = xScale || 1;
  82662. yScale = yScale || xScale;
  82663. for (var y = 0; y < this.layer.data.length; y++)
  82664. {
  82665. var row = this.layer.data[y];
  82666. for (var x = 0; x < row.length; x++)
  82667. {
  82668. var tile = row[x];
  82669. tile.width = this.map.tileWidth * xScale;
  82670. tile.height = this.map.tileHeight * yScale;
  82671. tile.worldX = tile.x * tile.width;
  82672. tile.worldY = tile.y * tile.height;
  82673. }
  82674. }
  82675. this.scale.setTo(xScale, yScale);
  82676. };
  82677. /**
  82678. * Shifts the contents of the canvas - does extra math so that different browsers agree on the result.
  82679. *
  82680. * The specified (x/y) will be shifted to (0,0) after the copy and the newly exposed canvas area will need to be filled in.
  82681. *
  82682. * @method Phaser.TilemapLayer#shiftCanvas
  82683. * @private
  82684. * @param {CanvasRenderingContext2D} context - The context to shift
  82685. * @param {integer} x
  82686. * @param {integer} y
  82687. */
  82688. Phaser.TilemapLayer.prototype.shiftCanvas = function (context, x, y) {
  82689. var canvas = context.canvas;
  82690. var copyW = canvas.width - Math.abs(x);
  82691. var copyH = canvas.height - Math.abs(y);
  82692. // When x/y non-negative
  82693. var dx = 0;
  82694. var dy = 0;
  82695. var sx = x;
  82696. var sy = y;
  82697. if (x < 0)
  82698. {
  82699. dx = -x;
  82700. sx = 0;
  82701. }
  82702. if (y < 0)
  82703. {
  82704. dy = -y;
  82705. sy = 0;
  82706. }
  82707. var copyCanvas = this.renderSettings.copyCanvas;
  82708. if (copyCanvas)
  82709. {
  82710. // Use a second copy buffer, without slice support, for Safari .. again.
  82711. // Ensure copy canvas is large enough
  82712. if (copyCanvas.width < copyW || copyCanvas.height < copyH)
  82713. {
  82714. copyCanvas.width = copyW;
  82715. copyCanvas.height = copyH;
  82716. }
  82717. var copyContext = copyCanvas.getContext('2d');
  82718. copyContext.clearRect(0, 0, copyW, copyH);
  82719. copyContext.drawImage(canvas, dx, dy, copyW, copyH, 0, 0, copyW, copyH);
  82720. // clear allows default 'source-over' semantics
  82721. context.clearRect(sx, sy, copyW, copyH);
  82722. context.drawImage(copyCanvas, 0, 0, copyW, copyH, sx, sy, copyW, copyH);
  82723. }
  82724. else
  82725. {
  82726. // Avoids a second copy but flickers in Safari / Safari Mobile
  82727. // Ref. https://github.com/photonstorm/phaser/issues/1439
  82728. context.save();
  82729. context.globalCompositeOperation = 'copy';
  82730. context.drawImage(canvas, dx, dy, copyW, copyH, sx, sy, copyW, copyH);
  82731. context.restore();
  82732. }
  82733. };
  82734. /**
  82735. * Render tiles in the given area given by the virtual tile coordinates biased by the given scroll factor.
  82736. * This will constrain the tile coordinates based on wrapping but not physical coordinates.
  82737. *
  82738. * @method Phaser.TilemapLayer#renderRegion
  82739. * @private
  82740. * @param {integer} scrollX - Render x offset/scroll.
  82741. * @param {integer} scrollY - Render y offset/scroll.
  82742. * @param {integer} left - Leftmost column to render.
  82743. * @param {integer} top - Topmost row to render.
  82744. * @param {integer} right - Rightmost column to render.
  82745. * @param {integer} bottom - Bottommost row to render.
  82746. */
  82747. Phaser.TilemapLayer.prototype.renderRegion = function (scrollX, scrollY, left, top, right, bottom) {
  82748. var context = this.context;
  82749. var width = this.layer.width;
  82750. var height = this.layer.height;
  82751. var tw = this._mc.tileWidth;
  82752. var th = this._mc.tileHeight;
  82753. var tilesets = this._mc.tilesets;
  82754. var lastAlpha = NaN;
  82755. if (!this._wrap)
  82756. {
  82757. if (left <= right) // Only adjust if going to render
  82758. {
  82759. left = Math.max(0, left);
  82760. right = Math.min(width - 1, right);
  82761. }
  82762. if (top <= bottom)
  82763. {
  82764. top = Math.max(0, top);
  82765. bottom = Math.min(height - 1, bottom);
  82766. }
  82767. }
  82768. // top-left pixel of top-left cell
  82769. var baseX = (left * tw) - scrollX;
  82770. var baseY = (top * th) - scrollY;
  82771. // Fix normStartX/normStartY such it is normalized [0..width/height). This allows a simple conditional and decrement to always keep in range [0..width/height) during the loop. The major offset bias is to take care of negative values.
  82772. var normStartX = (left + ((1 << 20) * width)) % width;
  82773. var normStartY = (top + ((1 << 20) * height)) % height;
  82774. // tx/ty - are pixel coordinates where tile is drawn
  82775. // x/y - is cell location, normalized [0..width/height) in loop
  82776. // xmax/ymax - remaining cells to render on column/row
  82777. var tx, ty, x, y, xmax, ymax;
  82778. for (y = normStartY, ymax = bottom - top, ty = baseY; ymax >= 0; y++, ymax--, ty += th)
  82779. {
  82780. if (y >= height)
  82781. {
  82782. y -= height;
  82783. }
  82784. var row = this.layer.data[y];
  82785. for (x = normStartX, xmax = right - left, tx = baseX; xmax >= 0; x++, xmax--, tx += tw)
  82786. {
  82787. if (x >= width)
  82788. {
  82789. x -= width;
  82790. }
  82791. var tile = row[x];
  82792. if (!tile || tile.index < 0)
  82793. {
  82794. continue;
  82795. }
  82796. var index = tile.index;
  82797. var set = tilesets[index];
  82798. if (set === undefined)
  82799. {
  82800. set = this.resolveTileset(index);
  82801. }
  82802. // Setting the globalAlpha is "surprisingly expensive" in Chrome (38)
  82803. if (tile.alpha !== lastAlpha && !this.debug)
  82804. {
  82805. context.globalAlpha = tile.alpha;
  82806. lastAlpha = tile.alpha;
  82807. }
  82808. if (set)
  82809. {
  82810. if (tile.rotation || tile.flipped)
  82811. {
  82812. context.save();
  82813. context.translate(tx + tile.centerX, ty + tile.centerY);
  82814. context.rotate(tile.rotation);
  82815. if (tile.flipped)
  82816. {
  82817. context.scale(-1, 1);
  82818. }
  82819. set.draw(context, -tile.centerX, -tile.centerY, index);
  82820. context.restore();
  82821. }
  82822. else
  82823. {
  82824. set.draw(context, tx, ty, index);
  82825. }
  82826. }
  82827. else if (this.debugSettings.missingImageFill)
  82828. {
  82829. context.fillStyle = this.debugSettings.missingImageFill;
  82830. context.fillRect(tx, ty, tw, th);
  82831. }
  82832. if (tile.debug && this.debugSettings.debuggedTileOverfill)
  82833. {
  82834. context.fillStyle = this.debugSettings.debuggedTileOverfill;
  82835. context.fillRect(tx, ty, tw, th);
  82836. }
  82837. }
  82838. }
  82839. };
  82840. /**
  82841. * Shifts the canvas and render damaged edge tiles.
  82842. *
  82843. * @method Phaser.TilemapLayer#renderDeltaScroll
  82844. * @private
  82845. */
  82846. Phaser.TilemapLayer.prototype.renderDeltaScroll = function (shiftX, shiftY) {
  82847. var scrollX = this._mc.scrollX;
  82848. var scrollY = this._mc.scrollY;
  82849. var renderW = this.canvas.width;
  82850. var renderH = this.canvas.height;
  82851. var tw = this._mc.tileWidth;
  82852. var th = this._mc.tileHeight;
  82853. // Only cells with coordinates in the "plus" formed by `left <= x <= right` OR `top <= y <= bottom` are drawn. These coordinates may be outside the layer bounds.
  82854. // Start in pixels
  82855. var left = 0;
  82856. var right = -tw;
  82857. var top = 0;
  82858. var bottom = -th;
  82859. if (shiftX < 0) // layer moving left, damage right
  82860. {
  82861. left = renderW + shiftX; // shiftX neg.
  82862. right = renderW - 1;
  82863. }
  82864. else if (shiftX > 0)
  82865. {
  82866. // left -> 0
  82867. right = shiftX;
  82868. }
  82869. if (shiftY < 0) // layer moving down, damage top
  82870. {
  82871. top = renderH + shiftY; // shiftY neg.
  82872. bottom = renderH - 1;
  82873. }
  82874. else if (shiftY > 0)
  82875. {
  82876. // top -> 0
  82877. bottom = shiftY;
  82878. }
  82879. this.shiftCanvas(this.context, shiftX, shiftY);
  82880. // Transform into tile-space
  82881. left = Math.floor((left + scrollX) / tw);
  82882. right = Math.floor((right + scrollX) / tw);
  82883. top = Math.floor((top + scrollY) / th);
  82884. bottom = Math.floor((bottom + scrollY) / th);
  82885. if (left <= right)
  82886. {
  82887. // Clear left or right edge
  82888. this.context.clearRect(((left * tw) - scrollX), 0, (right - left + 1) * tw, renderH);
  82889. var trueTop = Math.floor((0 + scrollY) / th);
  82890. var trueBottom = Math.floor((renderH - 1 + scrollY) / th);
  82891. this.renderRegion(scrollX, scrollY, left, trueTop, right, trueBottom);
  82892. }
  82893. if (top <= bottom)
  82894. {
  82895. // Clear top or bottom edge
  82896. this.context.clearRect(0, ((top * th) - scrollY), renderW, (bottom - top + 1) * th);
  82897. var trueLeft = Math.floor((0 + scrollX) / tw);
  82898. var trueRight = Math.floor((renderW - 1 + scrollX) / tw);
  82899. this.renderRegion(scrollX, scrollY, trueLeft, top, trueRight, bottom);
  82900. }
  82901. };
  82902. /**
  82903. * Clear and render the entire canvas.
  82904. *
  82905. * @method Phaser.TilemapLayer#renderFull
  82906. * @private
  82907. */
  82908. Phaser.TilemapLayer.prototype.renderFull = function () {
  82909. var scrollX = this._mc.scrollX;
  82910. var scrollY = this._mc.scrollY;
  82911. var renderW = this.canvas.width;
  82912. var renderH = this.canvas.height;
  82913. var tw = this._mc.tileWidth;
  82914. var th = this._mc.tileHeight;
  82915. var left = Math.floor(scrollX / tw);
  82916. var right = Math.floor((renderW - 1 + scrollX) / tw);
  82917. var top = Math.floor(scrollY / th);
  82918. var bottom = Math.floor((renderH - 1 + scrollY) / th);
  82919. this.context.clearRect(0, 0, renderW, renderH);
  82920. this.renderRegion(scrollX, scrollY, left, top, right, bottom);
  82921. };
  82922. /**
  82923. * Renders the tiles to the layer canvas and pushes to the display.
  82924. *
  82925. * @method Phaser.TilemapLayer#render
  82926. * @protected
  82927. */
  82928. Phaser.TilemapLayer.prototype.render = function () {
  82929. var redrawAll = false;
  82930. if (!this.visible)
  82931. {
  82932. return;
  82933. }
  82934. if (this.dirty || this.layer.dirty)
  82935. {
  82936. this.layer.dirty = false;
  82937. redrawAll = true;
  82938. }
  82939. var renderWidth = this.canvas.width; // Use Sprite.width/height?
  82940. var renderHeight = this.canvas.height;
  82941. // Scrolling bias; whole pixels only
  82942. var scrollX = this._scrollX | 0;
  82943. var scrollY = this._scrollY | 0;
  82944. var mc = this._mc;
  82945. var shiftX = mc.scrollX - scrollX; // Negative when scrolling right/down
  82946. var shiftY = mc.scrollY - scrollY;
  82947. if (!redrawAll &&
  82948. shiftX === 0 && shiftY === 0 &&
  82949. mc.renderWidth === renderWidth && mc.renderHeight === renderHeight)
  82950. {
  82951. // No reason to redraw map, looking at same thing and not invalidated.
  82952. return;
  82953. }
  82954. this.context.save();
  82955. mc.scrollX = scrollX;
  82956. mc.scrollY = scrollY;
  82957. if (mc.renderWidth !== renderWidth || mc.renderHeight !== renderHeight)
  82958. {
  82959. // Could support automatic canvas resizing
  82960. mc.renderWidth = renderWidth;
  82961. mc.renderHeight = renderHeight;
  82962. }
  82963. if (this.debug)
  82964. {
  82965. this.context.globalAlpha = this.debugSettings.debugAlpha;
  82966. if (this.debugSettings.forceFullRedraw)
  82967. {
  82968. redrawAll = true;
  82969. }
  82970. }
  82971. if (!redrawAll &&
  82972. this.renderSettings.enableScrollDelta &&
  82973. (Math.abs(shiftX) + Math.abs(shiftY)) < Math.min(renderWidth, renderHeight))
  82974. {
  82975. this.renderDeltaScroll(shiftX, shiftY);
  82976. }
  82977. else
  82978. {
  82979. // Too much change or otherwise requires full render
  82980. this.renderFull();
  82981. }
  82982. if (this.debug)
  82983. {
  82984. this.context.globalAlpha = 1;
  82985. this.renderDebug();
  82986. }
  82987. this.texture.baseTexture.dirty();
  82988. this.dirty = false;
  82989. this.context.restore();
  82990. return true;
  82991. };
  82992. /**
  82993. * Renders a debug overlay on-top of the canvas. Called automatically by render when `debug` is true.
  82994. *
  82995. * See `debugSettings` for assorted configuration options.
  82996. *
  82997. * @method Phaser.TilemapLayer#renderDebug
  82998. * @private
  82999. */
  83000. Phaser.TilemapLayer.prototype.renderDebug = function () {
  83001. var scrollX = this._mc.scrollX;
  83002. var scrollY = this._mc.scrollY;
  83003. var context = this.context;
  83004. var renderW = this.canvas.width;
  83005. var renderH = this.canvas.height;
  83006. var width = this.layer.width;
  83007. var height = this.layer.height;
  83008. var tw = this._mc.tileWidth;
  83009. var th = this._mc.tileHeight;
  83010. var left = Math.floor(scrollX / tw);
  83011. var right = Math.floor((renderW - 1 + scrollX) / tw);
  83012. var top = Math.floor(scrollY / th);
  83013. var bottom = Math.floor((renderH - 1 + scrollY) / th);
  83014. var baseX = (left * tw) - scrollX;
  83015. var baseY = (top * th) - scrollY;
  83016. var normStartX = (left + ((1 << 20) * width)) % width;
  83017. var normStartY = (top + ((1 << 20) * height)) % height;
  83018. var tx, ty, x, y, xmax, ymax;
  83019. context.strokeStyle = this.debugSettings.facingEdgeStroke;
  83020. for (y = normStartY, ymax = bottom - top, ty = baseY; ymax >= 0; y++, ymax--, ty += th)
  83021. {
  83022. if (y >= height)
  83023. {
  83024. y -= height;
  83025. }
  83026. var row = this.layer.data[y];
  83027. for (x = normStartX, xmax = right - left, tx = baseX; xmax >= 0; x++, xmax--, tx += tw)
  83028. {
  83029. if (x >= width)
  83030. {
  83031. x -= width;
  83032. }
  83033. var tile = row[x];
  83034. if (!tile || tile.index < 0 || !tile.collides)
  83035. {
  83036. continue;
  83037. }
  83038. if (this.debugSettings.collidingTileOverfill)
  83039. {
  83040. context.fillStyle = this.debugSettings.collidingTileOverfill;
  83041. context.fillRect(tx, ty, this._mc.cw, this._mc.ch);
  83042. }
  83043. if (this.debugSettings.facingEdgeStroke)
  83044. {
  83045. context.beginPath();
  83046. if (tile.faceTop)
  83047. {
  83048. context.moveTo(tx, ty);
  83049. context.lineTo(tx + this._mc.cw, ty);
  83050. }
  83051. if (tile.faceBottom)
  83052. {
  83053. context.moveTo(tx, ty + this._mc.ch);
  83054. context.lineTo(tx + this._mc.cw, ty + this._mc.ch);
  83055. }
  83056. if (tile.faceLeft)
  83057. {
  83058. context.moveTo(tx, ty);
  83059. context.lineTo(tx, ty + this._mc.ch);
  83060. }
  83061. if (tile.faceRight)
  83062. {
  83063. context.moveTo(tx + this._mc.cw, ty);
  83064. context.lineTo(tx + this._mc.cw, ty + this._mc.ch);
  83065. }
  83066. context.closePath();
  83067. context.stroke();
  83068. }
  83069. }
  83070. }
  83071. };
  83072. /**
  83073. * Flag controlling if the layer tiles wrap at the edges. Only works if the World size matches the Map size.
  83074. *
  83075. * @property {boolean} wrap
  83076. * @memberof Phaser.TilemapLayer
  83077. * @public
  83078. * @default false
  83079. */
  83080. Object.defineProperty(Phaser.TilemapLayer.prototype, "wrap", {
  83081. get: function () {
  83082. return this._wrap;
  83083. },
  83084. set: function (value) {
  83085. this._wrap = value;
  83086. this.dirty = true;
  83087. }
  83088. });
  83089. /**
  83090. * Scrolls the map horizontally or returns the current x position.
  83091. *
  83092. * @property {number} scrollX
  83093. * @memberof Phaser.TilemapLayer
  83094. * @public
  83095. */
  83096. Object.defineProperty(Phaser.TilemapLayer.prototype, "scrollX", {
  83097. get: function () {
  83098. return this._scrollX;
  83099. },
  83100. set: function (value) {
  83101. this._scrollX = value;
  83102. }
  83103. });
  83104. /**
  83105. * Scrolls the map vertically or returns the current y position.
  83106. *
  83107. * @property {number} scrollY
  83108. * @memberof Phaser.TilemapLayer
  83109. * @public
  83110. */
  83111. Object.defineProperty(Phaser.TilemapLayer.prototype, "scrollY", {
  83112. get: function () {
  83113. return this._scrollY;
  83114. },
  83115. set: function (value) {
  83116. this._scrollY = value;
  83117. }
  83118. });
  83119. /**
  83120. * The width of the collision tiles (in pixels).
  83121. *
  83122. * @property {integer} collisionWidth
  83123. * @memberof Phaser.TilemapLayer
  83124. * @public
  83125. */
  83126. Object.defineProperty(Phaser.TilemapLayer.prototype, "collisionWidth", {
  83127. get: function () {
  83128. return this._mc.cw;
  83129. },
  83130. set: function (value) {
  83131. this._mc.cw = value | 0;
  83132. this.dirty = true;
  83133. }
  83134. });
  83135. /**
  83136. * The height of the collision tiles (in pixels).
  83137. *
  83138. * @property {integer} collisionHeight
  83139. * @memberof Phaser.TilemapLayer
  83140. * @public
  83141. */
  83142. Object.defineProperty(Phaser.TilemapLayer.prototype, "collisionHeight", {
  83143. get: function () {
  83144. return this._mc.ch;
  83145. },
  83146. set: function (value) {
  83147. this._mc.ch = value | 0;
  83148. this.dirty = true;
  83149. }
  83150. });
  83151. /**
  83152. * @author Richard Davey <rich@photonstorm.com>
  83153. * @copyright 2016 Photon Storm Ltd.
  83154. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  83155. */
  83156. /**
  83157. * Phaser.TilemapParser parses data objects from Phaser.Loader that need more preparation before they can be inserted into a Tilemap.
  83158. *
  83159. * @class Phaser.TilemapParser
  83160. * @static
  83161. */
  83162. Phaser.TilemapParser = {
  83163. /**
  83164. * When scanning the Tiled map data the TilemapParser can either insert a null value (true) or
  83165. * a Phaser.Tile instance with an index of -1 (false, the default). Depending on your game type
  83166. * depends how this should be configured. If you've a large sparsely populated map and the tile
  83167. * data doesn't need to change then setting this value to `true` will help with memory consumption.
  83168. * However if your map is small, or you need to update the tiles (perhaps the map dynamically changes
  83169. * during the game) then leave the default value set.
  83170. *
  83171. * @constant
  83172. * @type {boolean}
  83173. */
  83174. INSERT_NULL: false,
  83175. /**
  83176. * Parse tilemap data from the cache and creates data for a Tilemap object.
  83177. *
  83178. * @method Phaser.TilemapParser.parse
  83179. * @param {Phaser.Game} game - Game reference to the currently running game.
  83180. * @param {string} key - The key of the tilemap in the Cache.
  83181. * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  83182. * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  83183. * @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  83184. * @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this.
  83185. * @return {object} The parsed map object.
  83186. */
  83187. parse: function (game, key, tileWidth, tileHeight, width, height) {
  83188. if (tileWidth === undefined) { tileWidth = 32; }
  83189. if (tileHeight === undefined) { tileHeight = 32; }
  83190. if (width === undefined) { width = 10; }
  83191. if (height === undefined) { height = 10; }
  83192. if (key === undefined)
  83193. {
  83194. return this.getEmptyData();
  83195. }
  83196. if (key === null)
  83197. {
  83198. return this.getEmptyData(tileWidth, tileHeight, width, height);
  83199. }
  83200. var map = game.cache.getTilemapData(key);
  83201. if (map)
  83202. {
  83203. if (map.format === Phaser.Tilemap.CSV)
  83204. {
  83205. return this.parseCSV(key, map.data, tileWidth, tileHeight);
  83206. }
  83207. else if (!map.format || map.format === Phaser.Tilemap.TILED_JSON)
  83208. {
  83209. return this.parseTiledJSON(map.data);
  83210. }
  83211. }
  83212. else
  83213. {
  83214. console.warn('Phaser.TilemapParser.parse - No map data found for key ' + key);
  83215. }
  83216. },
  83217. /**
  83218. * Parses a CSV file into valid map data.
  83219. *
  83220. * @method Phaser.TilemapParser.parseCSV
  83221. * @param {string} key - The name you want to give the map data.
  83222. * @param {string} data - The CSV file data.
  83223. * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  83224. * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data.
  83225. * @return {object} Generated map data.
  83226. */
  83227. parseCSV: function (key, data, tileWidth, tileHeight) {
  83228. var map = this.getEmptyData();
  83229. // Trim any rogue whitespace from the data
  83230. data = data.trim();
  83231. var output = [];
  83232. var rows = data.split("\n");
  83233. var height = rows.length;
  83234. var width = 0;
  83235. for (var y = 0; y < rows.length; y++)
  83236. {
  83237. output[y] = [];
  83238. var column = rows[y].split(",");
  83239. for (var x = 0; x < column.length; x++)
  83240. {
  83241. output[y][x] = new Phaser.Tile(map.layers[0], parseInt(column[x], 10), x, y, tileWidth, tileHeight);
  83242. }
  83243. if (width === 0)
  83244. {
  83245. width = column.length;
  83246. }
  83247. }
  83248. map.format = Phaser.Tilemap.CSV;
  83249. map.name = key;
  83250. map.width = width;
  83251. map.height = height;
  83252. map.tileWidth = tileWidth;
  83253. map.tileHeight = tileHeight;
  83254. map.widthInPixels = width * tileWidth;
  83255. map.heightInPixels = height * tileHeight;
  83256. map.layers[0].width = width;
  83257. map.layers[0].height = height;
  83258. map.layers[0].widthInPixels = map.widthInPixels;
  83259. map.layers[0].heightInPixels = map.heightInPixels;
  83260. map.layers[0].data = output;
  83261. return map;
  83262. },
  83263. /**
  83264. * Returns an empty map data object.
  83265. *
  83266. * @method Phaser.TilemapParser.getEmptyData
  83267. * @return {object} Generated map data.
  83268. */
  83269. getEmptyData: function (tileWidth, tileHeight, width, height) {
  83270. return {
  83271. width: (width !== undefined && width !== null) ? width : 0,
  83272. height: (height !== undefined && height !== null) ? height : 0,
  83273. tileWidth: (tileWidth !== undefined && tileWidth !== null) ? tileWidth : 0,
  83274. tileHeight: (tileHeight !== undefined && tileHeight !== null) ? tileHeight : 0,
  83275. orientation: 'orthogonal',
  83276. version: '1',
  83277. properties: {},
  83278. widthInPixels: 0,
  83279. heightInPixels: 0,
  83280. layers: [
  83281. {
  83282. name: 'layer',
  83283. x: 0,
  83284. y: 0,
  83285. width: 0,
  83286. height: 0,
  83287. widthInPixels: 0,
  83288. heightInPixels: 0,
  83289. alpha: 1,
  83290. visible: true,
  83291. properties: {},
  83292. indexes: [],
  83293. callbacks: [],
  83294. bodies: [],
  83295. data: []
  83296. }
  83297. ],
  83298. images: [],
  83299. objects: {},
  83300. collision: {},
  83301. tilesets: [],
  83302. tiles: []
  83303. };
  83304. },
  83305. /**
  83306. * Parses an object group in Tiled JSON files. Object groups can be found in both layers and tilesets. Called internally in parseTiledJSON.
  83307. * @method Phaser.TilemapParser.parseObjectGroup
  83308. * @param {object} objectGroup - A JSON object group.
  83309. * @param {object} objectsCollection - An object into which new array of Tiled map objects will be added.
  83310. * @param {object} collisionCollection - An object into which new array of collision objects will be added. Currently only polylines are added.
  83311. * @param {string} [nameKey=objectGroup.name] - Key under which to store objects in collisions in objectsCollection and collisionCollection
  83312. * @param {object} [relativePosition={x: 0, y: 0}] - Coordinates the object group's position is relative to.
  83313. * @return {object} A object literal containing the objectsCollection and collisionCollection
  83314. */
  83315. parseObjectGroup: function(objectGroup, objectsCollection, collisionCollection, nameKey, relativePosition){
  83316. var nameKey = nameKey || objectGroup.name;
  83317. var relativePosition = relativePosition || {x: 0, y: 0};
  83318. if (!nameKey) {
  83319. console.warn("No name found for objectGroup", objectGroup);
  83320. }
  83321. if (relativePosition.x === undefined || relativePosition.y === undefined) {
  83322. console.warn("Malformed xy properties in relativePosition", relativePosition);
  83323. }
  83324. objectsCollection[nameKey] = objectsCollection[nameKey] || [];
  83325. collisionCollection[nameKey] = collisionCollection[nameKey] || [];
  83326. for (var v = 0, len = objectGroup.objects.length; v < len; v++)
  83327. {
  83328. // Object Tiles
  83329. if (objectGroup.objects[v].gid)
  83330. {
  83331. var object = {
  83332. gid: objectGroup.objects[v].gid,
  83333. name: objectGroup.objects[v].name,
  83334. type: objectGroup.objects[v].hasOwnProperty("type") ? objectGroup.objects[v].type : "",
  83335. x: objectGroup.objects[v].x + relativePosition.x,
  83336. y: objectGroup.objects[v].y + relativePosition.y,
  83337. width: objectGroup.objects[v].width,
  83338. height: objectGroup.objects[v].height,
  83339. visible: objectGroup.objects[v].visible,
  83340. properties: objectGroup.objects[v].properties
  83341. };
  83342. if (objectGroup.objects[v].rotation)
  83343. {
  83344. object.rotation = objectGroup.objects[v].rotation;
  83345. }
  83346. objectsCollection[nameKey].push(object);
  83347. }
  83348. else if (objectGroup.objects[v].polyline)
  83349. {
  83350. var object = {
  83351. name: objectGroup.objects[v].name,
  83352. type: objectGroup.objects[v].type,
  83353. x: objectGroup.objects[v].x + relativePosition.x,
  83354. y: objectGroup.objects[v].y + relativePosition.y,
  83355. width: objectGroup.objects[v].width,
  83356. height: objectGroup.objects[v].height,
  83357. visible: objectGroup.objects[v].visible,
  83358. properties: objectGroup.objects[v].properties
  83359. };
  83360. if (objectGroup.objects[v].rotation)
  83361. {
  83362. object.rotation = objectGroup.objects[v].rotation;
  83363. }
  83364. object.polyline = [];
  83365. // Parse the polyline into an array
  83366. for (var p = 0; p < objectGroup.objects[v].polyline.length; p++)
  83367. {
  83368. object.polyline.push([objectGroup.objects[v].polyline[p].x, objectGroup.objects[v].polyline[p].y]);
  83369. }
  83370. collisionCollection[nameKey].push(object);
  83371. objectsCollection[nameKey].push(object);
  83372. }
  83373. // polygon
  83374. else if (objectGroup.objects[v].polygon)
  83375. {
  83376. var object = slice(objectGroup.objects[v], ['name', 'type', 'x', 'y', 'visible', 'rotation', 'properties']);
  83377. object.x += relativePosition.x
  83378. object.y += relativePosition.y
  83379. // Parse the polygon into an array
  83380. object.polygon = [];
  83381. for (var p = 0; p < objectGroup.objects[v].polygon.length; p++)
  83382. {
  83383. object.polygon.push([objectGroup.objects[v].polygon[p].x, objectGroup.objects[v].polygon[p].y]);
  83384. }
  83385. collisionCollection[nameKey].push(object);
  83386. objectsCollection[nameKey].push(object);
  83387. }
  83388. // ellipse
  83389. else if (objectGroup.objects[v].ellipse)
  83390. {
  83391. var object = slice(objectGroup.objects[v], ['name', 'type', 'ellipse', 'x', 'y', 'width', 'height', 'visible', 'rotation', 'properties']);
  83392. object.x += relativePosition.x;
  83393. object.y += relativePosition.y;
  83394. collisionCollection[nameKey].push(object);
  83395. objectsCollection[nameKey].push(object);
  83396. }
  83397. // otherwise it's a rectangle
  83398. else
  83399. {
  83400. var object = slice(objectGroup.objects[v], ['name', 'type', 'x', 'y', 'width', 'height', 'visible', 'rotation', 'properties']);
  83401. object.x += relativePosition.x;
  83402. object.y += relativePosition.y;
  83403. object.rectangle = true;
  83404. collisionCollection[nameKey].push(object);
  83405. objectsCollection[nameKey].push(object);
  83406. }
  83407. }
  83408. function slice (obj, fields) {
  83409. var sliced = {};
  83410. for (var k in fields)
  83411. {
  83412. var key = fields[k];
  83413. if (typeof obj[key] !== 'undefined')
  83414. {
  83415. sliced[key] = obj[key];
  83416. }
  83417. }
  83418. return sliced;
  83419. }
  83420. return {
  83421. objectsCollection: objectsCollection,
  83422. collisionCollection: collisionCollection
  83423. };
  83424. },
  83425. /**
  83426. * Parses a Tiled JSON file into valid map data.
  83427. * @method Phaser.TilemapParser.parseTiledJSON
  83428. * @param {object} json - The JSON map data.
  83429. * @return {object} Generated and parsed map data.
  83430. */
  83431. parseTiledJSON: function (json) {
  83432. if (json.orientation !== 'orthogonal')
  83433. {
  83434. console.warn('TilemapParser.parseTiledJSON - Only orthogonal map types are supported in this version of Phaser');
  83435. return null;
  83436. }
  83437. // Map data will consist of: layers, objects, images, tilesets, sizes
  83438. var map = {
  83439. width: json.width,
  83440. height: json.height,
  83441. tileWidth: json.tilewidth,
  83442. tileHeight: json.tileheight,
  83443. orientation: json.orientation,
  83444. format: Phaser.Tilemap.TILED_JSON,
  83445. version: json.version,
  83446. properties: json.properties,
  83447. widthInPixels: json.width * json.tilewidth,
  83448. heightInPixels: json.height * json.tileheight
  83449. };
  83450. // Tile Layers
  83451. var layers = [];
  83452. for (var i = 0; i < json.layers.length; i++)
  83453. {
  83454. if (json.layers[i].type !== 'tilelayer')
  83455. {
  83456. continue;
  83457. }
  83458. var curl = json.layers[i];
  83459. // Base64 decode data if necessary
  83460. // NOTE: uncompressed base64 only.
  83461. if (!curl.compression && curl.encoding && curl.encoding === 'base64')
  83462. {
  83463. var binaryString = window.atob(curl.data);
  83464. var len = binaryString.length;
  83465. var bytes = new Array(len);
  83466. // Interpret binaryString as an array of bytes representing
  83467. // little-endian encoded uint32 values.
  83468. for (var j = 0; j < len; j+=4)
  83469. {
  83470. bytes[j / 4] = (
  83471. binaryString.charCodeAt(j) |
  83472. binaryString.charCodeAt(j + 1) << 8 |
  83473. binaryString.charCodeAt(j + 2) << 16 |
  83474. binaryString.charCodeAt(j + 3) << 24
  83475. ) >>> 0;
  83476. }
  83477. curl.data = bytes;
  83478. delete curl.encoding;
  83479. }
  83480. else if (curl.compression)
  83481. {
  83482. console.warn('TilemapParser.parseTiledJSON - Layer compression is unsupported, skipping layer \'' + curl.name + '\'');
  83483. continue;
  83484. }
  83485. var layer = {
  83486. name: curl.name,
  83487. x: curl.x,
  83488. y: curl.y,
  83489. width: curl.width,
  83490. height: curl.height,
  83491. widthInPixels: curl.width * json.tilewidth,
  83492. heightInPixels: curl.height * json.tileheight,
  83493. alpha: curl.opacity,
  83494. offsetX: curl.offsetx,
  83495. offsetY: curl.offsety,
  83496. visible: curl.visible,
  83497. properties: {},
  83498. indexes: [],
  83499. callbacks: [],
  83500. bodies: []
  83501. };
  83502. if (curl.properties)
  83503. {
  83504. layer.properties = curl.properties;
  83505. }
  83506. var x = 0;
  83507. var row = [];
  83508. var output = [];
  83509. var rotation, flipped, flippedVal, gid;
  83510. // Loop through the data field in the JSON.
  83511. // This is an array containing the tile indexes, one after the other. -1 = no tile, everything else = the tile index (starting at 1 for Tiled, 0 for CSV)
  83512. // If the map contains multiple tilesets then the indexes are relative to that which the set starts from.
  83513. // Need to set which tileset in the cache = which tileset in the JSON, if you do this manually it means you can use the same map data but a new tileset.
  83514. for (var t = 0, len = curl.data.length; t < len; t++)
  83515. {
  83516. rotation = 0;
  83517. flipped = false;
  83518. gid = curl.data[t];
  83519. flippedVal = 0;
  83520. // If true the current tile is flipped or rotated (Tiled TMX format)
  83521. if (gid > 0x20000000)
  83522. {
  83523. // FlippedX
  83524. if (gid > 0x80000000)
  83525. {
  83526. gid -= 0x80000000;
  83527. flippedVal += 4;
  83528. }
  83529. // FlippedY
  83530. if (gid > 0x40000000)
  83531. {
  83532. gid -= 0x40000000;
  83533. flippedVal += 2;
  83534. }
  83535. // FlippedAD (anti-diagonal = top-right is swapped with bottom-left corners)
  83536. if (gid > 0x20000000)
  83537. {
  83538. gid -= 0x20000000;
  83539. flippedVal += 1;
  83540. }
  83541. switch (flippedVal)
  83542. {
  83543. case 5:
  83544. rotation = Math.PI / 2;
  83545. break;
  83546. case 6:
  83547. rotation = Math.PI;
  83548. break;
  83549. case 3:
  83550. rotation = 3 * Math.PI / 2;
  83551. break;
  83552. case 4:
  83553. rotation = 0;
  83554. flipped = true;
  83555. break;
  83556. case 7:
  83557. rotation = Math.PI / 2;
  83558. flipped = true;
  83559. break;
  83560. case 2:
  83561. rotation = Math.PI;
  83562. flipped = true;
  83563. break;
  83564. case 1:
  83565. rotation = 3 * Math.PI / 2;
  83566. flipped = true;
  83567. break;
  83568. }
  83569. }
  83570. // index, x, y, width, height
  83571. if (gid > 0)
  83572. {
  83573. var tile = new Phaser.Tile(layer, gid, x, output.length, json.tilewidth, json.tileheight);
  83574. tile.rotation = rotation;
  83575. tile.flipped = flipped;
  83576. if (flippedVal !== 0)
  83577. {
  83578. // The WebGL renderer uses this to flip UV coordinates before drawing
  83579. tile.flippedVal = flippedVal;
  83580. }
  83581. row.push(tile);
  83582. }
  83583. else
  83584. {
  83585. if (Phaser.TilemapParser.INSERT_NULL)
  83586. {
  83587. row.push(null);
  83588. }
  83589. else
  83590. {
  83591. row.push(new Phaser.Tile(layer, -1, x, output.length, json.tilewidth, json.tileheight));
  83592. }
  83593. }
  83594. x++;
  83595. if (x === curl.width)
  83596. {
  83597. output.push(row);
  83598. x = 0;
  83599. row = [];
  83600. }
  83601. }
  83602. layer.data = output;
  83603. layers.push(layer);
  83604. }
  83605. map.layers = layers;
  83606. // Images
  83607. var images = [];
  83608. for (var i = 0; i < json.layers.length; i++)
  83609. {
  83610. if (json.layers[i].type !== 'imagelayer')
  83611. {
  83612. continue;
  83613. }
  83614. var curi = json.layers[i];
  83615. var image = {
  83616. name: curi.name,
  83617. image: curi.image,
  83618. x: curi.x,
  83619. y: curi.y,
  83620. alpha: curi.opacity,
  83621. visible: curi.visible,
  83622. properties: {}
  83623. };
  83624. if (curi.properties)
  83625. {
  83626. image.properties = curi.properties;
  83627. }
  83628. images.push(image);
  83629. }
  83630. map.images = images;
  83631. // Tilesets & Image Collections
  83632. var tilesets = [];
  83633. var tilesetGroupObjects = {};
  83634. var imagecollections = [];
  83635. var lastSet = null;
  83636. for (var i = 0; i < json.tilesets.length; i++)
  83637. {
  83638. // name, firstgid, width, height, margin, spacing, properties
  83639. var set = json.tilesets[i];
  83640. if (set.source)
  83641. {
  83642. console.warn('Phaser.TilemapParser - Phaser can\'t load external tilesets (%s). Use the Embed Tileset button and then export the map again.', set.source);
  83643. }
  83644. else if (set.image)
  83645. {
  83646. var newSet = new Phaser.Tileset(set.name, set.firstgid, set.tilewidth, set.tileheight, set.margin, set.spacing, set.properties);
  83647. if (set.tileproperties)
  83648. {
  83649. newSet.tileProperties = set.tileproperties;
  83650. }
  83651. // For a normal sliced tileset the row/count/size information is computed when updated.
  83652. // This is done (again) after the image is set.
  83653. newSet.updateTileData(set.imagewidth, set.imageheight);
  83654. tilesets.push(newSet);
  83655. }
  83656. else if (set.tiles)
  83657. {
  83658. var newCollection = new Phaser.ImageCollection(set.name, set.firstgid, set.tilewidth, set.tileheight, set.margin, set.spacing, set.properties);
  83659. for (var ti in set.tiles)
  83660. {
  83661. var image = set.tiles[ti].image;
  83662. var gid = set.firstgid + parseInt(ti, 10);
  83663. newCollection.addImage(gid, image);
  83664. }
  83665. imagecollections.push(newCollection);
  83666. }
  83667. else
  83668. {
  83669. throw new Error('Tileset ' + set.name + ' has no `image` or `tiles` property.');
  83670. }
  83671. // build a temporary object for objectgroups found in the tileset's tiles
  83672. for (var ti in set.tiles)
  83673. {
  83674. var objectGroup = set.tiles[ti].objectgroup
  83675. if (!objectGroup)
  83676. {
  83677. continue;
  83678. }
  83679. tilesetGroupObjects[parseInt(ti) + set.firstgid] = objectGroup;
  83680. }
  83681. // We've got a new Tileset, so set the lastgid into the previous one
  83682. if (lastSet)
  83683. {
  83684. lastSet.lastgid = set.firstgid - 1;
  83685. }
  83686. lastSet = set;
  83687. }
  83688. if (tilesets.length === 0 && imagecollections.length === 0)
  83689. {
  83690. throw new Error('This tilemap has no tilesets.');
  83691. }
  83692. map.tilesets = tilesets;
  83693. map.imagecollections = imagecollections;
  83694. // Objects & Collision Data (polylines, etc)
  83695. var objects = {};
  83696. var collision = {};
  83697. for (var i = 0; i < json.layers.length; i++)
  83698. {
  83699. if (json.layers[i].type !== 'objectgroup')
  83700. {
  83701. continue;
  83702. }
  83703. var objectGroup = json.layers[i];
  83704. this.parseObjectGroup(objectGroup, objects, collision);
  83705. }
  83706. map.objects = objects;
  83707. map.collision = collision;
  83708. map.tiles = [];
  83709. // Finally lets build our super tileset index
  83710. for (var i = 0; i < map.tilesets.length; i++)
  83711. {
  83712. var set = map.tilesets[i];
  83713. var x = set.tileMargin;
  83714. var y = set.tileMargin;
  83715. var count = 0;
  83716. var countX = 0;
  83717. var countY = 0;
  83718. for (var t = set.firstgid; t < set.firstgid + set.total; t++)
  83719. {
  83720. // Can add extra properties here as needed
  83721. map.tiles[t] = [x, y, i];
  83722. x += set.tileWidth + set.tileSpacing;
  83723. count++;
  83724. if (count === set.total)
  83725. {
  83726. break;
  83727. }
  83728. countX++;
  83729. if (countX === set.columns)
  83730. {
  83731. x = set.tileMargin;
  83732. y += set.tileHeight + set.tileSpacing;
  83733. countX = 0;
  83734. countY++;
  83735. if (countY === set.rows)
  83736. {
  83737. break;
  83738. }
  83739. }
  83740. }
  83741. }
  83742. // assign tile properties
  83743. var layer;
  83744. var tile;
  83745. var sid;
  83746. var set;
  83747. // go through each of the map data layers
  83748. for (var i = 0; i < map.layers.length; i++)
  83749. {
  83750. layer = map.layers[i];
  83751. collision[layer.name] = [];
  83752. set = null;
  83753. // rows of tiles
  83754. for (var j = 0; j < layer.data.length; j++)
  83755. {
  83756. row = layer.data[j];
  83757. // individual tiles
  83758. for (var k = 0; k < row.length; k++)
  83759. {
  83760. tile = row[k];
  83761. if (tile === null || tile.index < 0)
  83762. {
  83763. continue;
  83764. }
  83765. // find the relevant tileset
  83766. sid = map.tiles[tile.index][2];
  83767. set = map.tilesets[sid];
  83768. // if that tile type has any properties, add them to the tile object
  83769. if (set.tileProperties && set.tileProperties[tile.index - set.firstgid])
  83770. {
  83771. tile.properties = Phaser.Utils.mixin(set.tileProperties[tile.index - set.firstgid], tile.properties);
  83772. }
  83773. var objectGroup = tilesetGroupObjects[tile.index];
  83774. if (objectGroup)
  83775. {
  83776. // build collisions and objects for objectgroups found in the tileset's tiles
  83777. this.parseObjectGroup(
  83778. objectGroup,
  83779. map.objects,
  83780. map.collision,
  83781. tile.layer.name,
  83782. {
  83783. x: tile.worldX + objectGroup.x,
  83784. y: tile.worldY + objectGroup.y
  83785. });
  83786. }
  83787. }
  83788. }
  83789. }
  83790. return map;
  83791. }
  83792. };
  83793. /**
  83794. * @author Richard Davey <rich@photonstorm.com>
  83795. * @copyright 2016 Photon Storm Ltd.
  83796. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  83797. */
  83798. /**
  83799. * A Tile set is a combination of an image containing the tiles and collision data per tile.
  83800. *
  83801. * Tilesets are normally created automatically when Tiled data is loaded.
  83802. *
  83803. * @class Phaser.Tileset
  83804. * @constructor
  83805. * @param {string} name - The name of the tileset in the map data.
  83806. * @param {integer} firstgid - The first tile index this tileset contains.
  83807. * @param {integer} [width=32] - Width of each tile (in pixels).
  83808. * @param {integer} [height=32] - Height of each tile (in pixels).
  83809. * @param {integer} [margin=0] - The margin around all tiles in the sheet (in pixels).
  83810. * @param {integer} [spacing=0] - The spacing between each tile in the sheet (in pixels).
  83811. * @param {object} [properties={}] - Custom Tileset properties.
  83812. */
  83813. Phaser.Tileset = function (name, firstgid, width, height, margin, spacing, properties) {
  83814. if (width === undefined || width <= 0) { width = 32; }
  83815. if (height === undefined || height <= 0) { height = 32; }
  83816. if (margin === undefined) { margin = 0; }
  83817. if (spacing === undefined) { spacing = 0; }
  83818. /**
  83819. * The name of the Tileset.
  83820. * @property {string} name
  83821. */
  83822. this.name = name;
  83823. /**
  83824. * The Tiled firstgid value.
  83825. * This is the starting index of the first tile index this Tileset contains.
  83826. * @property {integer} firstgid
  83827. */
  83828. this.firstgid = firstgid | 0;
  83829. /**
  83830. * The width of each tile (in pixels).
  83831. * @property {integer} tileWidth
  83832. * @readonly
  83833. */
  83834. this.tileWidth = width | 0;
  83835. /**
  83836. * The height of each tile (in pixels).
  83837. * @property {integer} tileHeight
  83838. * @readonly
  83839. */
  83840. this.tileHeight = height | 0;
  83841. /**
  83842. * The margin around the tiles in the sheet (in pixels).
  83843. * Use `setSpacing` to change.
  83844. * @property {integer} tileMarge
  83845. * @readonly
  83846. */
  83847. // Modified internally
  83848. this.tileMargin = margin | 0;
  83849. /**
  83850. * The spacing between each tile in the sheet (in pixels).
  83851. * Use `setSpacing` to change.
  83852. * @property {integer} tileSpacing
  83853. * @readonly
  83854. */
  83855. this.tileSpacing = spacing | 0;
  83856. /**
  83857. * Tileset-specific properties that are typically defined in the Tiled editor.
  83858. * @property {object} properties
  83859. */
  83860. this.properties = properties || {};
  83861. /**
  83862. * The cached image that contains the individual tiles. Use {@link Phaser.Tileset.setImage setImage} to set.
  83863. * @property {?object} image
  83864. * @readonly
  83865. */
  83866. // Modified internally
  83867. this.image = null;
  83868. /**
  83869. * The number of tile rows in the the tileset.
  83870. * @property {integer}
  83871. * @readonly
  83872. */
  83873. // Modified internally
  83874. this.rows = 0;
  83875. /**
  83876. * The number of tile columns in the tileset.
  83877. * @property {integer} columns
  83878. * @readonly
  83879. */
  83880. // Modified internally
  83881. this.columns = 0;
  83882. /**
  83883. * The total number of tiles in the tileset.
  83884. * @property {integer} total
  83885. * @readonly
  83886. */
  83887. // Modified internally
  83888. this.total = 0;
  83889. /**
  83890. * The look-up table to specific tile image offsets.
  83891. * The coordinates are interlaced such that it is [x0, y0, x1, y1 .. xN, yN] and the tile with the index of firstgid is found at indices 0/1.
  83892. * @property {integer[]} drawCoords
  83893. * @private
  83894. */
  83895. this.drawCoords = [];
  83896. };
  83897. Phaser.Tileset.prototype = {
  83898. /**
  83899. * Draws a tile from this Tileset at the given coordinates on the context.
  83900. *
  83901. * @method Phaser.Tileset#draw
  83902. * @public
  83903. * @param {CanvasRenderingContext2D} context - The context to draw the tile onto.
  83904. * @param {number} x - The x coordinate to draw to.
  83905. * @param {number} y - The y coordinate to draw to.
  83906. * @param {integer} index - The index of the tile within the set to draw.
  83907. */
  83908. draw: function (context, x, y, index) {
  83909. // Correct the tile index for the set and bias for interlacing
  83910. var coordIndex = (index - this.firstgid) << 1;
  83911. if (coordIndex >= 0 && (coordIndex + 1) < this.drawCoords.length)
  83912. {
  83913. context.drawImage(
  83914. this.image,
  83915. this.drawCoords[coordIndex],
  83916. this.drawCoords[coordIndex + 1],
  83917. this.tileWidth,
  83918. this.tileHeight,
  83919. x,
  83920. y,
  83921. this.tileWidth,
  83922. this.tileHeight
  83923. );
  83924. }
  83925. },
  83926. /**
  83927. * Returns true if and only if this tileset contains the given tile index.
  83928. *
  83929. * @method Phaser.Tileset#containsTileIndex
  83930. * @public
  83931. * @param {number} tileIndex
  83932. * @return {boolean} True if this tileset contains the given index.
  83933. */
  83934. containsTileIndex: function (tileIndex) {
  83935. return (
  83936. tileIndex >= this.firstgid &&
  83937. tileIndex < (this.firstgid + this.total)
  83938. );
  83939. },
  83940. /**
  83941. * Set the image associated with this Tileset and update the tile data.
  83942. *
  83943. * @method Phaser.Tileset#setImage
  83944. * @public
  83945. * @param {Image} image - The image that contains the tiles.
  83946. */
  83947. setImage: function (image) {
  83948. this.image = image;
  83949. this.updateTileData(image.width, image.height);
  83950. },
  83951. /**
  83952. * Sets tile spacing and margins.
  83953. *
  83954. * @method Phaser.Tileset#setSpacing
  83955. * @public
  83956. * @param {integer} [margin=0] - The margin around the tiles in the sheet (in pixels).
  83957. * @param {integer} [spacing=0] - The spacing between the tiles in the sheet (in pixels).
  83958. */
  83959. setSpacing: function (margin, spacing) {
  83960. this.tileMargin = margin | 0;
  83961. this.tileSpacing = spacing | 0;
  83962. if (this.image)
  83963. {
  83964. this.updateTileData(this.image.width, this.image.height);
  83965. }
  83966. },
  83967. /**
  83968. * Updates tile coordinates and tileset data.
  83969. *
  83970. * @method Phaser.Tileset#updateTileData
  83971. * @private
  83972. * @param {integer} imageWidth - The (expected) width of the image to slice.
  83973. * @param {integer} imageHeight - The (expected) height of the image to slice.
  83974. */
  83975. updateTileData: function (imageWidth, imageHeight) {
  83976. // May be fractional values
  83977. var rowCount = (imageHeight - this.tileMargin * 2 + this.tileSpacing) / (this.tileHeight + this.tileSpacing);
  83978. var colCount = (imageWidth - this.tileMargin * 2 + this.tileSpacing) / (this.tileWidth + this.tileSpacing);
  83979. if (rowCount % 1 !== 0 || colCount % 1 !== 0)
  83980. {
  83981. console.warn("Phaser.Tileset - " + this.name + " image tile area is not an even multiple of tile size");
  83982. }
  83983. // In Tiled a tileset image that is not an even multiple of the tile dimensions
  83984. // is truncated - hence the floor when calculating the rows/columns.
  83985. rowCount = Math.floor(rowCount);
  83986. colCount = Math.floor(colCount);
  83987. if ((this.rows && this.rows !== rowCount) || (this.columns && this.columns !== colCount))
  83988. {
  83989. console.warn("Phaser.Tileset - actual and expected number of tile rows and columns differ");
  83990. }
  83991. this.rows = rowCount;
  83992. this.columns = colCount;
  83993. this.total = rowCount * colCount;
  83994. this.drawCoords.length = 0;
  83995. var tx = this.tileMargin;
  83996. var ty = this.tileMargin;
  83997. for (var y = 0; y < this.rows; y++)
  83998. {
  83999. for (var x = 0; x < this.columns; x++)
  84000. {
  84001. this.drawCoords.push(tx);
  84002. this.drawCoords.push(ty);
  84003. tx += this.tileWidth + this.tileSpacing;
  84004. }
  84005. tx = this.tileMargin;
  84006. ty += this.tileHeight + this.tileSpacing;
  84007. }
  84008. }
  84009. };
  84010. Phaser.Tileset.prototype.constructor = Phaser.Tileset;
  84011. /**
  84012. * @author Richard Davey <rich@photonstorm.com>
  84013. * @copyright 2016 Photon Storm Ltd.
  84014. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  84015. */
  84016. /**
  84017. * Create a new `Particle` object. Particles are extended Sprites that are emitted by a particle emitter such as Phaser.Particles.Arcade.Emitter.
  84018. *
  84019. * @class Phaser.Particle
  84020. * @constructor
  84021. * @extends Phaser.Sprite
  84022. * @param {Phaser.Game} game - A reference to the currently running game.
  84023. * @param {number} x - The x coordinate (in world space) to position the Particle at.
  84024. * @param {number} y - The y coordinate (in world space) to position the Particle at.
  84025. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Particle during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture.
  84026. * @param {string|number} frame - If this Particle is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  84027. */
  84028. Phaser.Particle = function (game, x, y, key, frame) {
  84029. Phaser.Sprite.call(this, game, x, y, key, frame);
  84030. /**
  84031. * @property {boolean} autoScale - If this Particle automatically scales this is set to true by Particle.setScaleData.
  84032. * @protected
  84033. */
  84034. this.autoScale = false;
  84035. /**
  84036. * @property {array} scaleData - A reference to the scaleData array owned by the Emitter that emitted this Particle.
  84037. * @protected
  84038. */
  84039. this.scaleData = null;
  84040. /**
  84041. * @property {number} _s - Internal cache var for tracking auto scale.
  84042. * @private
  84043. */
  84044. this._s = 0;
  84045. /**
  84046. * @property {boolean} autoAlpha - If this Particle automatically changes alpha this is set to true by Particle.setAlphaData.
  84047. * @protected
  84048. */
  84049. this.autoAlpha = false;
  84050. /**
  84051. * @property {array} alphaData - A reference to the alphaData array owned by the Emitter that emitted this Particle.
  84052. * @protected
  84053. */
  84054. this.alphaData = null;
  84055. /**
  84056. * @property {number} _a - Internal cache var for tracking auto alpha.
  84057. * @private
  84058. */
  84059. this._a = 0;
  84060. };
  84061. Phaser.Particle.prototype = Object.create(Phaser.Sprite.prototype);
  84062. Phaser.Particle.prototype.constructor = Phaser.Particle;
  84063. /**
  84064. * Updates the Particle scale or alpha if autoScale and autoAlpha are set.
  84065. *
  84066. * @method Phaser.Particle#update
  84067. * @memberof Phaser.Particle
  84068. */
  84069. Phaser.Particle.prototype.update = function() {
  84070. if (this.autoScale)
  84071. {
  84072. this._s--;
  84073. if (this._s)
  84074. {
  84075. this.scale.set(this.scaleData[this._s].x, this.scaleData[this._s].y);
  84076. }
  84077. else
  84078. {
  84079. this.autoScale = false;
  84080. }
  84081. }
  84082. if (this.autoAlpha)
  84083. {
  84084. this._a--;
  84085. if (this._a)
  84086. {
  84087. this.alpha = this.alphaData[this._a].v;
  84088. }
  84089. else
  84090. {
  84091. this.autoAlpha = false;
  84092. }
  84093. }
  84094. };
  84095. /**
  84096. * Called by the Emitter when this particle is emitted. Left empty for you to over-ride as required.
  84097. *
  84098. * @method Phaser.Particle#onEmit
  84099. * @memberof Phaser.Particle
  84100. */
  84101. Phaser.Particle.prototype.onEmit = function() {
  84102. };
  84103. /**
  84104. * Called by the Emitter if autoAlpha has been enabled. Passes over the alpha ease data and resets the alpha counter.
  84105. *
  84106. * @method Phaser.Particle#setAlphaData
  84107. * @memberof Phaser.Particle
  84108. */
  84109. Phaser.Particle.prototype.setAlphaData = function(data) {
  84110. this.alphaData = data;
  84111. this._a = data.length - 1;
  84112. this.alpha = this.alphaData[this._a].v;
  84113. this.autoAlpha = true;
  84114. };
  84115. /**
  84116. * Called by the Emitter if autoScale has been enabled. Passes over the scale ease data and resets the scale counter.
  84117. *
  84118. * @method Phaser.Particle#setScaleData
  84119. * @memberof Phaser.Particle
  84120. */
  84121. Phaser.Particle.prototype.setScaleData = function(data) {
  84122. this.scaleData = data;
  84123. this._s = data.length - 1;
  84124. this.scale.set(this.scaleData[this._s].x, this.scaleData[this._s].y);
  84125. this.autoScale = true;
  84126. };
  84127. /**
  84128. * Resets the Particle. This places the Particle at the given x/y world coordinates and then
  84129. * sets alive, exists, visible and renderable all to true. Also resets the outOfBounds state and health values.
  84130. * If the Particle has a physics body that too is reset.
  84131. *
  84132. * @method Phaser.Particle#reset
  84133. * @memberof Phaser.Particle
  84134. * @param {number} x - The x coordinate (in world space) to position the Particle at.
  84135. * @param {number} y - The y coordinate (in world space) to position the Particle at.
  84136. * @param {number} [health=1] - The health to give the Particle.
  84137. * @return {Phaser.Particle} This instance.
  84138. */
  84139. Phaser.Particle.prototype.reset = function(x, y, health) {
  84140. Phaser.Component.Reset.prototype.reset.call(this, x, y, health);
  84141. this.alpha = 1;
  84142. this.scale.set(1);
  84143. this.autoScale = false;
  84144. this.autoAlpha = false;
  84145. return this;
  84146. };
  84147. /**
  84148. * @author Richard Davey <rich@photonstorm.com>
  84149. * @copyright 2016 Photon Storm Ltd.
  84150. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  84151. */
  84152. /**
  84153. * Phaser.Particles is the Particle Manager for the game. It is called during the game update loop and in turn updates any Emitters attached to it.
  84154. *
  84155. * @class Phaser.Particles
  84156. * @constructor
  84157. * @param {Phaser.Game} game - A reference to the currently running game.
  84158. */
  84159. Phaser.Particles = function (game) {
  84160. /**
  84161. * @property {Phaser.Game} game - A reference to the currently running Game.
  84162. */
  84163. this.game = game;
  84164. /**
  84165. * @property {object} emitters - Internal emitters store.
  84166. */
  84167. this.emitters = {};
  84168. /**
  84169. * @property {number} ID -
  84170. * @default
  84171. */
  84172. this.ID = 0;
  84173. };
  84174. Phaser.Particles.prototype = {
  84175. /**
  84176. * Adds a new Particle Emitter to the Particle Manager.
  84177. * @method Phaser.Particles#add
  84178. * @param {Phaser.Emitter} emitter - The emitter to be added to the particle manager.
  84179. * @return {Phaser.Emitter} The emitter that was added.
  84180. */
  84181. add: function (emitter) {
  84182. this.emitters[emitter.id] = emitter;
  84183. return emitter;
  84184. },
  84185. /**
  84186. * Removes an existing Particle Emitter from the Particle Manager.
  84187. * @method Phaser.Particles#remove
  84188. * @param {Phaser.Emitter} emitter - The emitter to remove.
  84189. */
  84190. remove: function (emitter) {
  84191. delete this.emitters[emitter.id];
  84192. },
  84193. /**
  84194. * Updates all Emitters who have their exists value set to true.
  84195. *
  84196. * Phaser no longer uses this method; Emitters receive updates via {@link Phaser.Stage#update} instead.
  84197. *
  84198. * @method Phaser.Particles#update
  84199. * @protected
  84200. * @deprecated
  84201. */
  84202. update: function () {
  84203. for (var key in this.emitters)
  84204. {
  84205. if (this.emitters[key].exists)
  84206. {
  84207. this.emitters[key].update();
  84208. }
  84209. }
  84210. }
  84211. };
  84212. Phaser.Particles.prototype.constructor = Phaser.Particles;
  84213. /**
  84214. * @author Richard Davey <rich@photonstorm.com>
  84215. * @copyright 2016 Photon Storm Ltd.
  84216. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  84217. */
  84218. /**
  84219. * Arcade Particles is a Particle System integrated with Arcade Physics.
  84220. *
  84221. * @class Phaser.Particles.Arcade
  84222. */
  84223. Phaser.Particles.Arcade = {};
  84224. /**
  84225. * @author Richard Davey <rich@photonstorm.com>
  84226. * @copyright 2016 Photon Storm Ltd.
  84227. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  84228. */
  84229. /**
  84230. * Emitter is a lightweight particle emitter that uses Arcade Physics.
  84231. * It can be used for one-time explosions or for continuous effects like rain and fire.
  84232. * All it really does is launch Particle objects out at set intervals, and fixes their positions and velocities accordingly.
  84233. *
  84234. * @class Phaser.Particles.Arcade.Emitter
  84235. * @constructor
  84236. * @extends Phaser.Group
  84237. * @param {Phaser.Game} game - Current game instance.
  84238. * @param {number} [x=0] - The x coordinate within the Emitter that the particles are emitted from.
  84239. * @param {number} [y=0] - The y coordinate within the Emitter that the particles are emitted from.
  84240. * @param {number} [maxParticles=50] - The total number of particles in this emitter.
  84241. */
  84242. Phaser.Particles.Arcade.Emitter = function (game, x, y, maxParticles) {
  84243. /**
  84244. * @property {number} maxParticles - The total number of particles in this emitter.
  84245. * @default
  84246. */
  84247. this.maxParticles = maxParticles || 50;
  84248. Phaser.Group.call(this, game);
  84249. /**
  84250. * @property {number} _id - Internal ID for this emitter -- only used by the Particle System in most cases
  84251. * @private
  84252. */
  84253. this._id = this.game.particles.ID++;
  84254. /**
  84255. * @property {string} name - A handy string name for this emitter. Can be set to anything.
  84256. */
  84257. this.name = 'emitter' + this.id;
  84258. /**
  84259. * @property {number} type - Internal Phaser Type value.
  84260. * @protected
  84261. */
  84262. this.type = Phaser.EMITTER;
  84263. /**
  84264. * @property {number} physicsType - The const physics body type of this object.
  84265. * @readonly
  84266. */
  84267. this.physicsType = Phaser.GROUP;
  84268. /**
  84269. * @property {Phaser.Rectangle} area - The {@link #setSize size} of the emitter's emit area. The **actual** emit area is a rectangle of this size centered on (emitX, emitY): `{x: this.left, y: this.top, width: this.area.width, height: this.area.height}`. Particles are generated at a random position within this area.
  84270. * @default
  84271. */
  84272. this.area = new Phaser.Rectangle(x, y, 1, 1);
  84273. /**
  84274. * @property {?number} minAngle - The minimum angle of initial particle velocities, in degrees. When set to a non-null value (with {@link #maxAngle}), {@link #minSpeed} and {@link #maxSpeed} are used and {@link #minParticleSpeed} and {@link #maxParticleSpeed} are ignored.
  84275. * @default
  84276. */
  84277. this.minAngle = null;
  84278. /**
  84279. * @property {?number} maxAngle - The maximum angle of initial particle velocities, in degrees. When set to a non-null value (with {@link #minAngle}), {@link #minSpeed} and {@link #maxSpeed} are used and {@link #minParticleSpeed} and {@link #maxParticleSpeed} are ignored.
  84280. * @default
  84281. */
  84282. this.maxAngle = null;
  84283. /**
  84284. * @property {number} minSpeed - The minimum initial speed of particles released within {@link #minAngle} and {@link #maxAngle}.
  84285. * @default
  84286. */
  84287. this.minSpeed = 0;
  84288. /**
  84289. * @property {number} maxSpeed - The maximum initial speed of particles released within {@link #minAngle} and {@link #maxAngle}.
  84290. * @default
  84291. */
  84292. this.maxSpeed = 100;
  84293. /**
  84294. * @property {Phaser.Point} minParticleSpeed - The minimum possible velocity of a particle.
  84295. * @default
  84296. */
  84297. this.minParticleSpeed = new Phaser.Point(-100, -100);
  84298. /**
  84299. * @property {Phaser.Point} maxParticleSpeed - The maximum possible velocity of a particle.
  84300. * @default
  84301. */
  84302. this.maxParticleSpeed = new Phaser.Point(100, 100);
  84303. /**
  84304. * @property {number} minParticleScale - The minimum possible scale of a particle. This is applied to the X and Y axis. If you need to control each axis see minParticleScaleX.
  84305. * @default
  84306. */
  84307. this.minParticleScale = 1;
  84308. /**
  84309. * @property {number} maxParticleScale - The maximum possible scale of a particle. This is applied to the X and Y axis. If you need to control each axis see maxParticleScaleX.
  84310. * @default
  84311. */
  84312. this.maxParticleScale = 1;
  84313. /**
  84314. * @property {array} scaleData - An array of the calculated scale easing data applied to particles with scaleRates > 0.
  84315. */
  84316. this.scaleData = null;
  84317. /**
  84318. * @property {number} minRotation - The minimum possible angular velocity of a particle.
  84319. * @default
  84320. */
  84321. this.minRotation = -360;
  84322. /**
  84323. * @property {number} maxRotation - The maximum possible angular velocity of a particle.
  84324. * @default
  84325. */
  84326. this.maxRotation = 360;
  84327. /**
  84328. * @property {number} minParticleAlpha - The minimum possible alpha value of a particle.
  84329. * @default
  84330. */
  84331. this.minParticleAlpha = 1;
  84332. /**
  84333. * @property {number} maxParticleAlpha - The maximum possible alpha value of a particle.
  84334. * @default
  84335. */
  84336. this.maxParticleAlpha = 1;
  84337. /**
  84338. * @property {array} alphaData - An array of the calculated alpha easing data applied to particles with alphaRates > 0.
  84339. */
  84340. this.alphaData = null;
  84341. /**
  84342. * @property {function} particleClass - For emitting your own particle class types. They must extend Phaser.Particle.
  84343. * @default
  84344. */
  84345. this.particleClass = Phaser.Particle;
  84346. /**
  84347. * @property {Phaser.Point} particleDrag - The X and Y drag component of particles launched from the emitter.
  84348. */
  84349. this.particleDrag = new Phaser.Point();
  84350. /**
  84351. * @property {number} angularDrag - The angular drag component of particles launched from the emitter if they are rotating.
  84352. * @default
  84353. */
  84354. this.angularDrag = 0;
  84355. /**
  84356. * @property {number} frequency - How often a particle is emitted in ms (if emitter is started with Explode === false).
  84357. * @default
  84358. */
  84359. this.frequency = 100;
  84360. /**
  84361. * @property {number} lifespan - How long each particle lives once it is emitted in ms. Default is 2 seconds. Set lifespan to 'zero' for particles to live forever.
  84362. * @default
  84363. */
  84364. this.lifespan = 2000;
  84365. /**
  84366. * @property {Phaser.Point} bounce - How much each particle should bounce on each axis. 1 = full bounce, 0 = no bounce.
  84367. */
  84368. this.bounce = new Phaser.Point();
  84369. /**
  84370. * @property {boolean} on - Determines whether the emitter is currently emitting particles. It is totally safe to directly toggle this.
  84371. * @default
  84372. */
  84373. this.on = false;
  84374. /**
  84375. * @property {Phaser.Point} particleAnchor - When a particle is created its anchor will be set to match this Point object (defaults to x/y: 0.5 to aid in rotation)
  84376. * @default
  84377. */
  84378. this.particleAnchor = new Phaser.Point(0.5, 0.5);
  84379. /**
  84380. * @property {number} blendMode - The blendMode as set on the particle when emitted from the Emitter. Defaults to NORMAL. Needs browser capable of supporting canvas blend-modes (most not available in WebGL)
  84381. * @default
  84382. */
  84383. this.blendMode = Phaser.blendModes.NORMAL;
  84384. /**
  84385. * The point the particles are emitted from.
  84386. * Emitter.x and Emitter.y control the containers location, which updates all current particles
  84387. * Emitter.emitX and Emitter.emitY control the emission location relative to the x/y position.
  84388. * @property {number} emitX
  84389. */
  84390. this.emitX = x;
  84391. /**
  84392. * The point the particles are emitted from.
  84393. * Emitter.x and Emitter.y control the containers location, which updates all current particles
  84394. * Emitter.emitX and Emitter.emitY control the emission location relative to the x/y position.
  84395. * @property {number} emitY
  84396. */
  84397. this.emitY = y;
  84398. /**
  84399. * @property {boolean} autoScale - When a new Particle is emitted this controls if it will automatically scale in size. Use Emitter.setScale to configure.
  84400. */
  84401. this.autoScale = false;
  84402. /**
  84403. * @property {boolean} autoAlpha - When a new Particle is emitted this controls if it will automatically change alpha. Use Emitter.setAlpha to configure.
  84404. */
  84405. this.autoAlpha = false;
  84406. /**
  84407. * @property {boolean} particleBringToTop - If this is `true` then when the Particle is emitted it will be bought to the top of the Emitters display list.
  84408. * @default
  84409. */
  84410. this.particleBringToTop = false;
  84411. /**
  84412. * @property {boolean} particleSendToBack - If this is `true` then when the Particle is emitted it will be sent to the back of the Emitters display list.
  84413. * @default
  84414. */
  84415. this.particleSendToBack = false;
  84416. /**
  84417. * @property {object} counts - Records emitter activity.
  84418. * @property {number} counts.emitted - How many particles were emitted during the last update.
  84419. * @property {number} counts.failed - How many particles could not be emitted during the last update (because no particles were available).
  84420. * @property {number} counts.totalEmitted - How many particles have been emitted.
  84421. * @property {number} counts.totalFailed - How many particles could not be emitted when they were due (because no particles were available).
  84422. */
  84423. this.counts = {
  84424. emitted: 0,
  84425. failed: 0,
  84426. totalEmitted: 0,
  84427. totalFailed: 0
  84428. };
  84429. /**
  84430. * @property {Phaser.Point} _gravity - Internal gravity value.
  84431. * @private
  84432. */
  84433. this._gravity = new Phaser.Point(0, 100);
  84434. /**
  84435. * @property {Phaser.Point} _minParticleScale - Internal particle scale var.
  84436. * @private
  84437. */
  84438. this._minParticleScale = new Phaser.Point(1, 1);
  84439. /**
  84440. * @property {Phaser.Point} _maxParticleScale - Internal particle scale var.
  84441. * @private
  84442. */
  84443. this._maxParticleScale = new Phaser.Point(1, 1);
  84444. /**
  84445. * @property {number} _total - Internal helper for deciding how many particles to launch (via {@link #start}).
  84446. * @private
  84447. */
  84448. this._total = 0;
  84449. /**
  84450. * @property {number} _timer - Internal helper for deciding when to launch particles or kill them.
  84451. * @private
  84452. */
  84453. this._timer = 0;
  84454. /**
  84455. * @property {number} _counter - Internal counter for figuring out how many particles to launch.
  84456. * @private
  84457. */
  84458. this._counter = 0;
  84459. /**
  84460. * @property {number} _flowQuantity - Internal counter for figuring out how many particles to launch per flow update.
  84461. * @private
  84462. */
  84463. this._flowQuantity = 0;
  84464. /**
  84465. * @property {number} _flowTotal - Internal counter for figuring out how many particles to launch in total (via {@link #flow}).
  84466. * @private
  84467. */
  84468. this._flowTotal = 0;
  84469. /**
  84470. * @property {boolean} _explode - Internal helper for the style of particle emission (all at once, or one at a time).
  84471. * @private
  84472. */
  84473. this._explode = true;
  84474. /**
  84475. * @property {any} _frames - Internal helper for the particle frame.
  84476. * @private
  84477. */
  84478. this._frames = null;
  84479. };
  84480. Phaser.Particles.Arcade.Emitter.prototype = Object.create(Phaser.Group.prototype);
  84481. Phaser.Particles.Arcade.Emitter.prototype.constructor = Phaser.Particles.Arcade.Emitter;
  84482. /**
  84483. * Called automatically by the game loop, decides when to launch particles and when to "die".
  84484. *
  84485. * @method Phaser.Particles.Arcade.Emitter#update
  84486. */
  84487. Phaser.Particles.Arcade.Emitter.prototype.update = function () {
  84488. this.counts.emitted = 0;
  84489. this.counts.failed = 0;
  84490. if (this.on && this.game.time.time >= this._timer)
  84491. {
  84492. this._timer = this.game.time.time + this.frequency * this.game.time.slowMotion;
  84493. if (this._flowTotal !== 0)
  84494. {
  84495. if (this._flowQuantity > 0)
  84496. {
  84497. for (var i = 0; i < this._flowQuantity; i++)
  84498. {
  84499. if (this.emitParticle())
  84500. {
  84501. this._counter++;
  84502. if (this._flowTotal !== -1 && this._counter >= this._flowTotal)
  84503. {
  84504. this.on = false;
  84505. break;
  84506. }
  84507. }
  84508. }
  84509. }
  84510. else
  84511. {
  84512. if (this.emitParticle())
  84513. {
  84514. this._counter++;
  84515. if (this._flowTotal !== -1 && this._counter >= this._flowTotal)
  84516. {
  84517. this.on = false;
  84518. }
  84519. }
  84520. }
  84521. }
  84522. else
  84523. {
  84524. if (this.emitParticle())
  84525. {
  84526. this._counter++;
  84527. if (this._total > 0 && this._counter >= this._total)
  84528. {
  84529. this.on = false;
  84530. }
  84531. }
  84532. }
  84533. }
  84534. var i = this.children.length;
  84535. while (i--)
  84536. {
  84537. if (this.children[i].exists)
  84538. {
  84539. this.children[i].update();
  84540. }
  84541. }
  84542. };
  84543. /**
  84544. * This function generates a new set of particles for use by this emitter.
  84545. * The particles are stored internally waiting to be emitted via Emitter.start.
  84546. *
  84547. * @method Phaser.Particles.Arcade.Emitter#makeParticles
  84548. * @param {array|string} keys - A string or an array of strings that the particle sprites will use as their texture. If an array one is picked at random.
  84549. * @param {array|number} [frames=0] - A frame number, or array of frames that the sprite will use. If an array one is picked at random.
  84550. * @param {number} [quantity] - The number of particles to generate. If not given it will use the value of Emitter.maxParticles. If the value is greater than Emitter.maxParticles it will use Emitter.maxParticles as the quantity.
  84551. * @param {boolean} [collide=false] - If you want the particles to be able to collide with other Arcade Physics bodies then set this to true.
  84552. * @param {boolean} [collideWorldBounds=false] - A particle can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World.
  84553. * @param {object} [particleArguments=null] - Custom arguments to pass to your particle class
  84554. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84555. */
  84556. Phaser.Particles.Arcade.Emitter.prototype.makeParticles = function (keys, frames, quantity, collide, collideWorldBounds, particleArguments) {
  84557. if (frames === undefined) { frames = 0; }
  84558. if (quantity === undefined) { quantity = this.maxParticles; }
  84559. if (collide === undefined) { collide = false; }
  84560. if (collideWorldBounds === undefined) { collideWorldBounds = false; }
  84561. if (particleArguments === undefined) { particleArguments = null; }
  84562. var particle;
  84563. var i = 0;
  84564. var rndKey = keys;
  84565. var rndFrame = frames;
  84566. this._frames = frames;
  84567. if (quantity > this.maxParticles)
  84568. {
  84569. this.maxParticles = quantity;
  84570. }
  84571. while (i < quantity)
  84572. {
  84573. if (Array.isArray(keys))
  84574. {
  84575. rndKey = this.game.rnd.pick(keys);
  84576. }
  84577. if (Array.isArray(frames))
  84578. {
  84579. rndFrame = this.game.rnd.pick(frames);
  84580. }
  84581. particle = new this.particleClass(this.game, 0, 0, rndKey, rndFrame, particleArguments);
  84582. this.game.physics.arcade.enable(particle, false);
  84583. particle.body.checkCollision.none = !collide;
  84584. particle.body.collideWorldBounds = collideWorldBounds;
  84585. particle.body.skipQuadTree = true;
  84586. particle.exists = false;
  84587. particle.visible = false;
  84588. particle.anchor.copyFrom(this.particleAnchor);
  84589. this.add(particle);
  84590. i++;
  84591. }
  84592. return this;
  84593. };
  84594. /**
  84595. * Call this function to turn off all the particles and the emitter.
  84596. *
  84597. * @method Phaser.Particles.Arcade.Emitter#kill
  84598. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84599. */
  84600. Phaser.Particles.Arcade.Emitter.prototype.kill = function () {
  84601. this.on = false;
  84602. this.alive = false;
  84603. this.exists = false;
  84604. return this;
  84605. };
  84606. /**
  84607. * Handy for bringing game objects "back to life". Just sets alive and exists back to true.
  84608. *
  84609. * @method Phaser.Particles.Arcade.Emitter#revive
  84610. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84611. */
  84612. Phaser.Particles.Arcade.Emitter.prototype.revive = function () {
  84613. this.alive = true;
  84614. this.exists = true;
  84615. return this;
  84616. };
  84617. /**
  84618. * Call this function to emit the given quantity of particles at all once (an explosion)
  84619. *
  84620. * @method Phaser.Particles.Arcade.Emitter#explode
  84621. * @param {number} [lifespan=0] - How long each particle lives once emitted in ms. 0 = forever.
  84622. * @param {number} [quantity=this.maxParticles] - How many particles to launch.
  84623. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84624. */
  84625. Phaser.Particles.Arcade.Emitter.prototype.explode = function (lifespan, quantity) {
  84626. if (quantity === undefined) {
  84627. quantity = this.maxParticles;
  84628. }
  84629. this._flowTotal = 0;
  84630. this.start(true, lifespan, 0, quantity, false);
  84631. return this;
  84632. };
  84633. /**
  84634. * Call this function to start emitting a flow of particles.
  84635. * `quantity` particles are released every interval of `frequency` ms until `total` particles have been released (or forever).
  84636. * If you set the total to be 20 and quantity to be 5 then flow will emit 4 times in total (4 × 5 = 20 total) and then turn {@link #on off}.
  84637. * If you set the total to be -1 then no quantity cap is used and it will keep emitting (as long as there are inactive particles available).
  84638. *
  84639. * {@link #output}, {@link #lifespanOutput}, and {@link #remainder} describe the particle flow rate.
  84640. * During a stable flow, the number of active particles approaches {@link #lifespanOutput} and the number of inactive particles approaches {@link #remainder}.
  84641. * If {@link #remainder} is less than 0, there will likely be no particles available for a portion of the flow (see {@link #count}).
  84642. *
  84643. * @method Phaser.Particles.Arcade.Emitter#flow
  84644. * @param {number} [lifespan=0] - How long each particle lives once emitted in ms. 0 = forever.
  84645. * @param {number} [frequency=250] - The interval between each release of particles, given in ms. Values between 0 and 16.66 will behave the same (60 releases per second).
  84646. * @param {number} [quantity=1] - How many particles to launch at each interval. Not larger than {@link #maxParticles}.
  84647. * @param {number} [total=-1] - Turn {@link #on off} after launching this many particles in total. If -1 it will carry on indefinitely.
  84648. * @param {boolean} [immediate=true] - Should the flow start immediately (true) or wait until the first frequency event? (false)
  84649. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84650. */
  84651. Phaser.Particles.Arcade.Emitter.prototype.flow = function (lifespan, frequency, quantity, total, immediate) {
  84652. if (frequency === undefined || frequency === null) { frequency = 250; }
  84653. if (quantity === undefined || quantity === 0) { quantity = 1; }
  84654. if (total === undefined) { total = -1; }
  84655. if (immediate === undefined) { immediate = true; }
  84656. if (quantity > this.maxParticles)
  84657. {
  84658. quantity = this.maxParticles;
  84659. }
  84660. this._counter = 0;
  84661. this._flowQuantity = quantity;
  84662. this._flowTotal = total;
  84663. if (immediate)
  84664. {
  84665. this.start(true, lifespan, frequency, quantity);
  84666. this._counter += quantity;
  84667. this.on = true;
  84668. this._timer = this.game.time.time + frequency * this.game.time.slowMotion;
  84669. }
  84670. else
  84671. {
  84672. this.start(false, lifespan, frequency, quantity);
  84673. }
  84674. return this;
  84675. };
  84676. /**
  84677. * Start emitting particles.
  84678. *
  84679. * {@link #explode} and {@link #flow} are simpler methods.
  84680. *
  84681. * There are two patterns, based on the `explode` argument:
  84682. *
  84683. * ##### explode=true
  84684. *
  84685. * start(true, lifespan=0, null, total)
  84686. *
  84687. * When `explode` is true or `forceQuantity` is true, `start` emits `total` particles immediately. You should pass a nonzero `total`.
  84688. *
  84689. * ##### explode=false
  84690. *
  84691. * start(false, lifespan=0, frequency=250, total=0)
  84692. *
  84693. * When `explode` is false and `forceQuantity` is false, `start` emits 1 particle every interval of `frequency` ms. If `total` is not zero, the emitter turns itself off after `total` particles have been released. If `total` is zero, the emitter keeps emitting particles as long as they are available. To emit more than 1 particle per flow interval, use {@link #flow} instead.
  84694. *
  84695. * `forceQuantity` seems equivalent to `explode` and can probably be avoided.
  84696. *
  84697. * @method Phaser.Particles.Arcade.Emitter#start
  84698. * @param {boolean} [explode=true] - Whether the particles should all burst out at once (true) or at the frequency given (false).
  84699. * @param {number} [lifespan=0] - How long each particle lives once emitted in ms. 0 = forever.
  84700. * @param {number} [frequency=250] - The interval between each release of 1 particle, when `explode` is false. Value given in ms. Ignored if `explode` is set to true.
  84701. * @param {number} [total=0] - Turn {@link #on off} after launching this many particles in total.
  84702. * @param {number} [forceQuantity=false] - Equivalent to `explodes`.
  84703. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84704. */
  84705. Phaser.Particles.Arcade.Emitter.prototype.start = function (explode, lifespan, frequency, total, forceQuantity) {
  84706. if (explode === undefined) { explode = true; }
  84707. if (lifespan === undefined) { lifespan = 0; }
  84708. if (frequency === undefined || frequency === null) { frequency = 250; }
  84709. if (total === undefined) { total = 0; }
  84710. if (forceQuantity === undefined) { forceQuantity = false; }
  84711. if (total > this.maxParticles)
  84712. {
  84713. total = this.maxParticles;
  84714. }
  84715. this.revive();
  84716. this.visible = true;
  84717. this.lifespan = lifespan;
  84718. this.frequency = frequency;
  84719. if (explode || forceQuantity)
  84720. {
  84721. for (var i = 0; i < total; i++)
  84722. {
  84723. this.emitParticle();
  84724. }
  84725. }
  84726. else
  84727. {
  84728. this.on = true;
  84729. this._total = total;
  84730. this._counter = 0;
  84731. this._timer = this.game.time.time + frequency * this.game.time.slowMotion;
  84732. }
  84733. return this;
  84734. };
  84735. /**
  84736. * This function is used internally to emit the next particle in the queue.
  84737. *
  84738. * However it can also be called externally to emit a particle.
  84739. *
  84740. * When called externally you can use the arguments to override any defaults the Emitter has set.
  84741. *
  84742. * The newly emitted particle is available in {@link Phaser.Particles.Arcade.Emitter#cursor}.
  84743. *
  84744. * @method Phaser.Particles.Arcade.Emitter#emitParticle
  84745. * @param {number} [x] - The x coordinate to emit the particle from. If `null` or `undefined` it will use `Emitter.emitX` or if the Emitter has a width > 1 a random value between `Emitter.left` and `Emitter.right`.
  84746. * @param {number} [y] - The y coordinate to emit the particle from. If `null` or `undefined` it will use `Emitter.emitY` or if the Emitter has a height > 1 a random value between `Emitter.top` and `Emitter.bottom`.
  84747. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} [key] - This is the image or texture used by the Particle during rendering. It can be a string which is a reference to the Cache Image entry, or an instance of a RenderTexture, BitmapData, Video or PIXI.Texture.
  84748. * @param {string|number} [frame] - If this Particle is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  84749. * @return {boolean} True if a particle was emitted, otherwise false.
  84750. */
  84751. Phaser.Particles.Arcade.Emitter.prototype.emitParticle = function (x, y, key, frame) {
  84752. if (x === undefined) { x = null; }
  84753. if (y === undefined) { y = null; }
  84754. var particle = this.getNextParticle();
  84755. if (particle === null)
  84756. {
  84757. this.counts.failed++;
  84758. this.counts.totalFailed++;
  84759. return false;
  84760. }
  84761. this.counts.emitted++;
  84762. this.counts.totalEmitted++;
  84763. var rnd = this.game.rnd;
  84764. if (key !== undefined && frame !== undefined)
  84765. {
  84766. particle.loadTexture(key, frame);
  84767. }
  84768. else if (key !== undefined)
  84769. {
  84770. particle.loadTexture(key);
  84771. particle.frame = Array.isArray(this._frames) ? rnd.pick(this._frames) : this._frames;
  84772. }
  84773. var emitX = this.emitX;
  84774. var emitY = this.emitY;
  84775. if (x !== null)
  84776. {
  84777. emitX = x;
  84778. }
  84779. else if (this.width > 1)
  84780. {
  84781. emitX = rnd.between(this.left, this.right);
  84782. }
  84783. if (y !== null)
  84784. {
  84785. emitY = y;
  84786. }
  84787. else if (this.height > 1)
  84788. {
  84789. emitY = rnd.between(this.top, this.bottom);
  84790. }
  84791. this.resetParticle(particle, emitX, emitY);
  84792. return true;
  84793. };
  84794. /**
  84795. * Helper for {@link #emitParticle}. Gets the next available particle.
  84796. *
  84797. * @private
  84798. * @return {?Phaser.Particle} The first particle with exists=false, or null
  84799. */
  84800. Phaser.Particles.Arcade.Emitter.prototype.getNextParticle = function () {
  84801. var i = this.length;
  84802. while (i--)
  84803. {
  84804. var next = this.next();
  84805. if (!next.exists)
  84806. {
  84807. return next;
  84808. }
  84809. }
  84810. return null;
  84811. };
  84812. /**
  84813. * Helper for {@link #emitParticle}. Sets particle properties and calls {@link Particle#onEmit}.
  84814. *
  84815. * @private
  84816. * @param {Phaser.Particle} particle
  84817. * @param {number} x
  84818. * @param {number} y
  84819. */
  84820. Phaser.Particles.Arcade.Emitter.prototype.resetParticle = function (particle, x, y) {
  84821. var rnd = this.game.rnd;
  84822. particle.reset(x, y);
  84823. particle.angle = 0;
  84824. particle.lifespan = this.lifespan;
  84825. if (this.particleBringToTop)
  84826. {
  84827. this.bringToTop(particle);
  84828. }
  84829. else if (this.particleSendToBack)
  84830. {
  84831. this.sendToBack(particle);
  84832. }
  84833. if (this.autoScale)
  84834. {
  84835. particle.setScaleData(this.scaleData);
  84836. }
  84837. else if (this.minParticleScale !== 1 || this.maxParticleScale !== 1)
  84838. {
  84839. particle.scale.set(rnd.realInRange(this.minParticleScale, this.maxParticleScale));
  84840. }
  84841. else if ((this._minParticleScale.x !== this._maxParticleScale.x) || (this._minParticleScale.y !== this._maxParticleScale.y))
  84842. {
  84843. particle.scale.set(rnd.realInRange(this._minParticleScale.x, this._maxParticleScale.x), rnd.realInRange(this._minParticleScale.y, this._maxParticleScale.y));
  84844. }
  84845. else
  84846. {
  84847. particle.scale.set(this._minParticleScale.x, this._minParticleScale.y);
  84848. }
  84849. if (this.autoAlpha)
  84850. {
  84851. particle.setAlphaData(this.alphaData);
  84852. }
  84853. else
  84854. {
  84855. particle.alpha = rnd.realInRange(this.minParticleAlpha, this.maxParticleAlpha);
  84856. }
  84857. particle.blendMode = this.blendMode;
  84858. var body = particle.body;
  84859. body.updateBounds();
  84860. body.bounce.copyFrom(this.bounce);
  84861. body.drag.copyFrom(this.particleDrag);
  84862. if (this.minAngle != null && this.maxAngle != null)
  84863. {
  84864. this.game.physics.arcade.velocityFromAngle(
  84865. (this.minAngle === this.maxAngle) ? this.minAngle : rnd.between(this.minAngle, this.maxAngle),
  84866. (this.minSpeed === this.maxSpeed) ? this.minSpeed : rnd.between(this.minSpeed, this.maxSpeed),
  84867. body.velocity
  84868. );
  84869. }
  84870. else
  84871. {
  84872. body.velocity.x = rnd.between(this.minParticleSpeed.x, this.maxParticleSpeed.x);
  84873. body.velocity.y = rnd.between(this.minParticleSpeed.y, this.maxParticleSpeed.y);
  84874. }
  84875. body.angularVelocity = rnd.between(this.minRotation, this.maxRotation);
  84876. body.gravity.copyFrom(this.gravity);
  84877. body.angularDrag = this.angularDrag;
  84878. particle.onEmit();
  84879. };
  84880. /**
  84881. * Destroys this Emitter, all associated child Particles and then removes itself from the Particle Manager.
  84882. *
  84883. * @method Phaser.Particles.Arcade.Emitter#destroy
  84884. */
  84885. Phaser.Particles.Arcade.Emitter.prototype.destroy = function () {
  84886. this.game.particles.remove(this);
  84887. Phaser.Group.prototype.destroy.call(this, true, false);
  84888. };
  84889. /**
  84890. * A more compact way of setting the width and height of the emitter.
  84891. *
  84892. * @method Phaser.Particles.Arcade.Emitter#setSize
  84893. * @param {number} width - The desired width of the emitter (particles are spawned randomly within these dimensions).
  84894. * @param {number} height - The desired height of the emitter.
  84895. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84896. */
  84897. Phaser.Particles.Arcade.Emitter.prototype.setSize = function (width, height) {
  84898. this.area.width = width;
  84899. this.area.height = height;
  84900. return this;
  84901. };
  84902. /**
  84903. * A more compact way of setting the X velocity range of the emitter.
  84904. * @method Phaser.Particles.Arcade.Emitter#setXSpeed
  84905. * @param {number} [min=0] - The minimum value for this range.
  84906. * @param {number} [max=0] - The maximum value for this range.
  84907. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84908. */
  84909. Phaser.Particles.Arcade.Emitter.prototype.setXSpeed = function (min, max) {
  84910. min = min || 0;
  84911. max = max || 0;
  84912. this.minParticleSpeed.x = min;
  84913. this.maxParticleSpeed.x = max;
  84914. return this;
  84915. };
  84916. /**
  84917. * A more compact way of setting the Y velocity range of the emitter.
  84918. * @method Phaser.Particles.Arcade.Emitter#setYSpeed
  84919. * @param {number} [min=0] - The minimum value for this range.
  84920. * @param {number} [max=0] - The maximum value for this range.
  84921. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84922. */
  84923. Phaser.Particles.Arcade.Emitter.prototype.setYSpeed = function (min, max) {
  84924. min = min || 0;
  84925. max = max || 0;
  84926. this.minParticleSpeed.y = min;
  84927. this.maxParticleSpeed.y = max;
  84928. return this;
  84929. };
  84930. /**
  84931. * A more compact way of setting the angular velocity constraints of the particles.
  84932. *
  84933. * @method Phaser.Particles.Arcade.Emitter#setRotation
  84934. * @param {number} [min=0] - The minimum value for this range.
  84935. * @param {number} [max=0] - The maximum value for this range.
  84936. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84937. */
  84938. Phaser.Particles.Arcade.Emitter.prototype.setRotation = function (min, max) {
  84939. min = min || 0;
  84940. max = max || 0;
  84941. this.minRotation = min;
  84942. this.maxRotation = max;
  84943. return this;
  84944. };
  84945. /**
  84946. * A more compact way of setting the alpha constraints of the particles.
  84947. * The rate parameter, if set to a value above zero, lets you set the speed at which the Particle change in alpha from min to max.
  84948. * If rate is zero, which is the default, the particle won't change alpha - instead it will pick a random alpha between min and max on emit.
  84949. *
  84950. * @method Phaser.Particles.Arcade.Emitter#setAlpha
  84951. * @param {number} [min=1] - The minimum value for this range.
  84952. * @param {number} [max=1] - The maximum value for this range.
  84953. * @param {number} [rate=0] - The rate (in ms) at which the particles will change in alpha from min to max, or set to zero to pick a random alpha between the two.
  84954. * @param {function} [ease=Phaser.Easing.Linear.None] - If you've set a rate > 0 this is the easing formula applied between the min and max values.
  84955. * @param {boolean} [yoyo=false] - If you've set a rate > 0 you can set if the ease will yoyo or not (i.e. ease back to its original values)
  84956. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84957. */
  84958. Phaser.Particles.Arcade.Emitter.prototype.setAlpha = function (min, max, rate, ease, yoyo) {
  84959. if (min === undefined) { min = 1; }
  84960. if (max === undefined) { max = 1; }
  84961. if (rate === undefined) { rate = 0; }
  84962. if (ease === undefined) { ease = Phaser.Easing.Linear.None; }
  84963. if (yoyo === undefined) { yoyo = false; }
  84964. this.minParticleAlpha = min;
  84965. this.maxParticleAlpha = max;
  84966. this.autoAlpha = false;
  84967. if (rate > 0 && min !== max)
  84968. {
  84969. var tweenData = { v: min };
  84970. var tween = this.game.make.tween(tweenData).to( { v: max }, rate, ease);
  84971. tween.yoyo(yoyo);
  84972. this.alphaData = tween.generateData(60);
  84973. // Inverse it so we don't have to do array length look-ups in Particle update loops
  84974. this.alphaData.reverse();
  84975. this.autoAlpha = true;
  84976. }
  84977. return this;
  84978. };
  84979. /**
  84980. * A more compact way of setting the scale constraints of the particles.
  84981. * The rate parameter, if set to a value above zero, lets you set the speed and ease which the Particle uses to change in scale from min to max across both axis.
  84982. * If rate is zero, which is the default, the particle won't change scale during update, instead it will pick a random scale between min and max on emit.
  84983. *
  84984. * @method Phaser.Particles.Arcade.Emitter#setScale
  84985. * @param {number} [minX=1] - The minimum value of Particle.scale.x.
  84986. * @param {number} [maxX=1] - The maximum value of Particle.scale.x.
  84987. * @param {number} [minY=1] - The minimum value of Particle.scale.y.
  84988. * @param {number} [maxY=1] - The maximum value of Particle.scale.y.
  84989. * @param {number} [rate=0] - The rate (in ms) at which the particles will change in scale from min to max, or set to zero to pick a random size between the two.
  84990. * @param {function} [ease=Phaser.Easing.Linear.None] - If you've set a rate > 0 this is the easing formula applied between the min and max values.
  84991. * @param {boolean} [yoyo=false] - If you've set a rate > 0 you can set if the ease will yoyo or not (i.e. ease back to its original values)
  84992. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  84993. */
  84994. Phaser.Particles.Arcade.Emitter.prototype.setScale = function (minX, maxX, minY, maxY, rate, ease, yoyo) {
  84995. if (minX === undefined) { minX = 1; }
  84996. if (maxX === undefined) { maxX = 1; }
  84997. if (minY === undefined) { minY = 1; }
  84998. if (maxY === undefined) { maxY = 1; }
  84999. if (rate === undefined) { rate = 0; }
  85000. if (ease === undefined) { ease = Phaser.Easing.Linear.None; }
  85001. if (yoyo === undefined) { yoyo = false; }
  85002. // Reset these
  85003. this.minParticleScale = 1;
  85004. this.maxParticleScale = 1;
  85005. this._minParticleScale.set(minX, minY);
  85006. this._maxParticleScale.set(maxX, maxY);
  85007. this.autoScale = false;
  85008. if (rate > 0 && ((minX !== maxX) || (minY !== maxY)))
  85009. {
  85010. var tweenData = { x: minX, y: minY };
  85011. var tween = this.game.make.tween(tweenData).to( { x: maxX, y: maxY }, rate, ease);
  85012. tween.yoyo(yoyo);
  85013. this.scaleData = tween.generateData(60);
  85014. // Inverse it so we don't have to do array length look-ups in Particle update loops
  85015. this.scaleData.reverse();
  85016. this.autoScale = true;
  85017. }
  85018. return this;
  85019. };
  85020. /**
  85021. * Sets a radial pattern for emitting particles.
  85022. *
  85023. * This is a shorthand for setting {@link #minAngle}, {@link #maxAngle}, {@link #minSpeed}, and {@link #maxSpeed}.
  85024. *
  85025. * To remove the radial pattern, use `setAngle(null, null)`.
  85026. *
  85027. * @method Phaser.Particles.Arcade.Emitter#setAngle
  85028. * @param {?number} minAngle - The minimum angle of initial particle velocities, in degrees.
  85029. * @param {?number} maxAngle - The maximum angle of initial particle velocities, in degrees.
  85030. * @param {number} [minSpeed] - The minimum initial particle speed.
  85031. * @param {number} [maxSpeed] - The maximum initial particle speed.
  85032. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  85033. */
  85034. Phaser.Particles.Arcade.Emitter.prototype.setAngle = function (minAngle, maxAngle, minSpeed, maxSpeed) {
  85035. this.minAngle = minAngle;
  85036. this.maxAngle = maxAngle;
  85037. if (minSpeed != null) { this.minSpeed = minSpeed; }
  85038. if (maxSpeed != null) { this.maxSpeed = maxSpeed; }
  85039. return this;
  85040. };
  85041. /**
  85042. * Change the emitter's center to match the center of any object with a `center` property, such as an Arcade Body.
  85043. * If the object doesn't have a `center` property it will be set to the object's anchor-adjusted world position (`object.world`).
  85044. *
  85045. * @method Phaser.Particles.Arcade.Emitter#at
  85046. * @param {object|Phaser.Sprite|Phaser.Image|Phaser.TileSprite|Phaser.Text|PIXI.DisplayObject} object - The object that you wish to match the center with.
  85047. * @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
  85048. */
  85049. Phaser.Particles.Arcade.Emitter.prototype.at = function (object) {
  85050. if (object.center)
  85051. {
  85052. this.emitX = object.center.x;
  85053. this.emitY = object.center.y;
  85054. }
  85055. else
  85056. {
  85057. this.emitX = object.world.x + (object.anchor.x * object.width);
  85058. this.emitY = object.world.y + (object.anchor.y * object.height);
  85059. }
  85060. return this;
  85061. };
  85062. /**
  85063. * @name Phaser.Particles.Arcade.Emitter#gravity
  85064. * @property {Phaser.Point} gravity - Sets the `body.gravity` of each particle sprite to this on launch.
  85065. */
  85066. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "gravity", {
  85067. get: function () {
  85068. return this._gravity;
  85069. },
  85070. set: function (value) {
  85071. if (typeof value === "number")
  85072. {
  85073. this._gravity.y = value;
  85074. }
  85075. else
  85076. {
  85077. this._gravity = value;
  85078. }
  85079. }
  85080. });
  85081. /**
  85082. * @name Phaser.Particles.Arcade.Emitter#id
  85083. * @property {number} id - Gets the internal ID that represents this emitter.
  85084. */
  85085. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "id", {
  85086. get: function () {
  85087. return this._id;
  85088. }
  85089. });
  85090. /**
  85091. * @name Phaser.Particles.Arcade.Emitter#width
  85092. * @property {number} width - Gets or sets the width of the Emitter. This is the region in which a particle can be emitted.
  85093. */
  85094. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "width", {
  85095. get: function () {
  85096. return this.area.width;
  85097. },
  85098. set: function (value) {
  85099. this.area.width = value;
  85100. }
  85101. });
  85102. /**
  85103. * @name Phaser.Particles.Arcade.Emitter#height
  85104. * @property {number} height - Gets or sets the height of the Emitter. This is the region in which a particle can be emitted.
  85105. */
  85106. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "height", {
  85107. get: function () {
  85108. return this.area.height;
  85109. },
  85110. set: function (value) {
  85111. this.area.height = value;
  85112. }
  85113. });
  85114. /**
  85115. * @name Phaser.Particles.Arcade.Emitter#x
  85116. * @property {number} x - Gets or sets the x position of the Emitter.
  85117. */
  85118. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "x", {
  85119. get: function () {
  85120. return this.emitX;
  85121. },
  85122. set: function (value) {
  85123. this.emitX = value;
  85124. }
  85125. });
  85126. /**
  85127. * @name Phaser.Particles.Arcade.Emitter#y
  85128. * @property {number} y - Gets or sets the y position of the Emitter.
  85129. */
  85130. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "y", {
  85131. get: function () {
  85132. return this.emitY;
  85133. },
  85134. set: function (value) {
  85135. this.emitY = value;
  85136. }
  85137. });
  85138. /**
  85139. * @name Phaser.Particles.Arcade.Emitter#left
  85140. * @property {number} left - Gets the left position of the Emitter.
  85141. * @readonly
  85142. */
  85143. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "left", {
  85144. get: function () {
  85145. return Math.floor(this.x - (this.area.width / 2));
  85146. }
  85147. });
  85148. /**
  85149. * @name Phaser.Particles.Arcade.Emitter#right
  85150. * @property {number} right - Gets the right position of the Emitter.
  85151. * @readonly
  85152. */
  85153. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "right", {
  85154. get: function () {
  85155. return Math.floor(this.x + (this.area.width / 2));
  85156. }
  85157. });
  85158. /**
  85159. * @name Phaser.Particles.Arcade.Emitter#top
  85160. * @property {number} top - Gets the top position of the Emitter.
  85161. * @readonly
  85162. */
  85163. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "top", {
  85164. get: function () {
  85165. return Math.floor(this.y - (this.area.height / 2));
  85166. }
  85167. });
  85168. /**
  85169. * @name Phaser.Particles.Arcade.Emitter#bottom
  85170. * @property {number} bottom - Gets the bottom position of the Emitter.
  85171. * @readonly
  85172. */
  85173. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "bottom", {
  85174. get: function () {
  85175. return Math.floor(this.y + (this.area.height / 2));
  85176. }
  85177. });
  85178. /**
  85179. * @name Phaser.Particles.Arcade.Emitter#output
  85180. * @property {number} output - The number of particles released per second, after calling {@link #flow}.
  85181. * @readonly
  85182. */
  85183. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "output", {
  85184. get: function () {
  85185. return 1000 * this._flowQuantity / this.frequency;
  85186. }
  85187. });
  85188. /**
  85189. * @name Phaser.Particles.Arcade.Emitter#lifespanOutput
  85190. * @property {number} lifespanOutput - The number of particles released during one particle's {@link #lifespan}, after calling {@link #flow}.
  85191. * @readonly
  85192. */
  85193. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "lifespanOutput", {
  85194. get: function () {
  85195. return (this.lifespan === 0 ? Infinity : this.lifespan) * this._flowQuantity / this.frequency;
  85196. }
  85197. });
  85198. /**
  85199. * @name Phaser.Particles.Arcade.Emitter#remainder
  85200. * @property {number} remainder - The expected number of unreleased particles after a flow interval of {@link #lifespan}, after calling {@link #flow}.
  85201. * @readonly
  85202. */
  85203. Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "remainder", {
  85204. get: function () {
  85205. return this.maxParticles - this.lifespanOutput;
  85206. }
  85207. });
  85208. /**
  85209. * The last particle released, if any.
  85210. *
  85211. * You should treat this as read-only (and also avoid {@link #next} and {@link #previous}) once the emitter is started. Phaser uses it internally to track particles.
  85212. *
  85213. * @name Phaser.Particles.Arcade.Emitter#cursor
  85214. * @property {?DisplayObject} cursor
  85215. * @readonly
  85216. */
  85217. // Inherited from Phaser.Group#cursor
  85218. /**
  85219. * Advances the cursor to the next particle.
  85220. *
  85221. * @method Phaser.Particles.Arcade.Emitter#next
  85222. * @protected
  85223. * @return {any} The child the cursor now points to.
  85224. */
  85225. // Inherited from Phaser.Group#next
  85226. /**
  85227. * Moves the group cursor to the previous particle.
  85228. *
  85229. * @method Phaser.Particles.Arcade.Emitter#previous
  85230. * @protected
  85231. * @return {any} The child the cursor now points to.
  85232. */
  85233. // Inherited from Phaser.Group#previous
  85234. /**
  85235. * @author Richard Davey <rich@photonstorm.com>
  85236. * @copyright 2016 Photon Storm Ltd.
  85237. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  85238. */
  85239. /**
  85240. * The Weapon Plugin provides the ability to easily create a bullet pool and manager.
  85241. *
  85242. * Weapons fire Phaser.Bullet objects, which are essentially Sprites with a few extra properties.
  85243. * The Bullets are enabled for Arcade Physics. They do not currently work with P2 Physics.
  85244. *
  85245. * The Bullets are created inside of `Weapon.bullets`, which is a Phaser.Group instance. Anything you
  85246. * can usually do with a Group, such as move it around the display list, iterate it, etc can be done
  85247. * to the bullets Group too.
  85248. *
  85249. * Bullets can have textures and even animations. You can control the speed at which they are fired,
  85250. * the firing rate, the firing angle, and even set things like gravity for them.
  85251. *
  85252. * A small example, assumed to be running from within a Phaser.State create method.
  85253. *
  85254. * `var weapon = this.add.weapon(10, 'bullet');`
  85255. * `weapon.fireFrom.set(300, 300);`
  85256. * `this.input.onDown.add(weapon.fire, this);`
  85257. *
  85258. * @class Phaser.Weapon
  85259. * @constructor
  85260. * @param {Phaser.Game} game - A reference to the current Phaser.Game instance.
  85261. * @param {Phaser.PluginManager} parent - The Phaser Plugin Manager which looks after this plugin.
  85262. */
  85263. Phaser.Weapon = function (game, parent) {
  85264. Phaser.Plugin.call(this, game, parent);
  85265. /**
  85266. * This is the Phaser.Group that contains all of the bullets managed by this plugin.
  85267. * @type {Phaser.Group}
  85268. */
  85269. this.bullets = null;
  85270. /**
  85271. * Should the bullet pool run out of bullets (i.e. they are all in flight) then this
  85272. * boolean controls if the Group will create a brand new bullet object or not.
  85273. * @type {boolean}
  85274. */
  85275. this.autoExpandBulletsGroup = false;
  85276. /**
  85277. * Will this weapon auto fire? If set to true then a new bullet will be fired
  85278. * based on the `fireRate` value.
  85279. * @type {boolean}
  85280. */
  85281. this.autofire = false;
  85282. /**
  85283. * The total number of bullets this Weapon has fired so far.
  85284. * You can limit the number of shots allowed (via `fireLimit`), and reset
  85285. * this total via `Weapon.resetShots`.
  85286. * @type {number}
  85287. */
  85288. this.shots = 0;
  85289. /**
  85290. * The maximum number of shots that this Weapon is allowed to fire before it stops.
  85291. * When the limit is his the `Weapon.onFireLimit` Signal is dispatched.
  85292. * You can reset the shot counter via `Weapon.resetShots`.
  85293. * @type {number}
  85294. */
  85295. this.fireLimit = 0;
  85296. /**
  85297. * The rate at which this Weapon can fire. The value is given in milliseconds.
  85298. * @type {number}
  85299. */
  85300. this.fireRate = 100;
  85301. /**
  85302. * This is a modifier that is added to the `fireRate` each update to add variety
  85303. * to the firing rate of the Weapon. The value is given in milliseconds.
  85304. * If you've a `fireRate` of 200 and a `fireRateVariance` of 50 then the actual
  85305. * firing rate of the Weapon will be between 150 and 250.
  85306. * @type {number}
  85307. */
  85308. this.fireRateVariance = 0;
  85309. /**
  85310. * This is a Rectangle from within which the bullets are fired. By default it's a 1x1
  85311. * rectangle, the equivalent of a Point. But you can change the width and height, and if
  85312. * larger than 1x1 it'll pick a random point within the rectangle to launch the bullet from.
  85313. * @type {Phaser.Rectangle}
  85314. */
  85315. this.fireFrom = new Phaser.Rectangle(0, 0, 1, 1);
  85316. /**
  85317. * The angle at which the bullets are fired. This can be a const such as Phaser.ANGLE_UP
  85318. * or it can be any number from 0 to 360 inclusive, where 0 degrees is to the right.
  85319. * @type {integer}
  85320. */
  85321. this.fireAngle = Phaser.ANGLE_UP;
  85322. /**
  85323. * When a Bullet is fired it can optionally inherit the velocity of the `trackedSprite` if set.
  85324. * @type {boolean}
  85325. */
  85326. this.bulletInheritSpriteSpeed = false;
  85327. /**
  85328. * The string based name of the animation that the Bullet will be given on launch.
  85329. * This is set via `Weapon.addBulletAnimation`.
  85330. * @type {string}
  85331. */
  85332. this.bulletAnimation = '';
  85333. /**
  85334. * If you've added a set of frames via `Weapon.setBulletFrames` then you can optionally
  85335. * chose for each Bullet fired to pick a random frame from the set.
  85336. * @type {boolean}
  85337. */
  85338. this.bulletFrameRandom = false;
  85339. /**
  85340. * If you've added a set of frames via `Weapon.setBulletFrames` then you can optionally
  85341. * chose for each Bullet fired to use the next frame in the set. The frame index is then
  85342. * advanced one frame until it reaches the end of the set, then it starts from the start
  85343. * again. Cycling frames like this allows you to create varied bullet effects via
  85344. * sprite sheets.
  85345. * @type {boolean}
  85346. */
  85347. this.bulletFrameCycle = false;
  85348. /**
  85349. * Should the Bullets wrap around the world bounds? This automatically calls
  85350. * `World.wrap` on the Bullet each frame. See the docs for that method for details.
  85351. * @type {boolean}
  85352. */
  85353. this.bulletWorldWrap = false;
  85354. /**
  85355. * If `bulletWorldWrap` is true then you can provide an optional padding value with this
  85356. * property. It's added to the calculations determining when the Bullet should wrap around
  85357. * the world or not. The value is given in pixels.
  85358. * @type {integer}
  85359. */
  85360. this.bulletWorldWrapPadding = 0;
  85361. /**
  85362. * An optional angle offset applied to the Bullets when they are launched.
  85363. * This is useful if for example your bullet sprites have been drawn facing up, instead of
  85364. * to the right, and you want to fire them at an angle. In which case you can set the
  85365. * angle offset to be 90 and they'll be properly rotated when fired.
  85366. * @type {number}
  85367. */
  85368. this.bulletAngleOffset = 0;
  85369. /**
  85370. * This is a variance added to the angle of Bullets when they are fired.
  85371. * If you fire from an angle of 90 and have a `bulletAngleVariance` of 20 then the actual
  85372. * angle of the Bullets will be between 70 and 110 degrees. This is a quick way to add a
  85373. * great 'spread' effect to a Weapon.
  85374. * @type {number}
  85375. */
  85376. this.bulletAngleVariance = 0;
  85377. /**
  85378. * The speed at which the bullets are fired. This value is given in pixels per second, and
  85379. * is used to set the starting velocity of the bullets.
  85380. * @type {number}
  85381. */
  85382. this.bulletSpeed = 200;
  85383. /**
  85384. * This is a variance added to the speed of Bullets when they are fired.
  85385. * If bullets have a `bulletSpeed` value of 200, and a `bulletSpeedVariance` of 50
  85386. * then the actual speed of the Bullets will be between 150 and 250 pixels per second.
  85387. * @type {number}
  85388. */
  85389. this.bulletSpeedVariance = 0;
  85390. /**
  85391. * If you've set `bulletKillType` to `Phaser.Weapon.KILL_LIFESPAN` this controls the amount
  85392. * of lifespan the Bullets have set on launch. The value is given in milliseconds.
  85393. * When a Bullet hits its lifespan limit it will be automatically killed.
  85394. * @type {number}
  85395. */
  85396. this.bulletLifespan = 0;
  85397. /**
  85398. * If you've set `bulletKillType` to `Phaser.Weapon.KILL_DISTANCE` this controls the distance
  85399. * the Bullet can travel before it is automatically killed. The distance is given in pixels.
  85400. * @type {number}
  85401. */
  85402. this.bulletKillDistance = 0;
  85403. /**
  85404. * This is the amount of gravity added to the Bullets physics body when fired.
  85405. * Gravity is expressed in pixels / second / second.
  85406. * @type {Phaser.Point}
  85407. */
  85408. this.bulletGravity = new Phaser.Point(0, 0);
  85409. /**
  85410. * Bullets can optionally adjust their rotation in-flight to match their velocity.
  85411. * This can create the effect of a bullet 'pointing' to the path it is following, for example
  85412. * an arrow being fired from a bow, and works especially well when added to `bulletGravity`.
  85413. * @type {boolean}
  85414. */
  85415. this.bulletRotateToVelocity = false;
  85416. /**
  85417. * The Texture Key that the Bullets use when rendering.
  85418. * Changing this has no effect on bullets in-flight, only on newly spawned bullets.
  85419. * @type {string}
  85420. */
  85421. this.bulletKey = '';
  85422. /**
  85423. * The Texture Frame that the Bullets use when rendering.
  85424. * Changing this has no effect on bullets in-flight, only on newly spawned bullets.
  85425. * @type {string|integer}
  85426. */
  85427. this.bulletFrame = '';
  85428. /**
  85429. * Private var that holds the public `bulletClass` property.
  85430. * @type {function}
  85431. * @private
  85432. */
  85433. this._bulletClass = Phaser.Bullet;
  85434. /**
  85435. * Private var that holds the public `bulletCollideWorldBounds` property.
  85436. * @type {boolean}
  85437. * @private
  85438. */
  85439. this._bulletCollideWorldBounds = false;
  85440. /**
  85441. * Private var that holds the public `bulletKillType` property.
  85442. * @type {integer}
  85443. * @private
  85444. */
  85445. this._bulletKillType = Phaser.Weapon.KILL_WORLD_BOUNDS;
  85446. /**
  85447. * Holds internal data about custom bullet body sizes.
  85448. *
  85449. * @type {Object}
  85450. * @private
  85451. */
  85452. this._data = {
  85453. customBody: false,
  85454. width: 0,
  85455. height: 0,
  85456. offsetX: 0,
  85457. offsetY: 0
  85458. };
  85459. /**
  85460. * This Rectangle defines the bounds that are used when determining if a Bullet should be killed or not.
  85461. * It's used in combination with `Weapon.bulletKillType` when that is set to either `Phaser.Weapon.KILL_WEAPON_BOUNDS`
  85462. * or `Phaser.Weapon.KILL_STATIC_BOUNDS`. If you are not using either of these kill types then the bounds are ignored.
  85463. * If you are tracking a Sprite or Point then the bounds are centered on that object every frame.
  85464. *
  85465. * @type {Phaser.Rectangle}
  85466. */
  85467. this.bounds = new Phaser.Rectangle();
  85468. /**
  85469. * The Rectangle used to calculate the bullet bounds from.
  85470. *
  85471. * @type {Phaser.Rectangle}
  85472. * @private
  85473. */
  85474. this.bulletBounds = game.world.bounds;
  85475. /**
  85476. * This array stores the frames added via `Weapon.setBulletFrames`.
  85477. *
  85478. * @type {Array}
  85479. * @protected
  85480. */
  85481. this.bulletFrames = [];
  85482. /**
  85483. * The index of the frame within `Weapon.bulletFrames` that is currently being used.
  85484. * This value is only used if `Weapon.bulletFrameCycle` is set to `true`.
  85485. * @type {number}
  85486. * @private
  85487. */
  85488. this.bulletFrameIndex = 0;
  85489. /**
  85490. * An internal object that stores the animation data added via `Weapon.addBulletAnimation`.
  85491. * @type {Object}
  85492. * @private
  85493. */
  85494. this.anims = {};
  85495. /**
  85496. * The onFire Signal is dispatched each time `Weapon.fire` is called, and a Bullet is
  85497. * _successfully_ launched. The callback is set two arguments: a reference to the bullet sprite itself,
  85498. * and a reference to the Weapon that fired the bullet.
  85499. *
  85500. * @type {Phaser.Signal}
  85501. */
  85502. this.onFire = new Phaser.Signal();
  85503. /**
  85504. * The onKill Signal is dispatched each time a Bullet that is in-flight is killed. This can be the result
  85505. * of leaving the Weapon bounds, an expiring lifespan, or exceeding a specified distance.
  85506. * The callback is sent one argument: A reference to the bullet sprite itself.
  85507. *
  85508. * @type {Phaser.Signal}
  85509. */
  85510. this.onKill = new Phaser.Signal();
  85511. /**
  85512. * The onFireLimit Signal is dispatched if `Weapon.fireLimit` is > 0, and a bullet launch takes the number
  85513. * of shots fired to equal the fire limit.
  85514. * The callback is sent two arguments: A reference to the Weapon that hit the limit, and the value of
  85515. * `Weapon.fireLimit`.
  85516. *
  85517. * @type {Phaser.Signal}
  85518. */
  85519. this.onFireLimit = new Phaser.Signal();
  85520. /**
  85521. * The Sprite currently being tracked by the Weapon, if any.
  85522. * This is set via the `Weapon.trackSprite` method.
  85523. *
  85524. * @type {Phaser.Sprite|Object}
  85525. */
  85526. this.trackedSprite = null;
  85527. /**
  85528. * The Pointer currently being tracked by the Weapon, if any.
  85529. * This is set via the `Weapon.trackPointer` method.
  85530. *
  85531. * @type {Phaser.Pointer}
  85532. */
  85533. this.trackedPointer = null;
  85534. /**
  85535. * If you want this Weapon to be able to fire more than 1 bullet in a single
  85536. * update, then set this property to `true`. When `true` the Weapon plugin won't
  85537. * set the shot / firing timers until the `postRender` phase of the game loop.
  85538. * This means you can call `fire` (and similar methods) as often as you like in one
  85539. * single game update.
  85540. *
  85541. * @type {boolean}
  85542. */
  85543. this.multiFire = false;
  85544. /**
  85545. * Internal multiFire test flag.
  85546. *
  85547. * @type {boolean}
  85548. */
  85549. this._hasFired = false;
  85550. /**
  85551. * If the Weapon is tracking a Sprite, should it also track the Sprites rotation?
  85552. * This is useful for a game such as Asteroids, where you want the weapon to fire based
  85553. * on the sprites rotation.
  85554. *
  85555. * @type {boolean}
  85556. */
  85557. this.trackRotation = false;
  85558. /**
  85559. * The Track Offset is a Point object that allows you to specify a pixel offset that bullets use
  85560. * when launching from a tracked Sprite or Pointer. For example if you've got a bullet that is 2x2 pixels
  85561. * in size, but you're tracking a Sprite that is 32x32, then you can set `trackOffset.x = 16` to have
  85562. * the bullet launched from the center of the Sprite.
  85563. *
  85564. * @type {Phaser.Point}
  85565. */
  85566. this.trackOffset = new Phaser.Point();
  85567. /**
  85568. * Internal firing rate time tracking variable.
  85569. *
  85570. * @type {number}
  85571. * @private
  85572. */
  85573. this._nextFire = 0;
  85574. /**
  85575. * Internal firing rate time tracking variable used by multiFire.
  85576. *
  85577. * @type {number}
  85578. * @private
  85579. */
  85580. this._tempNextFire = 0;
  85581. /**
  85582. * Internal firing rotation tracking point.
  85583. *
  85584. * @type {Phaser.Point}
  85585. * @private
  85586. */
  85587. this._rotatedPoint = new Phaser.Point();
  85588. };
  85589. Phaser.Weapon.prototype = Object.create(Phaser.Plugin.prototype);
  85590. Phaser.Weapon.prototype.constructor = Phaser.Weapon;
  85591. /**
  85592. * A `bulletKillType` constant that stops the bullets from ever being destroyed automatically.
  85593. * @constant
  85594. * @type {integer}
  85595. */
  85596. Phaser.Weapon.KILL_NEVER = 0;
  85597. /**
  85598. * A `bulletKillType` constant that automatically kills the bullets when their `bulletLifespan` expires.
  85599. * @constant
  85600. * @type {integer}
  85601. */
  85602. Phaser.Weapon.KILL_LIFESPAN = 1;
  85603. /**
  85604. * A `bulletKillType` constant that automatically kills the bullets after they
  85605. * exceed the `bulletDistance` from their original firing position.
  85606. * @constant
  85607. * @type {integer}
  85608. */
  85609. Phaser.Weapon.KILL_DISTANCE = 2;
  85610. /**
  85611. * A `bulletKillType` constant that automatically kills the bullets when they leave the `Weapon.bounds` rectangle.
  85612. * @constant
  85613. * @type {integer}
  85614. */
  85615. Phaser.Weapon.KILL_WEAPON_BOUNDS = 3;
  85616. /**
  85617. * A `bulletKillType` constant that automatically kills the bullets when they leave the `Camera.bounds` rectangle.
  85618. * @constant
  85619. * @type {integer}
  85620. */
  85621. Phaser.Weapon.KILL_CAMERA_BOUNDS = 4;
  85622. /**
  85623. * A `bulletKillType` constant that automatically kills the bullets when they leave the `World.bounds` rectangle.
  85624. * @constant
  85625. * @type {integer}
  85626. */
  85627. Phaser.Weapon.KILL_WORLD_BOUNDS = 5;
  85628. /**
  85629. * A `bulletKillType` constant that automatically kills the bullets when they leave the `Weapon.bounds` rectangle.
  85630. * @constant
  85631. * @type {integer}
  85632. */
  85633. Phaser.Weapon.KILL_STATIC_BOUNDS = 6;
  85634. /**
  85635. * This method performs two actions: First it will check to see if the `Weapon.bullets` Group exists or not,
  85636. * and if not it creates it, adding it the `group` given as the 4th argument.
  85637. *
  85638. * Then it will seed the bullet pool with the `quantity` number of Bullets, using the texture key and frame
  85639. * provided (if any).
  85640. *
  85641. * If for example you set the quantity to be 10, then this Weapon will only ever be able to have 10 bullets
  85642. * in-flight simultaneously. If you try to fire an 11th bullet then nothing will happen until one, or more, of
  85643. * the in-flight bullets have been killed, freeing them up for use by the Weapon again.
  85644. *
  85645. * If you do not wish to have a limit set, then pass in -1 as the quantity. In this instance the Weapon will
  85646. * keep increasing the size of the bullet pool as needed. It will never reduce the size of the pool however,
  85647. * so be careful it doesn't grow too large.
  85648. *
  85649. * You can either set the texture key and frame here, or via the `Weapon.bulletKey` and `Weapon.bulletFrame`
  85650. * properties. You can also animate bullets, or set them to use random frames. All Bullets belonging to a
  85651. * single Weapon instance must share the same texture key however.
  85652. *
  85653. * @method Phaser.Weapon#createBullets
  85654. * @param {integer} [quantity=1] - The quantity of bullets to seed the Weapon with. If -1 it will set the pool to automatically expand.
  85655. * @param {string} [key] - The Game.cache key of the image that this Sprite will use.
  85656. * @param {integer|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here.
  85657. * @param {Phaser.Group} [group] - Optional Group to add the object to. If not specified it will be added to the World group.
  85658. * @return {Phaser.Weapon} This Weapon instance.
  85659. */
  85660. Phaser.Weapon.prototype.createBullets = function (quantity, key, frame, group) {
  85661. if (quantity === undefined) { quantity = 1; }
  85662. if (group === undefined) { group = this.game.world; }
  85663. if (!this.bullets)
  85664. {
  85665. this.bullets = this.game.add.physicsGroup(Phaser.Physics.ARCADE, group);
  85666. this.bullets.classType = this._bulletClass;
  85667. }
  85668. if (quantity !== 0)
  85669. {
  85670. if (quantity === -1)
  85671. {
  85672. this.autoExpandBulletsGroup = true;
  85673. quantity = 1;
  85674. }
  85675. this.bullets.createMultiple(quantity, key, frame);
  85676. this.bullets.setAll('data.bulletManager', this);
  85677. this.bulletKey = key;
  85678. this.bulletFrame = frame;
  85679. }
  85680. return this;
  85681. };
  85682. /**
  85683. * Call a function on each in-flight bullet in this Weapon.
  85684. *
  85685. * See {@link Phaser.Group#forEachExists forEachExists} for more details.
  85686. *
  85687. * @method Phaser.Weapon#forEach
  85688. * @param {function} callback - The function that will be called for each applicable child. The child will be passed as the first argument.
  85689. * @param {object} callbackContext - The context in which the function should be called (usually 'this').
  85690. * @param {...any} [args=(none)] - Additional arguments to pass to the callback function, after the child item.
  85691. * @return {Phaser.Weapon} This Weapon instance.
  85692. */
  85693. Phaser.Weapon.prototype.forEach = function (callback, callbackContext) {
  85694. this.bullets.forEachExists(callback, callbackContext, arguments);
  85695. return this;
  85696. };
  85697. /**
  85698. * Sets `Body.enable` to `false` on each bullet in this Weapon.
  85699. * This has the effect of stopping them in-flight should they be moving.
  85700. * It also stops them being able to be checked for collision.
  85701. *
  85702. * @method Phaser.Weapon#pauseAll
  85703. * @return {Phaser.Weapon} This Weapon instance.
  85704. */
  85705. Phaser.Weapon.prototype.pauseAll = function () {
  85706. this.bullets.setAll('body.enable', false);
  85707. return this;
  85708. };
  85709. /**
  85710. * Sets `Body.enable` to `true` on each bullet in this Weapon.
  85711. * This has the effect of resuming their motion should they be in-flight.
  85712. * It also enables them for collision checks again.
  85713. *
  85714. * @method Phaser.Weapon#resumeAll
  85715. * @return {Phaser.Weapon} This Weapon instance.
  85716. */
  85717. Phaser.Weapon.prototype.resumeAll = function () {
  85718. this.bullets.setAll('body.enable', true);
  85719. return this;
  85720. };
  85721. /**
  85722. * Calls `Bullet.kill` on every in-flight bullet in this Weapon.
  85723. * Also re-enables their physics bodies, should they have been disabled via `pauseAll`.
  85724. *
  85725. * @method Phaser.Weapon#killAll
  85726. * @return {Phaser.Weapon} This Weapon instance.
  85727. */
  85728. Phaser.Weapon.prototype.killAll = function () {
  85729. this.bullets.callAllExists('kill', true);
  85730. this.bullets.setAll('body.enable', true);
  85731. return this;
  85732. };
  85733. /**
  85734. * Resets the `Weapon.shots` counter back to zero. This is used when you've set
  85735. * `Weapon.fireLimit`, and have hit (or just wish to reset) your limit.
  85736. *
  85737. * @method Phaser.Weapon#resetShots
  85738. * @param {integer} [newLimit] - Optionally set a new `Weapon.fireLimit`.
  85739. * @return {Phaser.Weapon} This Weapon instance.
  85740. */
  85741. Phaser.Weapon.prototype.resetShots = function (newLimit) {
  85742. this.shots = 0;
  85743. if (newLimit !== undefined)
  85744. {
  85745. this.fireLimit = newLimit;
  85746. }
  85747. return this;
  85748. };
  85749. /**
  85750. * Destroys this Weapon. It removes itself from the PluginManager, destroys
  85751. * the bullets Group, and nulls internal references.
  85752. *
  85753. * @method Phaser.Weapon#destroy
  85754. */
  85755. Phaser.Weapon.prototype.destroy = function () {
  85756. this.parent.remove(this, false);
  85757. this.bullets.destroy();
  85758. this.game = null;
  85759. this.parent = null;
  85760. this.active = false;
  85761. this.visible = false;
  85762. };
  85763. /**
  85764. * Internal update method, called by the PluginManager.
  85765. *
  85766. * @method Phaser.Weapon#update
  85767. * @protected
  85768. */
  85769. Phaser.Weapon.prototype.update = function () {
  85770. if (this._bulletKillType === Phaser.Weapon.KILL_WEAPON_BOUNDS)
  85771. {
  85772. if (this.trackedSprite)
  85773. {
  85774. this.trackedSprite.updateTransform();
  85775. this.bounds.centerOn(this.trackedSprite.worldPosition.x, this.trackedSprite.worldPosition.y);
  85776. }
  85777. else if (this.trackedPointer)
  85778. {
  85779. this.bounds.centerOn(this.trackedPointer.worldX, this.trackedPointer.worldY);
  85780. }
  85781. }
  85782. if (this.autofire)
  85783. {
  85784. this.fire();
  85785. }
  85786. };
  85787. /**
  85788. * Internal update method, called by the PluginManager.
  85789. *
  85790. * @method Phaser.Weapon#postRender
  85791. * @protected
  85792. */
  85793. Phaser.Weapon.prototype.postRender = function () {
  85794. if (!this.multiFire || !this._hasFired)
  85795. {
  85796. return;
  85797. }
  85798. this._hasFired = false;
  85799. this._nextFire = this._tempNextFire;
  85800. };
  85801. /**
  85802. * Sets this Weapon to track the given Sprite, or any Object with a public `world` Point object.
  85803. * When a Weapon tracks a Sprite it will automatically update its `fireFrom` value to match the Sprites
  85804. * position within the Game World, adjusting the coordinates based on the offset arguments.
  85805. *
  85806. * This allows you to lock a Weapon to a Sprite, so that bullets are always launched from its location.
  85807. *
  85808. * Calling `trackSprite` will reset `Weapon.trackedPointer` to null, should it have been set, as you can
  85809. * only track _either_ a Sprite, or a Pointer, at once, but not both.
  85810. *
  85811. * @method Phaser.Weapon#trackSprite
  85812. * @param {Phaser.Sprite|Object} sprite - The Sprite to track the position of.
  85813. * @param {integer} [offsetX=0] - The horizontal offset from the Sprites position to be applied to the Weapon.
  85814. * @param {integer} [offsetY=0] - The vertical offset from the Sprites position to be applied to the Weapon.
  85815. * @param {boolean} [trackRotation=false] - Should the Weapon also track the Sprites rotation?
  85816. * @return {Phaser.Weapon} This Weapon instance.
  85817. */
  85818. Phaser.Weapon.prototype.trackSprite = function (sprite, offsetX, offsetY, trackRotation) {
  85819. if (offsetX === undefined) { offsetX = 0; }
  85820. if (offsetY === undefined) { offsetY = 0; }
  85821. if (trackRotation === undefined) { trackRotation = false; }
  85822. this.trackedPointer = null;
  85823. this.trackedSprite = sprite;
  85824. this.trackRotation = trackRotation;
  85825. this.trackOffset.set(offsetX, offsetY);
  85826. return this;
  85827. };
  85828. /**
  85829. * Sets this Weapon to track the given Pointer.
  85830. * When a Weapon tracks a Pointer it will automatically update its `fireFrom` value to match the Pointers
  85831. * position within the Game World, adjusting the coordinates based on the offset arguments.
  85832. *
  85833. * This allows you to lock a Weapon to a Pointer, so that bullets are always launched from its location.
  85834. *
  85835. * Calling `trackPointer` will reset `Weapon.trackedSprite` to null, should it have been set, as you can
  85836. * only track _either_ a Pointer, or a Sprite, at once, but not both.
  85837. *
  85838. * @method Phaser.Weapon#trackPointer
  85839. * @param {Phaser.Pointer} [pointer] - The Pointer to track the position of. Defaults to `Input.activePointer` if not specified.
  85840. * @param {integer} [offsetX=0] - The horizontal offset from the Pointers position to be applied to the Weapon.
  85841. * @param {integer} [offsetY=0] - The vertical offset from the Pointers position to be applied to the Weapon.
  85842. * @return {Phaser.Weapon} This Weapon instance.
  85843. */
  85844. Phaser.Weapon.prototype.trackPointer = function (pointer, offsetX, offsetY) {
  85845. if (pointer === undefined) { pointer = this.game.input.activePointer; }
  85846. if (offsetX === undefined) { offsetX = 0; }
  85847. if (offsetY === undefined) { offsetY = 0; }
  85848. this.trackedPointer = pointer;
  85849. this.trackedSprite = null;
  85850. this.trackRotation = false;
  85851. this.trackOffset.set(offsetX, offsetY);
  85852. return this;
  85853. };
  85854. /**
  85855. * Attempts to fire multiple bullets from the positions defined in the given array.
  85856. *
  85857. * If you provide a `from` argument, or if there is a tracked Sprite or Pointer, then
  85858. * the positions are treated as __offsets__ from the given objects position.
  85859. *
  85860. * If `from` is undefined, and there is no tracked object, then the bullets are fired
  85861. * from the given positions, as they exist in the world.
  85862. *
  85863. * Calling this method sets `Weapon.multiFire = true`.
  85864. *
  85865. * If there are not enough bullets available in the pool, and the pool cannot be extended,
  85866. * then this method may not fire from all of the given positions.
  85867. *
  85868. * When the bullets are launched they have their texture and frame updated, as required.
  85869. * The velocity of the bullets are calculated based on Weapon properties like `bulletSpeed`.
  85870. *
  85871. * @method Phaser.Weapon#fireMany
  85872. * @param {array} positions - An array of positions. Each position can be any Object, as long as it has public `x` and `y` properties, such as Phaser.Point, { x: 0, y: 0 }, Phaser.Sprite, etc.
  85873. * @param {Phaser.Sprite|Phaser.Point|Object|string} [from] - Optionally fires the bullets **from** the `x` and `y` properties of this object, _instead_ of any `Weapon.trackedSprite` or `trackedPointer` that is set.
  85874. * @return {array} An array containing all of the fired Phaser.Bullet objects, if a launch was successful, otherwise an empty array.
  85875. */
  85876. Phaser.Weapon.prototype.fireMany = function (positions, from) {
  85877. this.multiFire = true;
  85878. var bullets = [];
  85879. var _this = this;
  85880. if (from || this.trackedSprite || this.trackedPointer)
  85881. {
  85882. positions.forEach(function(offset) {
  85883. bullets.push(_this.fire(from, null, null, offset.x, offset.y));
  85884. });
  85885. }
  85886. else
  85887. {
  85888. positions.forEach(function(position) {
  85889. bullets.push(_this.fire(position));
  85890. });
  85891. }
  85892. return bullets;
  85893. };
  85894. /**
  85895. * Attempts to fire a single Bullet from a tracked Sprite or Pointer, but applies an offset
  85896. * to the position first. This is the same as calling `Weapon.fire` and passing in the offset arguments.
  85897. *
  85898. * If there are no more bullets available in the pool, and the pool cannot be extended,
  85899. * then this method returns `null`. It will also return `null` if not enough time has expired since the last time
  85900. * the Weapon was fired, as defined in the `Weapon.fireRate` property.
  85901. *
  85902. * Otherwise the first available bullet is selected, launched, and returned.
  85903. *
  85904. * When the bullet is launched it has its texture and frame updated, as required. The velocity of the bullet is
  85905. * calculated based on Weapon properties like `bulletSpeed`.
  85906. *
  85907. * If you wish to fire multiple bullets in a single game update, then set `Weapon.multiFire = true`
  85908. * and you can call this method as many times as you like, per loop. See also `Weapon.fireMany`.
  85909. *
  85910. * @method Phaser.Weapon#fireOffset
  85911. * @param {number} [offsetX=0] - The horizontal offset from the position of the tracked Sprite or Pointer, as set with `Weapon.trackSprite`.
  85912. * @param {number} [offsetY=0] - The vertical offset from the position of the tracked Sprite or Pointer, as set with `Weapon.trackSprite`.
  85913. * @return {Phaser.Bullet} The fired bullet, if a launch was successful, otherwise `null`.
  85914. */
  85915. Phaser.Weapon.prototype.fireOffset = function (offsetX, offsetY) {
  85916. if (offsetX === undefined) { offsetX = 0; }
  85917. if (offsetY === undefined) { offsetY = 0; }
  85918. return this.fire(null, null, null, offsetX, offsetY);
  85919. };
  85920. /**
  85921. * Attempts to fire a single Bullet. If there are no more bullets available in the pool, and the pool cannot be extended,
  85922. * then this method returns `null`. It will also return `null` if not enough time has expired since the last time
  85923. * the Weapon was fired, as defined in the `Weapon.fireRate` property.
  85924. *
  85925. * Otherwise the first available bullet is selected, launched, and returned.
  85926. *
  85927. * The arguments are all optional, but allow you to control both where the bullet is launched from, and aimed at.
  85928. *
  85929. * If you don't provide any of the arguments then it uses those set via properties such as `Weapon.trackedSprite`,
  85930. * `Weapon.bulletAngle` and so on.
  85931. *
  85932. * When the bullet is launched it has its texture and frame updated, as required. The velocity of the bullet is
  85933. * calculated based on Weapon properties like `bulletSpeed`.
  85934. *
  85935. * If you wish to fire multiple bullets in a single game update, then set `Weapon.multiFire = true`
  85936. * and you can call `fire` as many times as you like, per loop. Multiple fires in a single update
  85937. * only counts once towards the `shots` total, but you will still receive a Signal for each bullet.
  85938. *
  85939. * @method Phaser.Weapon#fire
  85940. * @param {Phaser.Sprite|Phaser.Point|Object|string} [from] - Optionally fires the bullet **from** the `x` and `y` properties of this object. If set this overrides `Weapon.trackedSprite` or `trackedPointer`. Pass `null` to ignore it.
  85941. * @param {number} [x] - The x coordinate, in world space, to fire the bullet **towards**. If left as `undefined`, or `null`, the bullet direction is based on its angle.
  85942. * @param {number} [y] - The y coordinate, in world space, to fire the bullet **towards**. If left as `undefined`, or `null`, the bullet direction is based on its angle.
  85943. * @param {number} [offsetX=0] - If the bullet is fired from a tracked Sprite or Pointer, or the `from` argument is set, this applies a horizontal offset from the launch position.
  85944. * @param {number} [offsetY=0] - If the bullet is fired from a tracked Sprite or Pointer, or the `from` argument is set, this applies a vertical offset from the launch position.
  85945. * @return {Phaser.Bullet} The fired bullet, if a launch was successful, otherwise `null`.
  85946. */
  85947. Phaser.Weapon.prototype.fire = function (from, x, y, offsetX, offsetY) {
  85948. if (x === undefined) { x = null; }
  85949. if (y === undefined) { y = null; }
  85950. if (this.game.time.now < this._nextFire || (this.fireLimit > 0 && this.shots === this.fireLimit))
  85951. {
  85952. return null;
  85953. }
  85954. var speed = this.bulletSpeed;
  85955. // Apply +- speed variance
  85956. if (this.bulletSpeedVariance !== 0)
  85957. {
  85958. speed += Phaser.Math.between(-this.bulletSpeedVariance, this.bulletSpeedVariance);
  85959. }
  85960. if (from)
  85961. {
  85962. if (this.fireFrom.width > 1)
  85963. {
  85964. this.fireFrom.centerOn(from.x, from.y);
  85965. }
  85966. else
  85967. {
  85968. this.fireFrom.x = from.x;
  85969. this.fireFrom.y = from.y;
  85970. }
  85971. }
  85972. else if (this.trackedSprite)
  85973. {
  85974. if (this.trackRotation)
  85975. {
  85976. this._rotatedPoint.set(this.trackedSprite.world.x + this.trackOffset.x, this.trackedSprite.world.y + this.trackOffset.y);
  85977. this._rotatedPoint.rotate(this.trackedSprite.world.x, this.trackedSprite.world.y, this.trackedSprite.worldRotation);
  85978. if (this.fireFrom.width > 1)
  85979. {
  85980. this.fireFrom.centerOn(this._rotatedPoint.x, this._rotatedPoint.y);
  85981. }
  85982. else
  85983. {
  85984. this.fireFrom.x = this._rotatedPoint.x;
  85985. this.fireFrom.y = this._rotatedPoint.y;
  85986. }
  85987. }
  85988. else
  85989. {
  85990. if (this.fireFrom.width > 1)
  85991. {
  85992. this.fireFrom.centerOn(this.trackedSprite.world.x + this.trackOffset.x, this.trackedSprite.world.y + this.trackOffset.y);
  85993. }
  85994. else
  85995. {
  85996. this.fireFrom.x = this.trackedSprite.world.x + this.trackOffset.x;
  85997. this.fireFrom.y = this.trackedSprite.world.y + this.trackOffset.y;
  85998. }
  85999. }
  86000. if (this.bulletInheritSpriteSpeed)
  86001. {
  86002. speed += this.trackedSprite.body.speed;
  86003. }
  86004. }
  86005. else if (this.trackedPointer)
  86006. {
  86007. if (this.fireFrom.width > 1)
  86008. {
  86009. this.fireFrom.centerOn(this.trackedPointer.world.x + this.trackOffset.x, this.trackedPointer.world.y + this.trackOffset.y);
  86010. }
  86011. else
  86012. {
  86013. this.fireFrom.x = this.trackedPointer.world.x + this.trackOffset.x;
  86014. this.fireFrom.y = this.trackedPointer.world.y + this.trackOffset.y;
  86015. }
  86016. }
  86017. if (offsetX !== undefined)
  86018. {
  86019. this.fireFrom.x += offsetX;
  86020. }
  86021. if (offsetY !== undefined)
  86022. {
  86023. this.fireFrom.y += offsetY;
  86024. }
  86025. var fromX = (this.fireFrom.width > 1) ? this.fireFrom.randomX : this.fireFrom.x;
  86026. var fromY = (this.fireFrom.height > 1) ? this.fireFrom.randomY : this.fireFrom.y;
  86027. var angle = (this.trackRotation) ? this.trackedSprite.angle : this.fireAngle;
  86028. // The position (in world space) to fire the bullet towards, if set
  86029. if (x !== null && y !== null)
  86030. {
  86031. angle = this.game.math.radToDeg(Math.atan2(y - fromY, x - fromX));
  86032. }
  86033. // Apply +- angle variance
  86034. if (this.bulletAngleVariance !== 0)
  86035. {
  86036. angle += Phaser.Math.between(-this.bulletAngleVariance, this.bulletAngleVariance);
  86037. }
  86038. var moveX = 0;
  86039. var moveY = 0;
  86040. // Avoid sin/cos for right-angled shots
  86041. if (angle === 0 || angle === 180)
  86042. {
  86043. moveX = Math.cos(this.game.math.degToRad(angle)) * speed;
  86044. }
  86045. else if (angle === 90 || angle === 270)
  86046. {
  86047. moveY = Math.sin(this.game.math.degToRad(angle)) * speed;
  86048. }
  86049. else
  86050. {
  86051. moveX = Math.cos(this.game.math.degToRad(angle)) * speed;
  86052. moveY = Math.sin(this.game.math.degToRad(angle)) * speed;
  86053. }
  86054. var bullet = null;
  86055. if (this.autoExpandBulletsGroup)
  86056. {
  86057. bullet = this.bullets.getFirstExists(false, true, fromX, fromY, this.bulletKey, this.bulletFrame);
  86058. bullet.data.bulletManager = this;
  86059. }
  86060. else
  86061. {
  86062. bullet = this.bullets.getFirstExists(false);
  86063. }
  86064. if (bullet)
  86065. {
  86066. bullet.reset(fromX, fromY);
  86067. bullet.data.fromX = fromX;
  86068. bullet.data.fromY = fromY;
  86069. bullet.data.killType = this.bulletKillType;
  86070. bullet.data.killDistance = this.bulletKillDistance;
  86071. bullet.data.rotateToVelocity = this.bulletRotateToVelocity;
  86072. if (this.bulletKillType === Phaser.Weapon.KILL_LIFESPAN)
  86073. {
  86074. bullet.lifespan = this.bulletLifespan;
  86075. }
  86076. bullet.angle = angle + this.bulletAngleOffset;
  86077. // Frames and Animations
  86078. if (this.bulletAnimation !== '')
  86079. {
  86080. if (bullet.animations.getAnimation(this.bulletAnimation) === null)
  86081. {
  86082. var anim = this.anims[this.bulletAnimation];
  86083. bullet.animations.add(anim.name, anim.frames, anim.frameRate, anim.loop, anim.useNumericIndex);
  86084. }
  86085. bullet.animations.play(this.bulletAnimation);
  86086. }
  86087. else
  86088. {
  86089. if (this.bulletFrameCycle)
  86090. {
  86091. bullet.frame = this.bulletFrames[this.bulletFrameIndex];
  86092. this.bulletFrameIndex++;
  86093. if (this.bulletFrameIndex >= this.bulletFrames.length)
  86094. {
  86095. this.bulletFrameIndex = 0;
  86096. }
  86097. }
  86098. else if (this.bulletFrameRandom)
  86099. {
  86100. bullet.frame = this.bulletFrames[Math.floor(Math.random() * this.bulletFrames.length)];
  86101. }
  86102. }
  86103. if (bullet.data.bodyDirty)
  86104. {
  86105. if (this._data.customBody)
  86106. {
  86107. bullet.body.setSize(this._data.width, this._data.height, this._data.offsetX, this._data.offsetY);
  86108. }
  86109. bullet.body.collideWorldBounds = this.bulletCollideWorldBounds;
  86110. bullet.data.bodyDirty = false;
  86111. }
  86112. bullet.body.velocity.set(moveX, moveY);
  86113. bullet.body.gravity.set(this.bulletGravity.x, this.bulletGravity.y);
  86114. var next = 0;
  86115. if (this.bulletSpeedVariance !== 0)
  86116. {
  86117. var rate = this.fireRate;
  86118. rate += Phaser.Math.between(-this.fireRateVariance, this.fireRateVariance);
  86119. if (rate < 0)
  86120. {
  86121. rate = 0;
  86122. }
  86123. next = this.game.time.now + rate;
  86124. }
  86125. else
  86126. {
  86127. next = this.game.time.now + this.fireRate;
  86128. }
  86129. if (this.multiFire)
  86130. {
  86131. if (!this._hasFired)
  86132. {
  86133. // We only add 1 to the 'shots' count for multiFire shots
  86134. this._hasFired = true;
  86135. this._tempNextFire = next;
  86136. this.shots++;
  86137. }
  86138. }
  86139. else
  86140. {
  86141. this._nextFire = next;
  86142. this.shots++;
  86143. }
  86144. this.onFire.dispatch(bullet, this, speed);
  86145. if (this.fireLimit > 0 && this.shots === this.fireLimit)
  86146. {
  86147. this.onFireLimit.dispatch(this, this.fireLimit);
  86148. }
  86149. }
  86150. return bullet;
  86151. };
  86152. /**
  86153. * Fires a bullet **at** the given Pointer. The bullet will be launched from the `Weapon.fireFrom` position,
  86154. * or from a Tracked Sprite or Pointer, if you have one set.
  86155. *
  86156. * @method Phaser.Weapon#fireAtPointer
  86157. * @param {Phaser.Pointer} [pointer] - The Pointer to fire the bullet towards.
  86158. * @return {Phaser.Bullet} The fired bullet if successful, null otherwise.
  86159. */
  86160. Phaser.Weapon.prototype.fireAtPointer = function (pointer) {
  86161. if (pointer === undefined) { pointer = this.game.input.activePointer; }
  86162. return this.fire(null, pointer.worldX, pointer.worldY);
  86163. };
  86164. /**
  86165. * Fires a bullet **at** the given Sprite. The bullet will be launched from the `Weapon.fireFrom` position,
  86166. * or from a Tracked Sprite or Pointer, if you have one set.
  86167. *
  86168. * @method Phaser.Weapon#fireAtSprite
  86169. * @param {Phaser.Sprite} [sprite] - The Sprite to fire the bullet towards.
  86170. * @return {Phaser.Bullet} The fired bullet if successful, null otherwise.
  86171. */
  86172. Phaser.Weapon.prototype.fireAtSprite = function (sprite) {
  86173. return this.fire(null, sprite.world.x, sprite.world.y);
  86174. };
  86175. /**
  86176. * Fires a bullet **at** the given coordinates. The bullet will be launched from the `Weapon.fireFrom` position,
  86177. * or from a Tracked Sprite or Pointer, if you have one set.
  86178. *
  86179. * @method Phaser.Weapon#fireAtXY
  86180. * @param {number} [x] - The x coordinate, in world space, to fire the bullet towards.
  86181. * @param {number} [y] - The y coordinate, in world space, to fire the bullet towards.
  86182. * @return {Phaser.Bullet} The fired bullet if successful, null otherwise.
  86183. */
  86184. Phaser.Weapon.prototype.fireAtXY = function (x, y) {
  86185. return this.fire(null, x, y);
  86186. };
  86187. /**
  86188. * You can modify the size of the physics Body the Bullets use to be any dimension you need.
  86189. * This allows you to make it smaller, or larger, than the parent Sprite.
  86190. * You can also control the x and y offset of the Body. This is the position of the
  86191. * Body relative to the top-left of the Sprite _texture_.
  86192. *
  86193. * For example: If you have a Sprite with a texture that is 80x100 in size,
  86194. * and you want the physics body to be 32x32 pixels in the middle of the texture, you would do:
  86195. *
  86196. * `setSize(32 / Math.abs(this.scale.x), 32 / Math.abs(this.scale.y), 24, 34)`
  86197. *
  86198. * Where the first two parameters are the new Body size (32x32 pixels) relative to the Sprite's scale.
  86199. * 24 is the horizontal offset of the Body from the top-left of the Sprites texture, and 34
  86200. * is the vertical offset.
  86201. *
  86202. * @method Phaser.Weapon#setBulletBodyOffset
  86203. * @param {number} width - The width of the Body.
  86204. * @param {number} height - The height of the Body.
  86205. * @param {number} [offsetX] - The X offset of the Body from the top-left of the Sprites texture.
  86206. * @param {number} [offsetY] - The Y offset of the Body from the top-left of the Sprites texture.
  86207. * @return {Phaser.Weapon} The Weapon Plugin.
  86208. */
  86209. Phaser.Weapon.prototype.setBulletBodyOffset = function (width, height, offsetX, offsetY) {
  86210. if (offsetX === undefined) { offsetX = 0; }
  86211. if (offsetY === undefined) { offsetY = 0; }
  86212. this._data.customBody = true;
  86213. this._data.width = width;
  86214. this._data.height = height;
  86215. this._data.offsetX = offsetX;
  86216. this._data.offsetY = offsetY;
  86217. // Update all bullets in the pool
  86218. this.bullets.callAll('body.setSize', 'body', width, height, offsetX, offsetY);
  86219. this.bullets.setAll('data.bodyDirty', false);
  86220. return this;
  86221. };
  86222. /**
  86223. * Sets the texture frames that the bullets can use when being launched.
  86224. *
  86225. * This is intended for use when you've got numeric based frames, such as those loaded via a Sprite Sheet.
  86226. *
  86227. * It works by calling `Phaser.ArrayUtils.numberArray` internally, using the min and max values
  86228. * provided. Then it sets the frame index to be zero.
  86229. *
  86230. * You can optionally set the cycle and random booleans, to allow bullets to cycle through the frames
  86231. * when they're fired, or pick one at random.
  86232. *
  86233. * @method Phaser.Weapon#setBulletFrames
  86234. * @param {integer} min - The minimum value the frame can be. Usually zero.
  86235. * @param {integer} max - The maximum value the frame can be.
  86236. * @param {boolean} [cycle=true] - Should the bullet frames cycle as they are fired?
  86237. * @param {boolean} [random=false] - Should the bullet frames be picked at random as they are fired?
  86238. * @return {Phaser.Weapon} The Weapon Plugin.
  86239. */
  86240. Phaser.Weapon.prototype.setBulletFrames = function (min, max, cycle, random) {
  86241. if (cycle === undefined) { cycle = true; }
  86242. if (random === undefined) { random = false; }
  86243. this.bulletFrames = Phaser.ArrayUtils.numberArray(min, max);
  86244. this.bulletFrameIndex = 0;
  86245. this.bulletFrameCycle = cycle;
  86246. this.bulletFrameRandom = random;
  86247. return this;
  86248. };
  86249. /**
  86250. * Adds a new animation under the given key. Optionally set the frames, frame rate and loop.
  86251. * The arguments are all the same as for `Animation.add`, and work in the same way.
  86252. *
  86253. * `Weapon.bulletAnimation` will be set to this animation after it's created. From that point on, all
  86254. * bullets fired will play using this animation. You can swap between animations by calling this method
  86255. * several times, and then just changing the `Weapon.bulletAnimation` property to the name of the animation
  86256. * you wish to play for the next launched bullet.
  86257. *
  86258. * If you wish to stop using animations at all, set `Weapon.bulletAnimation` to '' (an empty string).
  86259. *
  86260. * @method Phaser.Weapon#addBulletAnimation
  86261. * @param {string} name - The unique (within the Weapon instance) name for the animation, i.e. "fire", "blast".
  86262. * @param {Array} [frames=null] - An array of numbers/strings that correspond to the frames to add to this animation and in which order. e.g. [1, 2, 3] or ['run0', 'run1', run2]). If null then all frames will be used.
  86263. * @param {number} [frameRate=60] - The speed at which the animation should play. The speed is given in frames per second.
  86264. * @param {boolean} [loop=false] - Whether or not the animation is looped or just plays once.
  86265. * @param {boolean} [useNumericIndex=true] - Are the given frames using numeric indexes (default) or strings?
  86266. * @return {Phaser.Weapon} The Weapon Plugin.
  86267. */
  86268. Phaser.Weapon.prototype.addBulletAnimation = function (name, frames, frameRate, loop, useNumericIndex) {
  86269. this.anims[name] = {
  86270. name: name,
  86271. frames: frames,
  86272. frameRate: frameRate,
  86273. loop: loop,
  86274. useNumericIndex: useNumericIndex
  86275. };
  86276. // Add the animation to any existing bullets in the pool
  86277. this.bullets.callAll('animations.add', 'animations', name, frames, frameRate, loop, useNumericIndex);
  86278. this.bulletAnimation = name;
  86279. return this;
  86280. };
  86281. /**
  86282. * Uses `Game.Debug` to draw some useful information about this Weapon, including the number of bullets
  86283. * both in-flight, and available. And optionally the physics debug bodies of the bullets.
  86284. *
  86285. * @method Phaser.Weapon#debug
  86286. * @param {integer} [x=16] - The coordinate, in screen space, at which to draw the Weapon debug data.
  86287. * @param {integer} [y=32] - The coordinate, in screen space, at which to draw the Weapon debug data.
  86288. * @param {boolean} [debugBodies=false] - Optionally draw the physics body of every bullet in-flight.
  86289. */
  86290. Phaser.Weapon.prototype.debug = function (x, y, debugBodies) {
  86291. if (x === undefined) { x = 16; }
  86292. if (y === undefined) { y = 32; }
  86293. if (debugBodies === undefined) { debugBodies = false; }
  86294. this.game.debug.text("Weapon Plugin", x, y);
  86295. this.game.debug.text("Bullets Alive: " + this.bullets.total + " - Total: " + this.bullets.length, x, y + 24);
  86296. if (debugBodies)
  86297. {
  86298. this.bullets.forEachExists(this.game.debug.body, this.game.debug, 'rgba(255, 0, 255, 0.8)');
  86299. }
  86300. };
  86301. /**
  86302. * The Class of the bullets that are launched by this Weapon. Defaults to {@link Phaser.Bullet}, but can be
  86303. * overridden before calling `createBullets` and set to your own class type.
  86304. *
  86305. * It should be a constructor function accepting `(game, x, y, key, frame)`.
  86306. *
  86307. * @name Phaser.Weapon#bulletClass
  86308. * @property {function} bulletClass
  86309. */
  86310. Object.defineProperty(Phaser.Weapon.prototype, "bulletClass", {
  86311. get: function () {
  86312. return this._bulletClass;
  86313. },
  86314. set: function (classType) {
  86315. this._bulletClass = classType;
  86316. // `this.bullets` exists only after createBullets()
  86317. if (this.bullets) {
  86318. this.bullets.classType = this._bulletClass;
  86319. }
  86320. }
  86321. });
  86322. /**
  86323. * This controls how the bullets will be killed. The default is `Phaser.Weapon.KILL_WORLD_BOUNDS`.
  86324. *
  86325. * There are 7 different "kill types" available:
  86326. *
  86327. * * `Phaser.Weapon.KILL_NEVER`
  86328. * The bullets are never destroyed by the Weapon. It's up to you to destroy them via your own code.
  86329. *
  86330. * * `Phaser.Weapon.KILL_LIFESPAN`
  86331. * The bullets are automatically killed when their `bulletLifespan` amount expires.
  86332. *
  86333. * * `Phaser.Weapon.KILL_DISTANCE`
  86334. * The bullets are automatically killed when they exceed `bulletDistance` pixels away from their original launch position.
  86335. *
  86336. * * `Phaser.Weapon.KILL_WEAPON_BOUNDS`
  86337. * The bullets are automatically killed when they no longer intersect with the `Weapon.bounds` rectangle.
  86338. *
  86339. * * `Phaser.Weapon.KILL_CAMERA_BOUNDS`
  86340. * The bullets are automatically killed when they no longer intersect with the `Camera.bounds` rectangle.
  86341. *
  86342. * * `Phaser.Weapon.KILL_WORLD_BOUNDS`
  86343. * The bullets are automatically killed when they no longer intersect with the `World.bounds` rectangle.
  86344. *
  86345. * * `Phaser.Weapon.KILL_STATIC_BOUNDS`
  86346. * The bullets are automatically killed when they no longer intersect with the `Weapon.bounds` rectangle.
  86347. * The difference between static bounds and weapon bounds, is that a static bounds will never be adjusted to
  86348. * match the position of a tracked sprite or pointer.
  86349. *
  86350. * @name Phaser.Weapon#bulletKillType
  86351. * @property {integer} bulletKillType
  86352. */
  86353. Object.defineProperty(Phaser.Weapon.prototype, "bulletKillType", {
  86354. get: function () {
  86355. return this._bulletKillType;
  86356. },
  86357. set: function (type) {
  86358. switch (type)
  86359. {
  86360. case Phaser.Weapon.KILL_STATIC_BOUNDS:
  86361. case Phaser.Weapon.KILL_WEAPON_BOUNDS:
  86362. this.bulletBounds = this.bounds;
  86363. break;
  86364. case Phaser.Weapon.KILL_CAMERA_BOUNDS:
  86365. this.bulletBounds = this.game.camera.view;
  86366. break;
  86367. case Phaser.Weapon.KILL_WORLD_BOUNDS:
  86368. this.bulletBounds = this.game.world.bounds;
  86369. break;
  86370. }
  86371. this._bulletKillType = type;
  86372. }
  86373. });
  86374. /**
  86375. * Should bullets collide with the World bounds or not?
  86376. *
  86377. * @name Phaser.Weapon#bulletCollideWorldBounds
  86378. * @property {boolean} bulletCollideWorldBounds
  86379. */
  86380. Object.defineProperty(Phaser.Weapon.prototype, "bulletCollideWorldBounds", {
  86381. get: function () {
  86382. return this._bulletCollideWorldBounds;
  86383. },
  86384. set: function (value) {
  86385. this._bulletCollideWorldBounds = value;
  86386. this.bullets.setAll('body.collideWorldBounds', value);
  86387. this.bullets.setAll('data.bodyDirty', false);
  86388. }
  86389. });
  86390. /**
  86391. * The x coordinate from which bullets are fired. This is the same as `Weapon.fireFrom.x`, and
  86392. * can be overridden by the `Weapon.fire` arguments.
  86393. *
  86394. * @name Phaser.Weapon#x
  86395. * @property {number} x
  86396. */
  86397. Object.defineProperty(Phaser.Weapon.prototype, "x", {
  86398. get: function () {
  86399. return this.fireFrom.x;
  86400. },
  86401. set: function (value) {
  86402. this.fireFrom.x = value;
  86403. }
  86404. });
  86405. /**
  86406. * The y coordinate from which bullets are fired. This is the same as `Weapon.fireFrom.y`, and
  86407. * can be overridden by the `Weapon.fire` arguments.
  86408. *
  86409. * @name Phaser.Weapon#y
  86410. * @property {number} y
  86411. */
  86412. Object.defineProperty(Phaser.Weapon.prototype, "y", {
  86413. get: function () {
  86414. return this.fireFrom.y;
  86415. },
  86416. set: function (value) {
  86417. this.fireFrom.y = value;
  86418. }
  86419. });
  86420. /**
  86421. * @author Richard Davey <rich@photonstorm.com>
  86422. * @copyright 2016 Photon Storm Ltd.
  86423. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  86424. */
  86425. /**
  86426. * Create a new `Bullet` object. Bullets are used by the `Phaser.Weapon` class, and are normal Sprites,
  86427. * with a few extra properties in the data object to handle Weapon specific features.
  86428. *
  86429. * @class Phaser.Bullet
  86430. * @constructor
  86431. * @extends Phaser.Sprite
  86432. * @param {Phaser.Game} game - A reference to the currently running game.
  86433. * @param {number} x - The x coordinate (in world space) to position the Particle at.
  86434. * @param {number} y - The y coordinate (in world space) to position the Particle at.
  86435. * @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Particle during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture.
  86436. * @param {string|number} frame - If this Particle is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
  86437. */
  86438. Phaser.Bullet = function (game, x, y, key, frame) {
  86439. Phaser.Sprite.call(this, game, x, y, key, frame);
  86440. this.anchor.set(0.5);
  86441. this.data = {
  86442. bulletManager: null,
  86443. fromX: 0,
  86444. fromY: 0,
  86445. bodyDirty: true,
  86446. rotateToVelocity: false,
  86447. killType: 0,
  86448. killDistance: 0
  86449. };
  86450. };
  86451. Phaser.Bullet.prototype = Object.create(Phaser.Sprite.prototype);
  86452. Phaser.Bullet.prototype.constructor = Phaser.Bullet;
  86453. /**
  86454. * Kills the Bullet, freeing it up for re-use by the Weapon bullet pool.
  86455. * Also dispatches the `Weapon.onKill` signal.
  86456. *
  86457. * @method Phaser.Bullet#kill
  86458. * @memberof Phaser.Bullet
  86459. */
  86460. Phaser.Bullet.prototype.kill = function () {
  86461. this.alive = false;
  86462. this.exists = false;
  86463. this.visible = false;
  86464. this.data.bulletManager.onKill.dispatch(this);
  86465. return this;
  86466. };
  86467. /**
  86468. * Updates the Bullet, killing as required.
  86469. *
  86470. * @method Phaser.Bullet#kill
  86471. * @memberof Phaser.Bullet
  86472. */
  86473. Phaser.Bullet.prototype.update = function () {
  86474. if (!this.exists)
  86475. {
  86476. return;
  86477. }
  86478. if (this.data.killType > Phaser.Weapon.KILL_LIFESPAN)
  86479. {
  86480. if (this.data.killType === Phaser.Weapon.KILL_DISTANCE)
  86481. {
  86482. if (this.game.physics.arcade.distanceToXY(this, this.data.fromX, this.data.fromY, true) > this.data.killDistance)
  86483. {
  86484. this.kill();
  86485. }
  86486. }
  86487. else
  86488. {
  86489. if (!this.data.bulletManager.bulletBounds.intersects(this))
  86490. {
  86491. this.kill();
  86492. }
  86493. }
  86494. }
  86495. if (this.data.rotateToVelocity)
  86496. {
  86497. this.rotation = Math.atan2(this.body.velocity.y, this.body.velocity.x);
  86498. }
  86499. if (this.data.bulletManager.bulletWorldWrap)
  86500. {
  86501. this.game.world.wrap(this, this.data.bulletManager.bulletWorldWrapPadding);
  86502. }
  86503. };
  86504. /**
  86505. * @author Richard Davey <rich@photonstorm.com>
  86506. * @copyright 2016 Photon Storm Ltd.
  86507. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  86508. */
  86509. /**
  86510. * A Video object that takes a previously loaded Video from the Phaser Cache and handles playback of it.
  86511. *
  86512. * Alternatively it takes a getUserMedia feed from an active webcam and streams the contents of that to
  86513. * the Video instead (see `startMediaStream` method)
  86514. *
  86515. * The video can then be applied to a Sprite as a texture. If multiple Sprites share the same Video texture and playback
  86516. * changes (i.e. you pause the video, or seek to a new time) then this change will be seen across all Sprites simultaneously.
  86517. *
  86518. * Due to a bug in IE11 you cannot play a video texture to a Sprite in WebGL. For IE11 force Canvas mode.
  86519. *
  86520. * If you need each Sprite to be able to play a video fully independently then you will need one Video object per Sprite.
  86521. * Please understand the obvious performance implications of doing this, and the memory required to hold videos in RAM.
  86522. *
  86523. * On some mobile browsers such as iOS Safari, you cannot play a video until the user has explicitly touched the screen.
  86524. * This works in the same way as audio unlocking. Phaser will handle the touch unlocking for you, however unlike with audio
  86525. * it's worth noting that every single Video needs to be touch unlocked, not just the first one. You can use the `changeSource`
  86526. * method to try and work around this limitation, but see the method help for details.
  86527. *
  86528. * Small screen devices, especially iPod and iPhone will launch the video in its own native video player,
  86529. * outside of the Safari browser. There is no way to avoid this, it's a device imposed limitation.
  86530. *
  86531. * Note: On iOS if you need to detect when the user presses the 'Done' button (before the video ends)
  86532. * then you need to add your own event listener
  86533. *
  86534. * @class Phaser.Video
  86535. * @constructor
  86536. * @param {Phaser.Game} game - A reference to the currently running game.
  86537. * @param {string|null} [key=null] - The key of the video file in the Phaser.Cache that this Video object will play. Set to `null` or leave undefined if you wish to use a webcam as the source. See `startMediaStream` to start webcam capture.
  86538. * @param {string|null} [url=null] - If the video hasn't been loaded then you can provide a full URL to the file here (make sure to set key to null)
  86539. */
  86540. Phaser.Video = function (game, key, url) {
  86541. if (key === undefined) { key = null; }
  86542. if (url === undefined) { url = null; }
  86543. /**
  86544. * @property {Phaser.Game} game - A reference to the currently running game.
  86545. */
  86546. this.game = game;
  86547. /**
  86548. * @property {string} key - The key of the Video in the Cache, if stored there. Will be `null` if this Video is using the webcam instead.
  86549. * @default null
  86550. */
  86551. this.key = key;
  86552. /**
  86553. * @property {number} width - The width of the video in pixels.
  86554. * @default
  86555. */
  86556. this.width = 0;
  86557. /**
  86558. * @property {number} height - The height of the video in pixels.
  86559. * @default
  86560. */
  86561. this.height = 0;
  86562. /**
  86563. * @property {number} type - The const type of this object.
  86564. * @default
  86565. */
  86566. this.type = Phaser.VIDEO;
  86567. /**
  86568. * @property {boolean} disableTextureUpload - If true this video will never send its image data to the GPU when its dirty flag is true. This only applies in WebGL.
  86569. */
  86570. this.disableTextureUpload = false;
  86571. /**
  86572. * @property {boolean} touchLocked - true if this video is currently locked awaiting a touch event. This happens on some mobile devices, such as iOS.
  86573. * @default
  86574. */
  86575. this.touchLocked = false;
  86576. /**
  86577. * @property {Phaser.Signal} onPlay - This signal is dispatched when the Video starts to play. It sends 3 parameters: a reference to the Video object, if the video is set to loop or not and the playback rate.
  86578. */
  86579. this.onPlay = new Phaser.Signal();
  86580. /**
  86581. * @property {Phaser.Signal} onChangeSource - This signal is dispatched if the Video source is changed. It sends 3 parameters: a reference to the Video object and the new width and height of the new video source.
  86582. */
  86583. this.onChangeSource = new Phaser.Signal();
  86584. /**
  86585. * @property {Phaser.Signal} onComplete - This signal is dispatched when the Video completes playback, i.e. enters an 'ended' state. On iOS specifically it also fires if the user hits the 'Done' button at any point during playback. Videos set to loop will never dispatch this signal.
  86586. */
  86587. this.onComplete = new Phaser.Signal();
  86588. /**
  86589. * @property {Phaser.Signal} onAccess - This signal is dispatched if the user allows access to their webcam.
  86590. */
  86591. this.onAccess = new Phaser.Signal();
  86592. /**
  86593. * @property {Phaser.Signal} onError - This signal is dispatched if an error occurs either getting permission to use the webcam (for a Video Stream) or when trying to play back a video file.
  86594. */
  86595. this.onError = new Phaser.Signal();
  86596. /**
  86597. * This signal is dispatched if when asking for permission to use the webcam no response is given within a the Video.timeout limit.
  86598. * This may be because the user has picked `Not now` in the permissions window, or there is a delay in establishing the LocalMediaStream.
  86599. * @property {Phaser.Signal} onTimeout
  86600. */
  86601. this.onTimeout = new Phaser.Signal();
  86602. /**
  86603. * @property {integer} timeout - The amount of ms allowed to elapsed before the Video.onTimeout signal is dispatched while waiting for webcam access.
  86604. * @default
  86605. */
  86606. this.timeout = 15000;
  86607. /**
  86608. * @property {integer} _timeOutID - setTimeout ID.
  86609. * @private
  86610. */
  86611. this._timeOutID = null;
  86612. /**
  86613. * @property {HTMLVideoElement} video - The HTML Video Element that is added to the document.
  86614. */
  86615. this.video = null;
  86616. /**
  86617. * @property {MediaStream} videoStream - The Video Stream data. Only set if this Video is streaming from the webcam via `startMediaStream`.
  86618. */
  86619. this.videoStream = null;
  86620. /**
  86621. * @property {boolean} isStreaming - Is there a streaming video source? I.e. from a webcam.
  86622. */
  86623. this.isStreaming = false;
  86624. /**
  86625. * When starting playback of a video Phaser will monitor its readyState using a setTimeout call.
  86626. * The setTimeout happens once every `Video.retryInterval` ms. It will carry on monitoring the video
  86627. * state in this manner until the `retryLimit` is reached and then abort.
  86628. * @property {integer} retryLimit
  86629. * @default
  86630. */
  86631. this.retryLimit = 20;
  86632. /**
  86633. * @property {integer} retry - The current retry attempt.
  86634. * @default
  86635. */
  86636. this.retry = 0;
  86637. /**
  86638. * @property {integer} retryInterval - The number of ms between each retry at monitoring the status of a downloading video.
  86639. * @default
  86640. */
  86641. this.retryInterval = 500;
  86642. /**
  86643. * @property {integer} _retryID - The callback ID of the retry setTimeout.
  86644. * @private
  86645. */
  86646. this._retryID = null;
  86647. /**
  86648. * @property {boolean} _codeMuted - Internal mute tracking var.
  86649. * @private
  86650. * @default
  86651. */
  86652. this._codeMuted = false;
  86653. /**
  86654. * @property {boolean} _muted - Internal mute tracking var.
  86655. * @private
  86656. * @default
  86657. */
  86658. this._muted = false;
  86659. /**
  86660. * @property {boolean} _codePaused - Internal paused tracking var.
  86661. * @private
  86662. * @default
  86663. */
  86664. this._codePaused = false;
  86665. /**
  86666. * @property {boolean} _paused - Internal paused tracking var.
  86667. * @private
  86668. * @default
  86669. */
  86670. this._paused = false;
  86671. /**
  86672. * @property {boolean} _pending - Internal var tracking play pending.
  86673. * @private
  86674. * @default
  86675. */
  86676. this._pending = false;
  86677. /**
  86678. * @property {boolean} _pendingChangeSource - Internal var tracking play pending.
  86679. * @private
  86680. * @default
  86681. */
  86682. this._pendingChangeSource = false;
  86683. /**
  86684. * @property {boolean} _autoplay - Internal var tracking autoplay when changing source.
  86685. * @private
  86686. * @default
  86687. */
  86688. this._autoplay = false;
  86689. /**
  86690. * @property {function} _endCallback - The addEventListener ended function.
  86691. * @private
  86692. */
  86693. this._endCallback = null;
  86694. /**
  86695. * @property {function} _playCallback - The addEventListener playing function.
  86696. * @private
  86697. */
  86698. this._playCallback = null;
  86699. if (key && this.game.cache.checkVideoKey(key))
  86700. {
  86701. var _video = this.game.cache.getVideo(key);
  86702. if (_video.isBlob)
  86703. {
  86704. this.createVideoFromBlob(_video.data);
  86705. }
  86706. else
  86707. {
  86708. this.video = _video.data;
  86709. }
  86710. this.width = this.video.videoWidth;
  86711. this.height = this.video.videoHeight;
  86712. }
  86713. else if (url)
  86714. {
  86715. this.createVideoFromURL(url, false);
  86716. }
  86717. /**
  86718. * @property {PIXI.BaseTexture} baseTexture - The PIXI.BaseTexture.
  86719. * @default
  86720. */
  86721. if (this.video && !url)
  86722. {
  86723. this.baseTexture = new PIXI.BaseTexture(this.video, null, this.game.resolution);
  86724. this.baseTexture.forceLoaded(this.width, this.height);
  86725. }
  86726. else
  86727. {
  86728. this.baseTexture = new PIXI.BaseTexture(Phaser.Cache.DEFAULT.baseTexture.source, null, this.game.resolution);
  86729. this.baseTexture.forceLoaded(this.width, this.height);
  86730. }
  86731. /**
  86732. * @property {PIXI.Texture} texture - The PIXI.Texture.
  86733. * @default
  86734. */
  86735. this.texture = new PIXI.Texture(this.baseTexture);
  86736. /**
  86737. * @property {Phaser.Frame} textureFrame - The Frame this video uses for rendering.
  86738. * @default
  86739. */
  86740. this.textureFrame = new Phaser.Frame(0, 0, 0, this.width, this.height, 'video');
  86741. this.texture.setFrame(this.textureFrame);
  86742. this.texture.valid = false;
  86743. if (key !== null && this.video)
  86744. {
  86745. this.texture.valid = this.video.canplay;
  86746. }
  86747. /**
  86748. * A snapshot grabbed from the video. This is initially black. Populate it by calling Video.grab().
  86749. * When called the BitmapData is updated with a grab taken from the current video playing or active video stream.
  86750. * If Phaser has been compiled without BitmapData support this property will always be `null`.
  86751. *
  86752. * @property {Phaser.BitmapData} snapshot
  86753. * @readOnly
  86754. */
  86755. this.snapshot = null;
  86756. if (Phaser.BitmapData)
  86757. {
  86758. this.snapshot = new Phaser.BitmapData(this.game, '', this.width, this.height);
  86759. }
  86760. if (this.game.device.needsTouchUnlock())
  86761. {
  86762. this.setTouchLock();
  86763. }
  86764. else
  86765. {
  86766. if (_video)
  86767. {
  86768. _video.locked = false;
  86769. }
  86770. }
  86771. };
  86772. Phaser.Video.prototype = {
  86773. /**
  86774. * Connects to an external media stream for the webcam, rather than using a local one.
  86775. *
  86776. * @method Phaser.Video#connectToMediaStream
  86777. * @param {HTMLVideoElement} video - The HTML Video Element that the stream uses.
  86778. * @param {MediaStream} stream - The Video Stream data.
  86779. * @return {Phaser.Video} This Video object for method chaining.
  86780. */
  86781. connectToMediaStream: function (video, stream) {
  86782. if (video && stream)
  86783. {
  86784. this.video = video;
  86785. this.videoStream = stream;
  86786. this.isStreaming = true;
  86787. this.baseTexture.source = this.video;
  86788. this.updateTexture(null, this.video.videoWidth, this.video.videoHeight);
  86789. this.onAccess.dispatch(this);
  86790. }
  86791. return this;
  86792. },
  86793. /**
  86794. * Instead of playing a video file this method allows you to stream video data from an attached webcam.
  86795. *
  86796. * As soon as this method is called the user will be prompted by their browser to "Allow" access to the webcam.
  86797. * If they allow it the webcam feed is directed to this Video. Call `Video.play` to start the stream.
  86798. *
  86799. * If they block the webcam the onError signal will be dispatched containing the NavigatorUserMediaError
  86800. * or MediaStreamError event.
  86801. *
  86802. * You can optionally set a width and height for the stream. If set the input will be cropped to these dimensions.
  86803. * If not given then as soon as the stream has enough data the video dimensions will be changed to match the webcam device.
  86804. * You can listen for this with the onChangeSource signal.
  86805. *
  86806. * @method Phaser.Video#startMediaStream
  86807. * @param {boolean} [captureAudio=false] - Controls if audio should be captured along with video in the video stream.
  86808. * @param {integer} [width] - The width is used to create the video stream. If not provided the video width will be set to the width of the webcam input source.
  86809. * @param {integer} [height] - The height is used to create the video stream. If not provided the video height will be set to the height of the webcam input source.
  86810. * @return {Phaser.Video} This Video object for method chaining or false if the device doesn't support getUserMedia.
  86811. */
  86812. startMediaStream: function (captureAudio, width, height) {
  86813. if (captureAudio === undefined) { captureAudio = false; }
  86814. if (width === undefined) { width = null; }
  86815. if (height === undefined) { height = null; }
  86816. if (!this.game.device.getUserMedia)
  86817. {
  86818. this.onError.dispatch(this, 'No getUserMedia');
  86819. return false;
  86820. }
  86821. if (this.videoStream !== null)
  86822. {
  86823. if (this.videoStream['active'])
  86824. {
  86825. this.videoStream.active = false;
  86826. }
  86827. else
  86828. {
  86829. this.videoStream.stop();
  86830. }
  86831. }
  86832. this.removeVideoElement();
  86833. this.video = document.createElement("video");
  86834. this.video.setAttribute('autoplay', 'autoplay');
  86835. if (width !== null)
  86836. {
  86837. this.video.width = width;
  86838. }
  86839. if (height !== null)
  86840. {
  86841. this.video.height = height;
  86842. }
  86843. // Request access to the webcam
  86844. this._timeOutID = window.setTimeout(this.getUserMediaTimeout.bind(this), this.timeout);
  86845. try {
  86846. navigator.getUserMedia(
  86847. { "audio": captureAudio, "video": true },
  86848. this.getUserMediaSuccess.bind(this),
  86849. this.getUserMediaError.bind(this)
  86850. );
  86851. }
  86852. catch (error)
  86853. {
  86854. this.getUserMediaError(error);
  86855. }
  86856. return this;
  86857. },
  86858. /**
  86859. * @method Phaser.Video#getUserMediaTimeout
  86860. * @private
  86861. */
  86862. getUserMediaTimeout: function () {
  86863. clearTimeout(this._timeOutID);
  86864. this.onTimeout.dispatch(this);
  86865. },
  86866. /**
  86867. * @method Phaser.Video#getUserMediaError
  86868. * @private
  86869. */
  86870. getUserMediaError: function (event) {
  86871. clearTimeout(this._timeOutID);
  86872. this.onError.dispatch(this, event);
  86873. },
  86874. /**
  86875. * @method Phaser.Video#getUserMediaSuccess
  86876. * @private
  86877. */
  86878. getUserMediaSuccess: function (stream) {
  86879. clearTimeout(this._timeOutID);
  86880. // Attach the stream to the video
  86881. this.videoStream = stream;
  86882. // Set the source of the video element with the stream from the camera
  86883. if (this.video.mozSrcObject !== undefined)
  86884. {
  86885. this.video.mozSrcObject = stream;
  86886. }
  86887. else
  86888. {
  86889. this.video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
  86890. }
  86891. var self = this;
  86892. this.video.onloadeddata = function () {
  86893. var retry = 10;
  86894. function checkStream () {
  86895. if (retry > 0)
  86896. {
  86897. if (self.video.videoWidth > 0)
  86898. {
  86899. // Patch for Firefox bug where the height can't be read from the video
  86900. var width = self.video.videoWidth;
  86901. var height = self.video.videoHeight;
  86902. if (isNaN(self.video.videoHeight))
  86903. {
  86904. height = width / (4/3);
  86905. }
  86906. self.video.play();
  86907. self.isStreaming = true;
  86908. self.baseTexture.source = self.video;
  86909. self.updateTexture(null, width, height);
  86910. self.onAccess.dispatch(self);
  86911. }
  86912. else
  86913. {
  86914. window.setTimeout(checkStream, 500);
  86915. }
  86916. }
  86917. else
  86918. {
  86919. console.warn('Unable to connect to video stream. Webcam error?');
  86920. }
  86921. retry--;
  86922. }
  86923. checkStream();
  86924. };
  86925. },
  86926. /**
  86927. * Creates a new Video element from the given Blob. The Blob must contain the video data in the correct encoded format.
  86928. * This method is typically called by the Phaser.Loader and Phaser.Cache for you, but is exposed publicly for convenience.
  86929. *
  86930. * @method Phaser.Video#createVideoFromBlob
  86931. * @param {Blob} blob - The Blob containing the video data.
  86932. * @return {Phaser.Video} This Video object for method chaining.
  86933. */
  86934. createVideoFromBlob: function (blob) {
  86935. var _this = this;
  86936. this.video = document.createElement("video");
  86937. this.video.controls = false;
  86938. this.video.setAttribute('autoplay', 'autoplay');
  86939. this.video.addEventListener('loadeddata', function (event) { _this.updateTexture(event); }, true);
  86940. this.video.src = window.URL.createObjectURL(blob);
  86941. this.video.canplay = true;
  86942. return this;
  86943. },
  86944. /**
  86945. * Creates a new Video element from the given URL.
  86946. *
  86947. * @method Phaser.Video#createVideoFromURL
  86948. * @param {string} url - The URL of the video.
  86949. * @param {boolean} [autoplay=false] - Automatically start the video?
  86950. * @return {Phaser.Video} This Video object for method chaining.
  86951. */
  86952. createVideoFromURL: function (url, autoplay) {
  86953. if (autoplay === undefined) { autoplay = false; }
  86954. // Invalidate the texture while we wait for the new one to load (crashes IE11 otherwise)
  86955. if (this.texture)
  86956. {
  86957. this.texture.valid = false;
  86958. }
  86959. this.video = document.createElement("video");
  86960. this.video.controls = false;
  86961. if (autoplay)
  86962. {
  86963. this.video.setAttribute('autoplay', 'autoplay');
  86964. }
  86965. this.video.src = url;
  86966. this.video.canplay = true;
  86967. this.video.load();
  86968. this.retry = this.retryLimit;
  86969. this._retryID = window.setTimeout(this.checkVideoProgress.bind(this), this.retryInterval);
  86970. this.key = url;
  86971. return this;
  86972. },
  86973. /**
  86974. * Called automatically if the video source changes and updates the internal texture dimensions.
  86975. * Then dispatches the onChangeSource signal.
  86976. *
  86977. * @method Phaser.Video#updateTexture
  86978. * @param {object} [event] - The event which triggered the texture update.
  86979. * @param {integer} [width] - The new width of the video. If undefined `video.videoWidth` is used.
  86980. * @param {integer} [height] - The new height of the video. If undefined `video.videoHeight` is used.
  86981. */
  86982. updateTexture: function (event, width, height) {
  86983. var change = false;
  86984. if (width === undefined || width === null) { width = this.video.videoWidth; change = true; }
  86985. if (height === undefined || height === null) { height = this.video.videoHeight; }
  86986. this.width = width;
  86987. this.height = height;
  86988. if (this.baseTexture.source !== this.video)
  86989. {
  86990. this.baseTexture.source = this.video;
  86991. }
  86992. this.baseTexture.forceLoaded(width, height);
  86993. this.texture.frame.resize(width, height);
  86994. this.texture.width = width;
  86995. this.texture.height = height;
  86996. this.texture.valid = true;
  86997. if (this.snapshot)
  86998. {
  86999. this.snapshot.resize(width, height);
  87000. }
  87001. if (change && this.key !== null)
  87002. {
  87003. this.onChangeSource.dispatch(this, width, height);
  87004. if (this._autoplay)
  87005. {
  87006. this.video.play();
  87007. this.onPlay.dispatch(this, this.loop, this.playbackRate);
  87008. }
  87009. }
  87010. },
  87011. /**
  87012. * Called when the video completes playback (reaches and ended state).
  87013. * Dispatches the Video.onComplete signal.
  87014. *
  87015. * @method Phaser.Video#complete
  87016. */
  87017. complete: function () {
  87018. this.onComplete.dispatch(this);
  87019. },
  87020. /**
  87021. * Starts this video playing.
  87022. *
  87023. * If the video is already playing, or has been queued to play with `changeSource` then this method just returns.
  87024. *
  87025. * @method Phaser.Video#play
  87026. * @param {boolean} [loop=false] - Should the video loop automatically when it reaches the end? Please note that at present some browsers (i.e. Chrome) do not support *seamless* video looping.
  87027. * @param {number} [playbackRate=1] - The playback rate of the video. 1 is normal speed, 2 is x2 speed, and so on. You cannot set a negative playback rate.
  87028. * @return {Phaser.Video} This Video object for method chaining.
  87029. */
  87030. play: function (loop, playbackRate) {
  87031. if (this._pendingChangeSource)
  87032. {
  87033. return this;
  87034. }
  87035. if (loop === undefined) { loop = false; }
  87036. if (playbackRate === undefined) { playbackRate = 1; }
  87037. if (this.game.sound.onMute)
  87038. {
  87039. this.game.sound.onMute.add(this.setMute, this);
  87040. this.game.sound.onUnMute.add(this.unsetMute, this);
  87041. if (this.game.sound.mute)
  87042. {
  87043. this.setMute();
  87044. }
  87045. }
  87046. this.game.onPause.add(this.setPause, this);
  87047. this.game.onResume.add(this.setResume, this);
  87048. this._endCallback = this.complete.bind(this);
  87049. this.video.addEventListener('ended', this._endCallback, true);
  87050. this.video.addEventListener('webkitendfullscreen', this._endCallback, true);
  87051. if (loop)
  87052. {
  87053. this.video.loop = 'loop';
  87054. }
  87055. else
  87056. {
  87057. this.video.loop = '';
  87058. }
  87059. this.video.playbackRate = playbackRate;
  87060. if (this.touchLocked)
  87061. {
  87062. this._pending = true;
  87063. }
  87064. else
  87065. {
  87066. this._pending = false;
  87067. if (this.key !== null)
  87068. {
  87069. if (this.video.readyState !== 4)
  87070. {
  87071. this.retry = this.retryLimit;
  87072. this._retryID = window.setTimeout(this.checkVideoProgress.bind(this), this.retryInterval);
  87073. }
  87074. else
  87075. {
  87076. this._playCallback = this.playHandler.bind(this);
  87077. this.video.addEventListener('playing', this._playCallback, true);
  87078. }
  87079. }
  87080. this.video.play();
  87081. this.onPlay.dispatch(this, loop, playbackRate);
  87082. }
  87083. return this;
  87084. },
  87085. /**
  87086. * Called when the video starts to play. Updates the texture.
  87087. *
  87088. * @method Phaser.Video#playHandler
  87089. * @private
  87090. */
  87091. playHandler: function () {
  87092. this.video.removeEventListener('playing', this._playCallback, true);
  87093. this.updateTexture();
  87094. },
  87095. /**
  87096. * Stops the video playing.
  87097. *
  87098. * This removes all locally set signals.
  87099. *
  87100. * If you only wish to pause playback of the video, to resume at a later time, use `Video.paused = true` instead.
  87101. * If the video hasn't finished downloading calling `Video.stop` will not abort the download. To do that you need to
  87102. * call `Video.destroy` instead.
  87103. *
  87104. * If you are using a video stream from a webcam then calling Stop will disconnect the MediaStream session and disable the webcam.
  87105. *
  87106. * @method Phaser.Video#stop
  87107. * @return {Phaser.Video} This Video object for method chaining.
  87108. */
  87109. stop: function () {
  87110. if (this.game.sound.onMute)
  87111. {
  87112. this.game.sound.onMute.remove(this.setMute, this);
  87113. this.game.sound.onUnMute.remove(this.unsetMute, this);
  87114. }
  87115. this.game.onPause.remove(this.setPause, this);
  87116. this.game.onResume.remove(this.setResume, this);
  87117. // Stream or file?
  87118. if (this.isStreaming)
  87119. {
  87120. if (this.video.mozSrcObject)
  87121. {
  87122. this.video.mozSrcObject.stop();
  87123. this.video.src = null;
  87124. }
  87125. else
  87126. {
  87127. this.video.src = '';
  87128. if (this.videoStream['active'])
  87129. {
  87130. this.videoStream.active = false;
  87131. }
  87132. else
  87133. {
  87134. if (this.videoStream.getTracks)
  87135. {
  87136. this.videoStream.getTracks().forEach(function (track) {
  87137. track.stop();
  87138. });
  87139. }
  87140. else
  87141. {
  87142. this.videoStream.stop();
  87143. }
  87144. }
  87145. }
  87146. this.videoStream = null;
  87147. this.isStreaming = false;
  87148. }
  87149. else
  87150. {
  87151. this.video.removeEventListener('ended', this._endCallback, true);
  87152. this.video.removeEventListener('webkitendfullscreen', this._endCallback, true);
  87153. this.video.removeEventListener('playing', this._playCallback, true);
  87154. if (this.touchLocked)
  87155. {
  87156. this._pending = false;
  87157. }
  87158. else
  87159. {
  87160. this.video.pause();
  87161. }
  87162. }
  87163. return this;
  87164. },
  87165. /**
  87166. * Updates the given Display Objects so they use this Video as their texture.
  87167. * This will replace any texture they will currently have set.
  87168. *
  87169. * @method Phaser.Video#add
  87170. * @param {Phaser.Sprite|Phaser.Sprite[]|Phaser.Image|Phaser.Image[]} object - Either a single Sprite/Image or an Array of Sprites/Images.
  87171. * @return {Phaser.Video} This Video object for method chaining.
  87172. */
  87173. add: function (object) {
  87174. if (Array.isArray(object))
  87175. {
  87176. for (var i = 0; i < object.length; i++)
  87177. {
  87178. if (object[i]['loadTexture'])
  87179. {
  87180. object[i].loadTexture(this);
  87181. }
  87182. }
  87183. }
  87184. else
  87185. {
  87186. object.loadTexture(this);
  87187. }
  87188. return this;
  87189. },
  87190. /**
  87191. * Creates a new Phaser.Image object, assigns this Video to be its texture, adds it to the world then returns it.
  87192. *
  87193. * @method Phaser.Video#addToWorld
  87194. * @param {number} [x=0] - The x coordinate to place the Image at.
  87195. * @param {number} [y=0] - The y coordinate to place the Image at.
  87196. * @param {number} [anchorX=0] - Set the x anchor point of the Image. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  87197. * @param {number} [anchorY=0] - Set the y anchor point of the Image. A value between 0 and 1, where 0 is the top-left and 1 is bottom-right.
  87198. * @param {number} [scaleX=1] - The horizontal scale factor of the Image. A value of 1 means no scaling. 2 would be twice the size, and so on.
  87199. * @param {number} [scaleY=1] - The vertical scale factor of the Image. A value of 1 means no scaling. 2 would be twice the size, and so on.
  87200. * @return {Phaser.Image} The newly added Image object.
  87201. */
  87202. addToWorld: function (x, y, anchorX, anchorY, scaleX, scaleY) {
  87203. scaleX = scaleX || 1;
  87204. scaleY = scaleY || 1;
  87205. var image = this.game.add.image(x, y, this);
  87206. image.anchor.set(anchorX, anchorY);
  87207. image.scale.set(scaleX, scaleY);
  87208. return image;
  87209. },
  87210. /**
  87211. * If the game is running in WebGL this will push the texture up to the GPU if it's dirty.
  87212. * This is called automatically if the Video is being used by a Sprite, otherwise you need to remember to call it in your render function.
  87213. * If you wish to suppress this functionality set Video.disableTextureUpload to `true`.
  87214. *
  87215. * @method Phaser.Video#render
  87216. */
  87217. render: function () {
  87218. if (!this.disableTextureUpload && this.playing)
  87219. {
  87220. this.baseTexture.dirty();
  87221. }
  87222. },
  87223. /**
  87224. * Internal handler called automatically by the Video.mute setter.
  87225. *
  87226. * @method Phaser.Video#setMute
  87227. * @private
  87228. */
  87229. setMute: function () {
  87230. if (this._muted)
  87231. {
  87232. return;
  87233. }
  87234. this._muted = true;
  87235. this.video.muted = true;
  87236. },
  87237. /**
  87238. * Internal handler called automatically by the Video.mute setter.
  87239. *
  87240. * @method Phaser.Video#unsetMute
  87241. * @private
  87242. */
  87243. unsetMute: function () {
  87244. if (!this._muted || this._codeMuted)
  87245. {
  87246. return;
  87247. }
  87248. this._muted = false;
  87249. this.video.muted = false;
  87250. },
  87251. /**
  87252. * Internal handler called automatically by the Video.paused setter.
  87253. *
  87254. * @method Phaser.Video#setPause
  87255. * @private
  87256. */
  87257. setPause: function () {
  87258. if (this._paused || this.touchLocked)
  87259. {
  87260. return;
  87261. }
  87262. this._paused = true;
  87263. this.video.pause();
  87264. },
  87265. /**
  87266. * Internal handler called automatically by the Video.paused setter.
  87267. *
  87268. * @method Phaser.Video#setResume
  87269. * @private
  87270. */
  87271. setResume: function () {
  87272. if (!this._paused || this._codePaused || this.touchLocked)
  87273. {
  87274. return;
  87275. }
  87276. this._paused = false;
  87277. if (!this.video.ended)
  87278. {
  87279. this.video.play();
  87280. }
  87281. },
  87282. /**
  87283. * On some mobile browsers you cannot play a video until the user has explicitly touched the video to allow it.
  87284. * Phaser handles this via the `setTouchLock` method. However if you have 3 different videos, maybe an "Intro", "Start" and "Game Over"
  87285. * split into three different Video objects, then you will need the user to touch-unlock every single one of them.
  87286. *
  87287. * You can avoid this by using just one Video object and simply changing the video source. Once a Video element is unlocked it remains
  87288. * unlocked, even if the source changes. So you can use this to your benefit to avoid forcing the user to 'touch' the video yet again.
  87289. *
  87290. * As you'd expect there are limitations. So far we've found that the videos need to be in the same encoding format and bitrate.
  87291. * This method will automatically handle a change in video dimensions, but if you try swapping to a different bitrate we've found it
  87292. * cannot render the new video on iOS (desktop browsers cope better).
  87293. *
  87294. * When the video source is changed the video file is requested over the network. Listen for the `onChangeSource` signal to know
  87295. * when the new video has downloaded enough content to be able to be played. Previous settings such as the volume and loop state
  87296. * are adopted automatically by the new video.
  87297. *
  87298. * @method Phaser.Video#changeSource
  87299. * @param {string} src - The new URL to change the video.src to.
  87300. * @param {boolean} [autoplay=true] - Should the video play automatically after the source has been updated?
  87301. * @return {Phaser.Video} This Video object for method chaining.
  87302. */
  87303. changeSource: function (src, autoplay) {
  87304. if (autoplay === undefined) { autoplay = true; }
  87305. // Invalidate the texture while we wait for the new one to load (crashes IE11 otherwise)
  87306. this.texture.valid = false;
  87307. this.video.pause();
  87308. this._pendingChangeSource = true;
  87309. this.retry = this.retryLimit;
  87310. this._retryID = window.setTimeout(this.checkVideoProgress.bind(this), this.retryInterval);
  87311. this.video.src = src;
  87312. this.video.load();
  87313. this._autoplay = autoplay;
  87314. if (!autoplay)
  87315. {
  87316. this.paused = true;
  87317. }
  87318. return this;
  87319. },
  87320. /**
  87321. * Internal callback that monitors the download progress of a video after changing its source.
  87322. *
  87323. * @method Phaser.Video#checkVideoProgress
  87324. * @private
  87325. */
  87326. checkVideoProgress: function () {
  87327. // if (this.video.readyState === 2 || this.video.readyState === 4)
  87328. if (this.video.readyState === 4)
  87329. {
  87330. this._pendingChangeSource = false;
  87331. // We've got enough data to update the texture for playback
  87332. this.updateTexture();
  87333. }
  87334. else
  87335. {
  87336. this.retry--;
  87337. if (this.retry > 0)
  87338. {
  87339. this._retryID = window.setTimeout(this.checkVideoProgress.bind(this), this.retryInterval);
  87340. }
  87341. else
  87342. {
  87343. console.warn('Phaser.Video: Unable to start downloading video in time', this.isStreaming);
  87344. }
  87345. }
  87346. },
  87347. /**
  87348. * Sets the Input Manager touch callback to be Video.unlock.
  87349. * Required for mobile video unlocking. Mostly just used internally.
  87350. *
  87351. * @method Phaser.Video#setTouchLock
  87352. */
  87353. setTouchLock: function () {
  87354. this.game.input.addTouchLockCallback(this.unlock, this);
  87355. this.touchLocked = true;
  87356. },
  87357. /**
  87358. * Enables the video on mobile devices, usually after the first touch.
  87359. * If the SoundManager hasn't been unlocked then this will automatically unlock that as well.
  87360. * Only one video can be pending unlock at any one time.
  87361. *
  87362. * @method Phaser.Video#unlock
  87363. */
  87364. unlock: function () {
  87365. this.touchLocked = false;
  87366. this.video.play();
  87367. this.onPlay.dispatch(this, this.loop, this.playbackRate);
  87368. if (this.key)
  87369. {
  87370. var _video = this.game.cache.getVideo(this.key);
  87371. if (_video && !_video.isBlob)
  87372. {
  87373. _video.locked = false;
  87374. }
  87375. }
  87376. return true;
  87377. },
  87378. /**
  87379. * Grabs the current frame from the Video or Video Stream and renders it to the Video.snapshot BitmapData.
  87380. *
  87381. * You can optionally set if the BitmapData should be cleared or not, the alpha and the blend mode of the draw.
  87382. *
  87383. * If you need more advanced control over the grabbing them call `Video.snapshot.copy` directly with the same parameters as BitmapData.copy.
  87384. *
  87385. * @method Phaser.Video#grab
  87386. * @param {boolean} [clear=false] - Should the BitmapData be cleared before the Video is grabbed? Unless you are using alpha or a blend mode you can usually leave this set to false.
  87387. * @param {number} [alpha=1] - The alpha that will be set on the video before drawing. A value between 0 (fully transparent) and 1, opaque.
  87388. * @param {string} [blendMode=null] - The composite blend mode that will be used when drawing. The default is no blend mode at all. This is a Canvas globalCompositeOperation value such as 'lighter' or 'xor'.
  87389. * @return {Phaser.BitmapData} A reference to the Video.snapshot BitmapData object for further method chaining.
  87390. */
  87391. grab: function (clear, alpha, blendMode) {
  87392. if (clear === undefined) { clear = false; }
  87393. if (alpha === undefined) { alpha = 1; }
  87394. if (blendMode === undefined) { blendMode = null; }
  87395. if (this.snapshot === null)
  87396. {
  87397. console.warn('Video.grab cannot run because Phaser.BitmapData is unavailable');
  87398. return;
  87399. }
  87400. if (clear)
  87401. {
  87402. this.snapshot.cls();
  87403. }
  87404. this.snapshot.copy(this.video, 0, 0, this.width, this.height, 0, 0, this.width, this.height, 0, 0, 0, 1, 1, alpha, blendMode);
  87405. return this.snapshot;
  87406. },
  87407. /**
  87408. * Removes the Video element from the DOM by calling parentNode.removeChild on itself.
  87409. * Also removes the autoplay and src attributes and nulls the reference.
  87410. *
  87411. * @method Phaser.Video#removeVideoElement
  87412. */
  87413. removeVideoElement: function () {
  87414. if (!this.video)
  87415. {
  87416. return;
  87417. }
  87418. if (this.video.parentNode)
  87419. {
  87420. this.video.parentNode.removeChild(this.video);
  87421. }
  87422. while (this.video.hasChildNodes())
  87423. {
  87424. this.video.removeChild(this.video.firstChild);
  87425. }
  87426. this.video.removeAttribute('autoplay');
  87427. this.video.removeAttribute('src');
  87428. this.video = null;
  87429. },
  87430. /**
  87431. * Destroys the Video object. This calls `Video.stop` and then `Video.removeVideoElement`.
  87432. * If any Sprites are using this Video as their texture it is up to you to manage those.
  87433. *
  87434. * @method Phaser.Video#destroy
  87435. */
  87436. destroy: function () {
  87437. this.stop();
  87438. this.removeVideoElement();
  87439. if (this.touchLocked)
  87440. {
  87441. this.game.input.touch.removeTouchLockCallback(this.unlock, this);
  87442. }
  87443. if (this._retryID)
  87444. {
  87445. window.clearTimeout(this._retryID);
  87446. }
  87447. }
  87448. };
  87449. /**
  87450. * @name Phaser.Video#currentTime
  87451. * @property {number} currentTime - The current time of the video in seconds. If set the video will attempt to seek to that point in time.
  87452. */
  87453. Object.defineProperty(Phaser.Video.prototype, "currentTime", {
  87454. get: function () {
  87455. return (this.video) ? this.video.currentTime : 0;
  87456. },
  87457. set: function (value) {
  87458. this.video.currentTime = value;
  87459. }
  87460. });
  87461. /**
  87462. * @name Phaser.Video#duration
  87463. * @property {number} duration - The duration of the video in seconds.
  87464. * @readOnly
  87465. */
  87466. Object.defineProperty(Phaser.Video.prototype, "duration", {
  87467. get: function () {
  87468. return (this.video) ? this.video.duration : 0;
  87469. }
  87470. });
  87471. /**
  87472. * @name Phaser.Video#progress
  87473. * @property {number} progress - The progress of this video. This is a value between 0 and 1, where 0 is the start and 1 is the end of the video.
  87474. * @readOnly
  87475. */
  87476. Object.defineProperty(Phaser.Video.prototype, "progress", {
  87477. get: function () {
  87478. return (this.video) ? (this.video.currentTime / this.video.duration) : 0;
  87479. }
  87480. });
  87481. /**
  87482. * @name Phaser.Video#mute
  87483. * @property {boolean} mute - Gets or sets the muted state of the Video.
  87484. */
  87485. Object.defineProperty(Phaser.Video.prototype, "mute", {
  87486. get: function () {
  87487. return this._muted;
  87488. },
  87489. set: function (value) {
  87490. value = value || null;
  87491. if (value)
  87492. {
  87493. if (this._muted)
  87494. {
  87495. return;
  87496. }
  87497. this._codeMuted = true;
  87498. this.setMute();
  87499. }
  87500. else
  87501. {
  87502. if (!this._muted)
  87503. {
  87504. return;
  87505. }
  87506. this._codeMuted = false;
  87507. this.unsetMute();
  87508. }
  87509. }
  87510. });
  87511. /**
  87512. * Gets or sets the paused state of the Video.
  87513. * If the video is still touch locked (such as on iOS devices) this call has no effect.
  87514. *
  87515. * @name Phaser.Video#paused
  87516. * @property {boolean} paused
  87517. */
  87518. Object.defineProperty(Phaser.Video.prototype, "paused", {
  87519. get: function () {
  87520. return this._paused;
  87521. },
  87522. set: function (value) {
  87523. value = value || null;
  87524. if (this.touchLocked)
  87525. {
  87526. return;
  87527. }
  87528. if (value)
  87529. {
  87530. if (this._paused)
  87531. {
  87532. return;
  87533. }
  87534. this._codePaused = true;
  87535. this.setPause();
  87536. }
  87537. else
  87538. {
  87539. if (!this._paused)
  87540. {
  87541. return;
  87542. }
  87543. this._codePaused = false;
  87544. this.setResume();
  87545. }
  87546. }
  87547. });
  87548. /**
  87549. * @name Phaser.Video#volume
  87550. * @property {number} volume - Gets or sets the volume of the Video, a value between 0 and 1. The value given is clamped to the range 0 to 1.
  87551. */
  87552. Object.defineProperty(Phaser.Video.prototype, "volume", {
  87553. get: function () {
  87554. return (this.video) ? this.video.volume : 1;
  87555. },
  87556. set: function (value) {
  87557. if (value < 0)
  87558. {
  87559. value = 0;
  87560. }
  87561. else if (value > 1)
  87562. {
  87563. value = 1;
  87564. }
  87565. if (this.video)
  87566. {
  87567. this.video.volume = value;
  87568. }
  87569. }
  87570. });
  87571. /**
  87572. * @name Phaser.Video#playbackRate
  87573. * @property {number} playbackRate - Gets or sets the playback rate of the Video. This is the speed at which the video is playing.
  87574. */
  87575. Object.defineProperty(Phaser.Video.prototype, "playbackRate", {
  87576. get: function () {
  87577. return (this.video) ? this.video.playbackRate : 1;
  87578. },
  87579. set: function (value) {
  87580. if (this.video)
  87581. {
  87582. this.video.playbackRate = value;
  87583. }
  87584. }
  87585. });
  87586. /**
  87587. * Gets or sets if the Video is set to loop.
  87588. * Please note that at present some browsers (i.e. Chrome) do not support *seamless* video looping.
  87589. * If the video isn't yet set this will always return false.
  87590. *
  87591. * @name Phaser.Video#loop
  87592. * @property {boolean} loop
  87593. */
  87594. Object.defineProperty(Phaser.Video.prototype, "loop", {
  87595. get: function () {
  87596. return (this.video) ? this.video.loop : false;
  87597. },
  87598. set: function (value) {
  87599. if (value && this.video)
  87600. {
  87601. this.video.loop = 'loop';
  87602. }
  87603. else if (this.video)
  87604. {
  87605. this.video.loop = '';
  87606. }
  87607. }
  87608. });
  87609. /**
  87610. * @name Phaser.Video#playing
  87611. * @property {boolean} playing - True if the video is currently playing (and not paused or ended), otherwise false.
  87612. * @readOnly
  87613. */
  87614. Object.defineProperty(Phaser.Video.prototype, "playing", {
  87615. get: function () {
  87616. return (this.video) ? !(this.video.paused && this.video.ended) : false;
  87617. }
  87618. });
  87619. Phaser.Video.prototype.constructor = Phaser.Video;
  87620. /* global Phaser:true */
  87621. /**
  87622. * @author Richard Davey <rich@photonstorm.com>
  87623. * @copyright 2016 Photon Storm Ltd.
  87624. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  87625. */
  87626. // Pixi expects these globals to exist
  87627. if (PIXI.blendModes === undefined)
  87628. {
  87629. PIXI.blendModes = Phaser.blendModes;
  87630. }
  87631. if (PIXI.scaleModes === undefined)
  87632. {
  87633. PIXI.scaleModes = Phaser.scaleModes;
  87634. }
  87635. if (PIXI.Texture.emptyTexture === undefined)
  87636. {
  87637. PIXI.Texture.emptyTexture = new PIXI.Texture(new PIXI.BaseTexture());
  87638. }
  87639. if (PIXI.DisplayObject._tempMatrix === undefined)
  87640. {
  87641. PIXI.DisplayObject._tempMatrix = new Phaser.Matrix();
  87642. }
  87643. PIXI.TextureSilentFail = true;
  87644. // Required by Particle Storm
  87645. PIXI.canUseNewCanvasBlendModes = function () {
  87646. return Phaser.Device.canUseMultiply;
  87647. };
  87648. /**
  87649. * @author Richard Davey <rich@photonstorm.com>
  87650. * @copyright 2016 Photon Storm Ltd.
  87651. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  87652. */
  87653. if (typeof exports !== 'undefined') {
  87654. if (typeof module !== 'undefined' && module.exports) {
  87655. exports = module.exports = Phaser;
  87656. }
  87657. exports.Phaser = Phaser;
  87658. } else if (typeof define !== 'undefined' && define.amd) {
  87659. define('Phaser', (function() { return root.Phaser = Phaser; })() );
  87660. } else {
  87661. root.Phaser = Phaser;
  87662. }
  87663. return Phaser;
  87664. }).call(this);
  87665. /*
  87666. * "What matters in this life is not what we do but what we do for others, the legacy we leave and the imprint we make." - Eric Meyer
  87667. */