From 72b8213f742962d3892659feb34ef2c283052d69 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 29 Mar 2022 18:17:06 +0100 Subject: [PATCH] feat: including black and white Flipper assets (#102) * feat: included left and right flipper assets * feat: loaded left and right flipper assets * feat: moved Flipper to components and defined controller * refactor: moved lock to FlipperJoint * refactor(sandbox): rephrased description * feat(sanbox): including Flipper example * feat: included Tracing story * feat: defined trace method * feat(sandbox): included right flipper * feat: sized Flipper to match asset * refactor: moved tests * feat: tested flipper_controller * feat: adjusted flipper size * feat(sandbox): removed TapDetector * refactor: removed unused import * fix: increased test coverage * docs: improved doc comments * fix: changing merge imports * refactor: simplified loading asset logic Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * chore: removed old Flipper asset * fix: used correct variable * feat: enchanced tracing example * refactor: renamed circleAssetShadow to assetShadow Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> --- assets/images/components/flipper.png | Bin 8287 -> 0 bytes lib/game/components/baseboard.dart | 1 - lib/game/components/board.dart | 4 + lib/game/components/chrome_dino.dart | 1 - lib/game/components/components.dart | 4 +- lib/game/components/flipper_controller.dart | 52 ++++ lib/game/components/kicker.dart | 1 - lib/game/game_assets.dart | 3 +- lib/gen/assets.gen.dart | 4 - .../assets/images/flipper/left.png | Bin 0 -> 3782 bytes .../assets/images/flipper/right.png | Bin 0 -> 3709 bytes .../lib/gen/assets.gen.dart | 17 ++ .../lib/src/components/ball.dart | 4 +- .../lib/src}/components/board_side.dart | 6 +- .../lib/src/components/components.dart | 3 + .../lib/src}/components/flipper.dart | 137 ++++----- .../lib/src}/components/joint_anchor.dart | 0 packages/pinball_components/pubspec.yaml | 1 + .../pinball_components/sandbox/lib/main.dart | 1 + .../sandbox/lib/stories/ball/basic.dart | 5 +- .../sandbox/lib/stories/flipper/basic.dart | 26 ++ .../sandbox/lib/stories/flipper/flipper.dart | 25 ++ .../sandbox/lib/stories/flipper/tracing.dart | 49 ++++ .../sandbox/lib/stories/layer/basic.dart | 5 +- .../sandbox/lib/stories/stories.dart | 1 + .../test/src}/components/board_side_test.dart | 2 +- .../test/src/components/flipper_test.dart | 133 +++++++++ .../src}/components/joint_anchor_test.dart | 2 +- test/game/components/baseboard_test.dart | 1 + test/game/components/board_test.dart | 1 + test/game/components/bonus_word_test.dart | 1 + .../components/flipper_controller_test.dart | 169 +++++++++++ test/game/components/flipper_test.dart | 275 ------------------ test/game/components/kicker_test.dart | 1 + 34 files changed, 564 insertions(+), 371 deletions(-) delete mode 100644 assets/images/components/flipper.png create mode 100644 lib/game/components/flipper_controller.dart create mode 100644 packages/pinball_components/assets/images/flipper/left.png create mode 100644 packages/pinball_components/assets/images/flipper/right.png rename {lib/game => packages/pinball_components/lib/src}/components/board_side.dart (77%) rename {lib/game => packages/pinball_components/lib/src}/components/flipper.dart (70%) rename {lib/game => packages/pinball_components/lib/src}/components/joint_anchor.dart (100%) create mode 100644 packages/pinball_components/sandbox/lib/stories/flipper/basic.dart create mode 100644 packages/pinball_components/sandbox/lib/stories/flipper/flipper.dart create mode 100644 packages/pinball_components/sandbox/lib/stories/flipper/tracing.dart rename {test/game => packages/pinball_components/test/src}/components/board_side_test.dart (92%) create mode 100644 packages/pinball_components/test/src/components/flipper_test.dart rename {test/game => packages/pinball_components/test/src}/components/joint_anchor_test.dart (94%) create mode 100644 test/game/components/flipper_controller_test.dart delete mode 100644 test/game/components/flipper_test.dart diff --git a/assets/images/components/flipper.png b/assets/images/components/flipper.png deleted file mode 100644 index f63974c482a57307fcd6bbcedd306710a10703ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8287 zcmX9^bzD>58z#r-5#ne@Hv<9b77!2-K}uRcLO`j}0;7?Xbc9l)OUcpQAl(Sc=Km^&l`fAKe*`6qAlHkJ2(Bg~q5}#8JNRWU$XKY-N{$t#4OI71oW-~iKnZcnq5dnU$4;Tbk%@#6?Ss9NK@j(vqhWdVO)Ql0Dzz z@5}tmMCl_&<69PxJz!;e+S6Yu)2vG}yB*v_p_M62b23pS)ykRVQgu{QnOrm5kFO!< z^dTsbn1+V?!o{$@(%~1~ZQKFU#I*0w*Ttpc#Mj!|nwKW}tirsNX=PlE6(byp6{IeF znUa!1Oh->|5(;{UIN^w?s(Ntx$$1Kl4S^rl+#Gvjj&PNX8|> z&3;rB1hYkatag>)eIidBZ?2y^vu0pHu%Y=QqIc+knUt zamr$7zHSjhgTl_Lp3Ke)mTG6!8_TG9hPhmp8XrhktLq|3ma9u`AziqL6E(2)!zYv! z4%8U4gK#)lS>Uj2;o1J+fSHTS0j^R+>jol@ zhoWim4>X=u)<=~7k!{RL2l_>>YUW8)w-tX!sS?c`RlQMtM3xJ1+X&J zxcCRpsE(i514MxX|0oVTC4zX0^aOChVRO(J0e^r0R$@&LeSH9VPr$}d`VFKiwR5%| z#ifnt<9wFU)$@tISFq*MO5AA{`cAdhm{j1qD@?#yQOK$KFJ{+j>?aD^`Fo5QnwMV| zeLiWrnVOkFFNS#Ca;>~?MiJZ(ejpfm9SOv~qW~!(ej!=~;j=geD-#peE_2m?w8VT~ zi2+=UrnP!zjeBON@XI#T35Wi1->cnolaJFwtd=;kip?<iF`nJk7%h=?ko`H4P5-!*eEDdN-DB6D9fXi3# zcd(AnE%ncZ@7GN8eBv*1HIkG9{%XJ~%q~58?y`)!dYdmm^truv{bQryq;Lb!4c^L)a&(j1b`tby_0(>`{a%}d6`+xFO5+?K!$gC zyoIrwCYOaK)sNVShj-AAxGcM-A&1~8@IA2j-9qimsxWWeZ5tS6V?-4S`XY%=edtJ% z){c;Ln=O>Tv!5Ot)7kxSEx!g76&DvlP6xAkU?1|o9IatIng8D zLQml8?PgyB+wSIg?g(-Ap9|~WSbeEDv%Q0ZR+sgjPxl7emnzehCa(%le;_3}Z;2F8VXb!&15whxH+yw+b2WC+ukh3= zwK!|I)3rRQn++RsSOLs&y@m8)M>y!)V87&!4y(Cp8>fNKJo(?F%cnrthO+J7ALzw8 zuoIbb^2ib8Lfz-F6s<1ymv%2&?`3^=%IX+uR{hxF5`&U1HScbov;vcd|3R>OfK+Bc zxNyqM?w<_Da!bur!C~3c0Qx60Taj3P)aCVSQHx)TvzjmKr!3CLx|7_}_t}cnZr)e6 zT6O}|s)gEq$JvRbJ0|tNsmnIQNPITom*N&+*P>xNl-54Ku&}dXd4bDm+R0!i3Ip%( zcbBXKWo1r}RNxARKn4FA&pl($>(ebi{l7nJ_dMnIc%s`)QbIcdvnp^5d-=^!v(N9` zpJhU@vH|KxVU`lI6E7ZCkP$vT@(@=P+Zs`0_U{U~>}0NfWQSsW{V08CkCBm4USK*i zk=D<|WI+Pb#f*U>p9f@3o`cm8Q_>%TZ5Ds`Z>`PkUlU^04+N3aP|3|yWxOG$Vizwx|S@(Lfnh}!;G zZYZ^)&IPbPf&^9|gCPNr@-7LfIDbRS33!-noew{7u;O*7V1-wV%3dJsl9eLVs3N

=5p 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 diff --git a/lib/game/components/baseboard.dart b/lib/game/components/baseboard.dart index d4c326e3..cdad23fc 100644 --- a/lib/game/components/baseboard.dart +++ b/lib/game/components/baseboard.dart @@ -1,7 +1,6 @@ import 'dart:math' as math; import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart'; /// {@template baseboard} diff --git a/lib/game/components/board.dart b/lib/game/components/board.dart index 1f96120e..84e6758d 100644 --- a/lib/game/components/board.dart +++ b/lib/game/components/board.dart @@ -1,5 +1,6 @@ import 'package:flame/components.dart'; import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; /// {@template board} /// The main flat surface of the [PinballGame]. @@ -95,12 +96,15 @@ class _BottomGroupSide extends Component { final flipper = Flipper( side: _side, )..initialPosition = _position; + await flipper.add(FlipperController(flipper)); + final baseboard = Baseboard(side: _side) ..initialPosition = _position + Vector2( (Baseboard.size.x / 1.6 * direction), Baseboard.size.y - 2, ); + final kicker = Kicker( side: _side, )..initialPosition = _position + diff --git a/lib/game/components/chrome_dino.dart b/lib/game/components/chrome_dino.dart index 5cf39b3c..dc280350 100644 --- a/lib/game/components/chrome_dino.dart +++ b/lib/game/components/chrome_dino.dart @@ -4,7 +4,6 @@ import 'dart:math' as math; import 'package:flame/components.dart'; import 'package:flame_forge2d/flame_forge2d.dart' hide Timer; import 'package:flutter/material.dart'; -import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart'; /// {@template chrome_dino} diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 7c3347a6..d02063c9 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -1,13 +1,11 @@ export 'ball.dart'; export 'baseboard.dart'; export 'board.dart'; -export 'board_side.dart'; export 'bonus_word.dart'; export 'chrome_dino.dart'; -export 'flipper.dart'; +export 'flipper_controller.dart'; export 'flutter_forest.dart'; export 'jetpack_ramp.dart'; -export 'joint_anchor.dart'; export 'kicker.dart'; export 'launcher_ramp.dart'; export 'plunger.dart'; diff --git a/lib/game/components/flipper_controller.dart b/lib/game/components/flipper_controller.dart new file mode 100644 index 00000000..946cfd49 --- /dev/null +++ b/lib/game/components/flipper_controller.dart @@ -0,0 +1,52 @@ +import 'package:flame/components.dart'; +import 'package:flutter/services.dart'; +import 'package:pinball_components/pinball_components.dart'; + +/// {@template flipper_controller} +/// A [Component] that controls the [Flipper]s movement. +/// {@endtemplate} +class FlipperController extends Component with KeyboardHandler { + /// {@macro flipper_controller} + FlipperController(this.flipper) : _keys = flipper.side.flipperKeys; + + /// The [Flipper] this controller is controlling. + final Flipper flipper; + + /// The [LogicalKeyboardKey]s that will control the [Flipper]. + /// + /// [onKeyEvent] method listens to when one of these keys is pressed. + final List _keys; + + @override + bool onKeyEvent( + RawKeyEvent event, + Set keysPressed, + ) { + if (!_keys.contains(event.logicalKey)) return true; + + if (event is RawKeyDownEvent) { + flipper.moveUp(); + } else if (event is RawKeyUpEvent) { + flipper.moveDown(); + } + + return false; + } +} + +extension on BoardSide { + List get flipperKeys { + switch (this) { + case BoardSide.left: + return [ + LogicalKeyboardKey.arrowLeft, + LogicalKeyboardKey.keyA, + ]; + case BoardSide.right: + return [ + LogicalKeyboardKey.arrowRight, + LogicalKeyboardKey.keyD, + ]; + } + } +} diff --git a/lib/game/components/kicker.dart b/lib/game/components/kicker.dart index dc55a52f..d9eb7932 100644 --- a/lib/game/components/kicker.dart +++ b/lib/game/components/kicker.dart @@ -4,7 +4,6 @@ import 'package:flame/extensions.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flutter/material.dart'; import 'package:geometry/geometry.dart' as geometry show centroid; -import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart'; /// {@template kicker} diff --git a/lib/game/game_assets.dart b/lib/game/game_assets.dart index 648532cf..47e41393 100644 --- a/lib/game/game_assets.dart +++ b/lib/game/game_assets.dart @@ -8,7 +8,8 @@ extension PinballGameAssetsX on PinballGame { Future preLoadAssets() async { await Future.wait([ images.load(components.Assets.images.ball.keyName), - images.load(Assets.images.components.flipper.path), + images.load(components.Assets.images.flipper.left.keyName), + images.load(components.Assets.images.flipper.right.keyName), images.load(Assets.images.components.background.path), images.load(Assets.images.components.spaceship.androidTop.path), images.load(Assets.images.components.spaceship.androidBottom.path), diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index 8c228e16..14f0e632 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -21,10 +21,6 @@ class $AssetsImagesComponentsGen { AssetGenImage get background => const AssetGenImage('assets/images/components/background.png'); - /// File path: assets/images/components/flipper.png - AssetGenImage get flipper => - const AssetGenImage('assets/images/components/flipper.png'); - $AssetsImagesComponentsSpaceshipGen get spaceship => const $AssetsImagesComponentsSpaceshipGen(); } diff --git a/packages/pinball_components/assets/images/flipper/left.png b/packages/pinball_components/assets/images/flipper/left.png new file mode 100644 index 0000000000000000000000000000000000000000..42798f28f592b9ed2a7bb2ac8fae52413db4a402 GIT binary patch literal 3782 zcmWkx2{_Yl9N*+$Be8^*Ke1Xdx7^N8^hrRIha3dH zIGwygpyRu4<`@J59X|HAfkCu<7ziYI6Ju;>d-KDJi}M|cixJVSRjrS`y>19btk%m! zkl%*E>l zQTdek%fwibRgW8j=hdRB7b_PlU7D*dsXcUE^H8~V-`*#LyZpqvyzueEP3r*B&R1uf z(oUeZj|6eP|G{A^3S~Cr&m@s(<$fH?8hn+8c$!zk`}~5uygYXY2ZwwbjW&e23`+## zu+mh72Q1M>B!MiE1e-x%vUrL4gj7{xDh_)IiyWv=^>#cV|S`agRMFZ|w`p+wKWEt(#D^F|?iV77AU1>KJ$hVC63;}PhNQ5YzNqGjKnAf^Tl zO(^1_Xft6Z`91<8kys?f+hu@?oR;D>RJm0w3lliFFAd>IC8Htm{GcA4;nHlh%;>A{ zU>yl2IX5>KpDu-p{?an{Fyiy)B&px74exzztL&H|t_R?}<)ks)As(r9`Nr>S?UI|$m^M1qbnN{cpfKv{ehBSua^3IK zXy;5YMVI*`Vf)-dXS?r-#=?jgYMeoev12Y~sO4+^VQd8*4I}1LJz!fM(^3KlAI^nM zy4Bi4k@iJ~Cl9}-LbJ+AwAtKanB)<-Kd>k(``TdK1bC05Bd+rlb$*{!V1eL#M z8;6W7tcOqfKj&=d*XqFp!ZBIKI>|S4JuiBN4)@kIH#bKD37O_jw%#E5_$+Fo=<#9xLfO_ zzn{Oq+w{keZP9Dr2A5VscgyF(B&RnIktLWU+82HKf$#XR#9j}_-1WV+VaD~>q6Y~5L^@X2oJGa-G^=Hrxa3(PoUsc$ozJoZ4YAu9Vh-Nf zI7>*8jmYZ`?x6z9#~lCXS^-mSVW(w=8$(;$XT#iNAUr5cmbL}U)@p&GqJsy*sz5iS zY2<2i`iuxdMW6&Sp*{EdL6Bgos*1n?U(P`))FJnuTu)Kzi0JG%{p4nx83g{+k0X0; z0H0ncUset7EYAM<2#WS{JbQu|hwHzKfCKBtcXb9l=M(^ohRyV(U2~7#o@GS+-k$sO zfxCGgPMydEV5C`H*#62I7#LV$`-I5)TUSUE1t9PY1m7#N0Es3jN|(#wA6p7}Vk>8@ zbgxU@qPO0+I^5js=NhzE-J-i*p~P110f+#Um}b!144l$jyemJvl)FpWe0|(~kJ-xY z*tIH*{MpAqV1%c|D3!MZTU^4{+4jm37b3UnOiDcFV`Yc}^$PLo7F}!lK&knpE%;`5 zxO;C;Up>#l020gHg(kx9m+O?C+);%ymG2kLel>)gVEZ%%f9i~FeEcwcQTZr3XW*W) z`%9P%v9B&*x}$O2En-DTNPo4{yv5}t)?R1sAJsVNnAurR2UpjGg$2@e*W>-O=f-?A zuBwY0AQNh86oEeyOl1E;3G>zKW&W2i7K@c*lq4vrVZmy-`Qr;it>@}zi?P>>i;GiE zHJSmA@2o?Mzog5ibZ$mDI6B5AB>eMK;Tpt+3bmCJb#QUvWs)CF`X7LoLI_OH^T#-n zDfQmN5BqN`cQliKe(jsHP}J2FjsKhXBi*uaDnHZ?ibW=<2o$~deYv-{*K|>trCx-q z=o}ptCZvLiE^ngDGK^l`f6}8=Np%u?Gc=?*oUhX`;;ZQm(3Mu+^5Vq{FIsuos7+M1 zT934V(Gz^tquz$Q?(+8rI(3q?(+_8L87qV~hBwo%RoB)^Il8-}w2cA5aB^_C+1ci4 zw00VO>y&(jt(;!^&5Lp@b%5vjYcFS?YEfY{f+c3reECxnfgpgRtqTdXb9EgCR3=71BMTryDs7V82jl} zXr^k9?Lm?NGASE}!?H$VY>#Cqo zLi8oUOb_9pWy?$Kfbozsa9;UMkJ&#W_H>tRsUC+ERr>t?zlk0(D-+hW<8TPi)&?ga zR`sBoni?>3O7kg<@O)_N>i*`mQ4KyGNHTycfwN((8ro8^U5_oxTJQ}156NU#*)uG& zO79^sW$%5(?)rg1zIiNptR z*Vu*^@Cz3+t6Y@2JEC?05Ddz2NH5YlX*W51S?Mkg4NI(q92~E8zZ2f>#?=fowh?h_ z37kaVP2@<%Hz!00VU%F3IlP0EdsNFCnT8QZk0#Cd8a6U z_BV}c+&oB92*%E0)t_(qo8~N+^kPU)MUvZ!gjPf4y>S_zA2VR7e_Y)!cfnY#v$tb# zHzs#dn@`2(=64jW`tIOqrn>=5g(O&|!eMx4eKk+;?2GkKb0)cyod0EAs%pYUcU&=3PNmjX&gir=H3+ZPJnGm$eRUcTT2nV?(wu7WcZwl9`xgL3NHaM= z8}#a0bf*b$6e+ebl}eibXqG*LP44X4g_fCA&S*0Vkz94;XLuN@(kTGy`zC83;^W z321JQ9x5`iVUODS6fe}V{?0j|K%4x9de^G9vezM`@EBU!f`vZI9_4L+SM<$e?7)!B zP5xy3SG$76e$>B-;9O5|*|X-yFYf#tTs*%sR~gvOv*#99Q`>(Jhn2i~W<`Da79xE{ zJEhnx?MoLyWqxxvYQNe&$piLH5BwxV#z+smC(*QW>6}0}pi-{w*FV2ZXaGc`W_&3m zO816(PH{F5yfh=^yskZ=BCE~vY|ih>DLYB)_NL+kk;+#hud4qCH{SSTaA`0Lf%&4H zz9xCQ*d~Vk9>BL>5tD@&Ov7Ot6W(3c^4q`8l+gulD_|BESb&2=QMOh;chi?%%xvuK z5dTdw4InF*Iv1=Pq^b6p`SX90O(~X!#6|nhnAC+!^}sG+fu{?Sn2O{sVuz%jc$ z=d6V47FcR&iI&cC&Jr|eAq&52{J;J*Jz`IV(tzrw7yfI0WQKW13KhCMQMV2Rz?bKK z98C*W8_PegC#Kqs(arr*i&vhW9-|HO%`;SVOycdkRe*Y;z-d|mjQ2SWHGsrxfkQguvrdeM gzDS+AE&XfLon8+e$4Fc&S2>1aaS|F7Uc*8l(j literal 0 HcmV?d00001 diff --git a/packages/pinball_components/assets/images/flipper/right.png b/packages/pinball_components/assets/images/flipper/right.png new file mode 100644 index 0000000000000000000000000000000000000000..86fbc81d7699c6c8a0d17ef040626e9b27770935 GIT binary patch literal 3709 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 literal 0 HcmV?d00001 diff --git a/packages/pinball_components/lib/gen/assets.gen.dart b/packages/pinball_components/lib/gen/assets.gen.dart index c4ed6ca0..c61923c3 100644 --- a/packages/pinball_components/lib/gen/assets.gen.dart +++ b/packages/pinball_components/lib/gen/assets.gen.dart @@ -3,12 +3,29 @@ /// FlutterGen /// ***************************************************** +// ignore_for_file: directives_ordering,unnecessary_import + import 'package:flutter/widgets.dart'; class $AssetsImagesGen { const $AssetsImagesGen(); + /// File path: assets/images/ball.png AssetGenImage get ball => const AssetGenImage('assets/images/ball.png'); + + $AssetsImagesFlipperGen get flipper => const $AssetsImagesFlipperGen(); +} + +class $AssetsImagesFlipperGen { + const $AssetsImagesFlipperGen(); + + /// File path: assets/images/flipper/left.png + AssetGenImage get left => + const AssetGenImage('assets/images/flipper/left.png'); + + /// File path: assets/images/flipper/right.png + AssetGenImage get right => + const AssetGenImage('assets/images/flipper/right.png'); } class Assets { diff --git a/packages/pinball_components/lib/src/components/ball.dart b/packages/pinball_components/lib/src/components/ball.dart index 2ceb56d7..9a2da898 100644 --- a/packages/pinball_components/lib/src/components/ball.dart +++ b/packages/pinball_components/lib/src/components/ball.dart @@ -6,7 +6,7 @@ import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:pinball_components/pinball_components.dart'; /// {@template ball} -/// A solid, [BodyType.dynamic] sphere that rolls and bounces around +/// A solid, [BodyType.dynamic] sphere that rolls and bounces around. /// {@endtemplate} class Ball extends BodyComponent with Layered, InitialPosition { @@ -90,7 +90,7 @@ class Ball extends BodyComponent } } - /// Applies a boost on this [Ball] + /// Applies a boost on this [Ball]. void boost(Vector2 impulse) { body.applyLinearImpulse(impulse); _boostTimer = _boostDuration; diff --git a/lib/game/components/board_side.dart b/packages/pinball_components/lib/src/components/board_side.dart similarity index 77% rename from lib/game/components/board_side.dart rename to packages/pinball_components/lib/src/components/board_side.dart index 2ef8d651..ac530567 100644 --- a/lib/game/components/board_side.dart +++ b/packages/pinball_components/lib/src/components/board_side.dart @@ -1,4 +1,8 @@ -import 'package:pinball/game/game.dart'; +// ignore_for_file: comment_references +// TODO(alestiago): Revisit ignore lint rule once Kicker is moved to this +// package. + +import 'package:pinball_components/pinball_components.dart'; /// Indicates a side of the board. /// diff --git a/packages/pinball_components/lib/src/components/components.dart b/packages/pinball_components/lib/src/components/components.dart index a55f9566..185ac25f 100644 --- a/packages/pinball_components/lib/src/components/components.dart +++ b/packages/pinball_components/lib/src/components/components.dart @@ -1,5 +1,8 @@ export 'ball.dart'; +export 'board_side.dart'; export 'fire_effect.dart'; +export 'flipper.dart'; export 'initial_position.dart'; +export 'joint_anchor.dart'; export 'layer.dart'; export 'shapes/shapes.dart'; diff --git a/lib/game/components/flipper.dart b/packages/pinball_components/lib/src/components/flipper.dart similarity index 70% rename from lib/game/components/flipper.dart rename to packages/pinball_components/lib/src/components/flipper.dart index 6e64c781..de5f18c8 100644 --- a/lib/game/components/flipper.dart +++ b/packages/pinball_components/lib/src/components/flipper.dart @@ -3,20 +3,7 @@ import 'dart:math' as math; import 'package:flame/components.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:flutter/services.dart'; -import 'package:pinball/game/game.dart'; -import 'package:pinball/gen/assets.gen.dart'; -import 'package:pinball_components/pinball_components.dart' hide Assets; - -const _leftFlipperKeys = [ - LogicalKeyboardKey.arrowLeft, - LogicalKeyboardKey.keyA, -]; - -const _rightFlipperKeys = [ - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.keyD, -]; +import 'package:pinball_components/pinball_components.dart'; /// {@template flipper} /// A bat, typically found in pairs at the bottom of the board. @@ -27,10 +14,10 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { /// {@macro flipper} Flipper({ required this.side, - }) : _keys = side.isLeft ? _leftFlipperKeys : _rightFlipperKeys; + }); /// The size of the [Flipper]. - static final size = Vector2(12, 2.8); + static final size = Vector2(13.5, 4.3); /// The speed required to move the [Flipper] to its highest position. /// @@ -43,27 +30,24 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { /// whereas a [Flipper] with [BoardSide.right] has a clockwise arc motion. final BoardSide side; - /// The [LogicalKeyboardKey]s that will control the [Flipper]. - /// - /// [onKeyEvent] method listens to when one of these keys is pressed. - final List _keys; - /// Applies downward linear velocity to the [Flipper], moving it to its /// resting position. - void _moveDown() { + void moveDown() { body.linearVelocity = Vector2(0, -_speed); } /// Applies upward linear velocity to the [Flipper], moving it to its highest /// position. - void _moveUp() { + void moveUp() { body.linearVelocity = Vector2(0, _speed); } /// Loads the sprite that renders with the [Flipper]. Future _loadSprite() async { final sprite = await gameRef.loadSprite( - Assets.images.components.flipper.path, + (side.isLeft) + ? Assets.images.flipper.left.keyName + : Assets.images.flipper.right.keyName, ); final spriteComponent = SpriteComponent( sprite: sprite, @@ -71,10 +55,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { anchor: Anchor.center, ); - if (side.isRight) { - spriteComponent.flipHorizontally(); - } - await add(spriteComponent); } @@ -87,30 +67,36 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { flipper: this, anchor: anchor, ); - final joint = _FlipperJoint(jointDef)..create(world); - - // FIXME(erickzanardo): when mounted the initial position is not fully - // reached. - unawaited( - mounted.whenComplete(joint.unlock), - ); + final joint = _FlipperJoint(jointDef); + world.createJoint2(joint); + unawaited(mounted.whenComplete(joint.unlock)); } List _createFixtureDefs() { final fixturesDef = []; final direction = side.direction; - final bigCircleShape = CircleShape()..radius = 1.75; + final assetShadow = Flipper.size.x * 0.012 * -direction; + final size = Vector2( + Flipper.size.x - (assetShadow * 2), + Flipper.size.y, + ); + + final bigCircleShape = CircleShape()..radius = size.y / 2 - 0.2; bigCircleShape.position.setValues( - ((size.x / 2) * direction) + (bigCircleShape.radius * -direction), + ((size.x / 2) * direction) + + (bigCircleShape.radius * -direction) + + assetShadow, 0, ); final bigCircleFixtureDef = FixtureDef(bigCircleShape); fixturesDef.add(bigCircleFixtureDef); - final smallCircleShape = CircleShape()..radius = 0.9; + final smallCircleShape = CircleShape()..radius = size.y * 0.23; smallCircleShape.position.setValues( - ((size.x / 2) * -direction) + (smallCircleShape.radius * direction), + ((size.x / 2) * -direction) + + (smallCircleShape.radius * direction) - + assetShadow, 0, ); final smallCircleFixtureDef = FixtureDef(smallCircleShape); @@ -143,7 +129,7 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { await super.onLoad(); renderBody = false; - await Future.wait([ + await Future.wait([ _loadSprite(), _anchorToJoint(), ]); @@ -160,22 +146,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { return body; } - - @override - bool onKeyEvent( - RawKeyEvent event, - Set keysPressed, - ) { - if (!_keys.contains(event.logicalKey)) return true; - - if (event is RawKeyDownEvent) { - _moveUp(); - } else if (event is RawKeyUpEvent) { - _moveDown(); - } - - return false; - } } /// {@template flipper_anchor} @@ -204,45 +174,60 @@ class _FlipperAnchorRevoluteJointDef extends RevoluteJointDef { required Flipper flipper, required _FlipperAnchor anchor, }) : side = flipper.side { + enableLimit = true; initialize( flipper.body, anchor.body, anchor.body.position, ); - - enableLimit = true; - final angle = (_sweepingAngle * -side.direction) / 2; - lowerAngle = upperAngle = angle; } - /// The total angle of the arc motion. - static const _sweepingAngle = math.pi / 3.5; - final BoardSide side; } +/// {@template flipper_joint} +/// [RevoluteJoint] that controls the arc motion of a [Flipper]. +/// {@endtemplate} class _FlipperJoint extends RevoluteJoint { + /// {@macro flipper_joint} _FlipperJoint(_FlipperAnchorRevoluteJointDef def) : side = def.side, - super(def); + super(def) { + lock(); + } + + /// The total angle of the arc motion. + static const _sweepingAngle = math.pi / 3.5; final BoardSide side; - // TODO(alestiago): Remove once Forge2D supports custom joints. - void create(World world) { - world.joints.add(this); - bodyA.joints.add(this); - bodyB.joints.add(this); + /// Locks the [Flipper] to its resting position. + /// + /// The joint is locked when initialized in order to force the [Flipper] + /// at its resting position. + void lock() { + const angle = _sweepingAngle / 2; + setLimits( + -angle * side.direction, + -angle * side.direction, + ); } /// Unlocks the [Flipper] from its resting position. - /// - /// The [Flipper] is locked when initialized in order to force it to be at - /// its resting position. void unlock() { - setLimits( - lowerLimit * side.direction, - -upperLimit * side.direction, - ); + const angle = _sweepingAngle / 2; + setLimits(-angle, angle); + } +} + +// TODO(alestiago): Remove once Forge2D supports custom joints. +extension on World { + void createJoint2(Joint joint) { + assert(!isLocked, ''); + + joints.add(joint); + + joint.bodyA.joints.add(joint); + joint.bodyB.joints.add(joint); } } diff --git a/lib/game/components/joint_anchor.dart b/packages/pinball_components/lib/src/components/joint_anchor.dart similarity index 100% rename from lib/game/components/joint_anchor.dart rename to packages/pinball_components/lib/src/components/joint_anchor.dart diff --git a/packages/pinball_components/pubspec.yaml b/packages/pinball_components/pubspec.yaml index 1c8dfbe3..849469cc 100644 --- a/packages/pinball_components/pubspec.yaml +++ b/packages/pinball_components/pubspec.yaml @@ -26,6 +26,7 @@ flutter: generate: true assets: - assets/images/ + - assets/images/flipper/ flutter_gen: line_length: 80 diff --git a/packages/pinball_components/sandbox/lib/main.dart b/packages/pinball_components/sandbox/lib/main.dart index 44b594d7..113d61ac 100644 --- a/packages/pinball_components/sandbox/lib/main.dart +++ b/packages/pinball_components/sandbox/lib/main.dart @@ -15,5 +15,6 @@ void main() { addBallStories(dashbook); addLayerStories(dashbook); addEffectsStories(dashbook); + addFlipperStories(dashbook); runApp(dashbook); } diff --git a/packages/pinball_components/sandbox/lib/stories/ball/basic.dart b/packages/pinball_components/sandbox/lib/stories/ball/basic.dart index f133ee3f..73890519 100644 --- a/packages/pinball_components/sandbox/lib/stories/ball/basic.dart +++ b/packages/pinball_components/sandbox/lib/stories/ball/basic.dart @@ -7,8 +7,9 @@ class BasicBallGame extends BasicGame with TapDetector { BasicBallGame({required this.color}); static const info = ''' - Basic example of how a Ball works, tap anywhere on the - screen to spawn a ball into the game. + Basic example of how a Ball works. + + Tap anywhere on the screen to spawn a ball into the game. '''; final Color color; diff --git a/packages/pinball_components/sandbox/lib/stories/flipper/basic.dart b/packages/pinball_components/sandbox/lib/stories/flipper/basic.dart new file mode 100644 index 00000000..0e5587ea --- /dev/null +++ b/packages/pinball_components/sandbox/lib/stories/flipper/basic.dart @@ -0,0 +1,26 @@ +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:sandbox/common/common.dart'; + +class BasicFlipperGame extends BasicGame { + static const info = ''' + Basic example of how a Flipper works. +'''; + + @override + Future onLoad() async { + await super.onLoad(); + + final center = screenToWorld(camera.viewport.canvasSize! / 2); + + final leftFlipper = Flipper(side: BoardSide.left) + ..initialPosition = center - Vector2(Flipper.size.x, 0); + final rightFlipper = Flipper(side: BoardSide.right) + ..initialPosition = center + Vector2(Flipper.size.x, 0); + + await addAll([ + leftFlipper, + rightFlipper, + ]); + } +} diff --git a/packages/pinball_components/sandbox/lib/stories/flipper/flipper.dart b/packages/pinball_components/sandbox/lib/stories/flipper/flipper.dart new file mode 100644 index 00000000..7c8465da --- /dev/null +++ b/packages/pinball_components/sandbox/lib/stories/flipper/flipper.dart @@ -0,0 +1,25 @@ +import 'package:dashbook/dashbook.dart'; +import 'package:flame/game.dart'; +import 'package:sandbox/common/common.dart'; +import 'package:sandbox/stories/flipper/basic.dart'; +import 'package:sandbox/stories/flipper/tracing.dart'; + +void addFlipperStories(Dashbook dashbook) { + dashbook.storiesOf('Flipper') + ..add( + 'Basic', + (context) => GameWidget( + game: BasicFlipperGame(), + ), + codeLink: buildSourceLink('flipper/basic.dart'), + info: BasicFlipperGame.info, + ) + ..add( + 'Tracing', + (context) => GameWidget( + game: FlipperTracingGame(), + ), + codeLink: buildSourceLink('flipper/tracing.dart'), + info: FlipperTracingGame.info, + ); +} diff --git a/packages/pinball_components/sandbox/lib/stories/flipper/tracing.dart b/packages/pinball_components/sandbox/lib/stories/flipper/tracing.dart new file mode 100644 index 00000000..d6c5d3df --- /dev/null +++ b/packages/pinball_components/sandbox/lib/stories/flipper/tracing.dart @@ -0,0 +1,49 @@ +import 'dart:async'; + +import 'package:flame/components.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flutter/material.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:sandbox/common/common.dart'; + +class FlipperTracingGame extends BasicGame { + static const info = ''' + Basic example of how the Flipper body overlays the sprite. +'''; + + @override + Future onLoad() async { + await super.onLoad(); + final center = screenToWorld(camera.viewport.canvasSize! / 2); + + final leftFlipper = Flipper(side: BoardSide.left) + ..initialPosition = center - Vector2(Flipper.size.x, 0); + final rightFlipper = Flipper(side: BoardSide.right) + ..initialPosition = center + Vector2(Flipper.size.x, 0); + + await addAll([ + leftFlipper, + rightFlipper, + ]); + leftFlipper.trace(); + rightFlipper.trace(); + } +} + +extension on BodyComponent { + void trace({Color color = Colors.red}) { + paint = Paint()..color = color; + renderBody = true; + body.joints.whereType().forEach( + (joint) => joint.setLimits(0, 0), + ); + body.setType(BodyType.static); + + unawaited( + mounted.whenComplete(() { + final sprite = children.whereType().first; + sprite.paint.color = sprite.paint.color.withOpacity(0.5); + }), + ); + } +} diff --git a/packages/pinball_components/sandbox/lib/stories/layer/basic.dart b/packages/pinball_components/sandbox/lib/stories/layer/basic.dart index 89ef337f..ccbd67d9 100644 --- a/packages/pinball_components/sandbox/lib/stories/layer/basic.dart +++ b/packages/pinball_components/sandbox/lib/stories/layer/basic.dart @@ -8,8 +8,9 @@ class BasicLayerGame extends BasicGame with TapDetector { BasicLayerGame({required this.color}); static const info = ''' - Basic example of how layers work with a Ball hitting other components, - tap anywhere on the screen to spawn a ball into the game. + Basic example of how layers work when a Ball hits other components. + + Tap anywhere on the screen to spawn a ball into the game. '''; final Color color; diff --git a/packages/pinball_components/sandbox/lib/stories/stories.dart b/packages/pinball_components/sandbox/lib/stories/stories.dart index 1135fbaf..9f861bde 100644 --- a/packages/pinball_components/sandbox/lib/stories/stories.dart +++ b/packages/pinball_components/sandbox/lib/stories/stories.dart @@ -1,2 +1,3 @@ export 'ball/ball.dart'; +export 'flipper/flipper.dart'; export 'layer/layer.dart'; diff --git a/test/game/components/board_side_test.dart b/packages/pinball_components/test/src/components/board_side_test.dart similarity index 92% rename from test/game/components/board_side_test.dart rename to packages/pinball_components/test/src/components/board_side_test.dart index ba201065..7c17828d 100644 --- a/test/game/components/board_side_test.dart +++ b/packages/pinball_components/test/src/components/board_side_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; void main() { group( diff --git a/packages/pinball_components/test/src/components/flipper_test.dart b/packages/pinball_components/test/src/components/flipper_test.dart new file mode 100644 index 00000000..efd4d2b0 --- /dev/null +++ b/packages/pinball_components/test/src/components/flipper_test.dart @@ -0,0 +1,133 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball_components/pinball_components.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(TestGame.new); + + group('Flipper', () { + // TODO(alestiago): Add golden tests. + // TODO(alestiago): Consider testing always both left and right Flipper. + + flameTester.test( + 'loads correctly', + (game) async { + final leftFlipper = Flipper(side: BoardSide.left); + final rightFlipper = Flipper(side: BoardSide.right); + await game.ready(); + await game.ensureAddAll([leftFlipper, rightFlipper]); + + expect(game.contains(leftFlipper), isTrue); + expect(game.contains(rightFlipper), isTrue); + }, + ); + + group('constructor', () { + test('sets BoardSide', () { + final leftFlipper = Flipper(side: BoardSide.left); + expect(leftFlipper.side, equals(leftFlipper.side)); + + final rightFlipper = Flipper(side: BoardSide.right); + expect(rightFlipper.side, equals(rightFlipper.side)); + }); + }); + + group('body', () { + flameTester.test( + 'is dynamic', + (game) async { + final flipper = Flipper(side: BoardSide.left); + await game.ensureAdd(flipper); + expect(flipper.body.bodyType, equals(BodyType.dynamic)); + }, + ); + + flameTester.test( + 'ignores gravity', + (game) async { + final flipper = Flipper(side: BoardSide.left); + await game.ensureAdd(flipper); + + expect(flipper.body.gravityScale, isZero); + }, + ); + + flameTester.test( + 'has greater mass than Ball', + (game) async { + final flipper = Flipper(side: BoardSide.left); + final ball = Ball(baseColor: Colors.white); + + await game.ready(); + await game.ensureAddAll([flipper, ball]); + + expect( + flipper.body.getMassData().mass, + greaterThan(ball.body.getMassData().mass), + ); + }, + ); + }); + + group('fixtures', () { + flameTester.test( + 'has three', + (game) async { + final flipper = Flipper(side: BoardSide.left); + await game.ensureAdd(flipper); + + expect(flipper.body.fixtures.length, equals(3)); + }, + ); + + flameTester.test( + 'has density', + (game) async { + final flipper = Flipper(side: BoardSide.left); + await game.ensureAdd(flipper); + + final fixtures = flipper.body.fixtures; + final density = fixtures.fold( + 0, + (sum, fixture) => sum + fixture.density, + ); + + expect(density, greaterThan(0)); + }, + ); + }); + + flameTester.test( + 'moveDown applies downward velocity', + (game) async { + final flipper = Flipper(side: BoardSide.left); + await game.ensureAdd(flipper); + + expect(flipper.body.linearVelocity, equals(Vector2.zero())); + flipper.moveDown(); + + expect(flipper.body.linearVelocity.y, lessThan(0)); + }, + ); + + flameTester.test( + 'moveUp applies upward velocity', + (game) async { + final flipper = Flipper(side: BoardSide.left); + await game.ensureAdd(flipper); + + expect(flipper.body.linearVelocity, equals(Vector2.zero())); + flipper.moveUp(); + + expect(flipper.body.linearVelocity.y, greaterThan(0)); + }, + ); + }); +} diff --git a/test/game/components/joint_anchor_test.dart b/packages/pinball_components/test/src/components/joint_anchor_test.dart similarity index 94% rename from test/game/components/joint_anchor_test.dart rename to packages/pinball_components/test/src/components/joint_anchor_test.dart index 652bd445..f7c341dd 100644 --- a/test/game/components/joint_anchor_test.dart +++ b/packages/pinball_components/test/src/components/joint_anchor_test.dart @@ -3,7 +3,7 @@ import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/game/components/baseboard_test.dart b/test/game/components/baseboard_test.dart index f834a41e..37c3c978 100644 --- a/test/game/components/baseboard_test.dart +++ b/test/game/components/baseboard_test.dart @@ -4,6 +4,7 @@ import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; void main() { group('Baseboard', () { diff --git a/test/game/components/board_test.dart b/test/game/components/board_test.dart index f6304cec..7b74d0da 100644 --- a/test/game/components/board_test.dart +++ b/test/game/components/board_test.dart @@ -3,6 +3,7 @@ import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; import '../../helpers/helpers.dart'; diff --git a/test/game/components/bonus_word_test.dart b/test/game/components/bonus_word_test.dart index 293062ae..001ccd46 100644 --- a/test/game/components/bonus_word_test.dart +++ b/test/game/components/bonus_word_test.dart @@ -29,6 +29,7 @@ void main() { group('listenWhen', () { final previousState = MockGameState(); final currentState = MockGameState(); + test( 'returns true when there is a new word bonus awarded', () { diff --git a/test/game/components/flipper_controller_test.dart b/test/game/components/flipper_controller_test.dart new file mode 100644 index 00000000..eabeca5e --- /dev/null +++ b/test/game/components/flipper_controller_test.dart @@ -0,0 +1,169 @@ +import 'dart:collection'; + +import 'package:flame_test/flame_test.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(PinballGameTest.create); + + group('FlipperController', () { + group('onKeyEvent', () { + final leftKeys = UnmodifiableListView([ + LogicalKeyboardKey.arrowLeft, + LogicalKeyboardKey.keyA, + ]); + final rightKeys = UnmodifiableListView([ + LogicalKeyboardKey.arrowRight, + LogicalKeyboardKey.keyD, + ]); + + group('and Flipper is left', () { + late Flipper flipper; + late FlipperController controller; + + setUp(() { + flipper = Flipper(side: BoardSide.left); + controller = FlipperController(flipper); + flipper.add(controller); + }); + + testRawKeyDownEvents(leftKeys, (event) { + flameTester.test( + 'moves upwards ' + 'when ${event.logicalKey.keyLabel} is pressed', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isPositive); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + + testRawKeyUpEvents(leftKeys, (event) { + flameTester.test( + 'moves downwards ' + 'when ${event.logicalKey.keyLabel} is released', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isNegative); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + + testRawKeyUpEvents(rightKeys, (event) { + flameTester.test( + 'does nothing ' + 'when ${event.logicalKey.keyLabel} is released', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isZero); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + + testRawKeyDownEvents(rightKeys, (event) { + flameTester.test( + 'does nothing ' + 'when ${event.logicalKey.keyLabel} is pressed', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isZero); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + }); + + group('and Flipper is right', () { + late Flipper flipper; + late FlipperController controller; + + setUp(() { + flipper = Flipper(side: BoardSide.right); + controller = FlipperController(flipper); + flipper.add(controller); + }); + + testRawKeyDownEvents(rightKeys, (event) { + flameTester.test( + 'moves upwards ' + 'when ${event.logicalKey.keyLabel} is pressed', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isPositive); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + + testRawKeyUpEvents(rightKeys, (event) { + flameTester.test( + 'moves downwards ' + 'when ${event.logicalKey.keyLabel} is released', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isNegative); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + + testRawKeyUpEvents(leftKeys, (event) { + flameTester.test( + 'does nothing ' + 'when ${event.logicalKey.keyLabel} is released', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isZero); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + + testRawKeyDownEvents(leftKeys, (event) { + flameTester.test( + 'does nothing ' + 'when ${event.logicalKey.keyLabel} is pressed', + (game) async { + await game.ready(); + await game.add(flipper); + controller.onKeyEvent(event, {}); + + expect(flipper.body.linearVelocity.y, isZero); + expect(flipper.body.linearVelocity.x, isZero); + }, + ); + }); + }); + }); + }); +} diff --git a/test/game/components/flipper_test.dart b/test/game/components/flipper_test.dart deleted file mode 100644 index 3e6429df..00000000 --- a/test/game/components/flipper_test.dart +++ /dev/null @@ -1,275 +0,0 @@ -// ignore_for_file: cascade_invocations - -import 'dart:collection'; - -import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:flame_test/flame_test.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:pinball/game/game.dart'; -import 'package:pinball_components/pinball_components.dart'; - -import '../../helpers/helpers.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - final flameTester = FlameTester(PinballGameTest.create); - - group( - 'Flipper', - () { - // TODO(alestiago): Add golden tests. - flameTester.test( - 'loads correctly', - (game) async { - final leftFlipper = Flipper( - side: BoardSide.left, - ); - final rightFlipper = Flipper( - side: BoardSide.right, - ); - await game.ready(); - await game.ensureAddAll([leftFlipper, rightFlipper]); - - expect(game.contains(leftFlipper), isTrue); - expect(game.contains(rightFlipper), isTrue); - }, - ); - - group('constructor', () { - test('sets BoardSide', () { - final leftFlipper = Flipper( - side: BoardSide.left, - ); - - expect(leftFlipper.side, equals(leftFlipper.side)); - - final rightFlipper = Flipper( - side: BoardSide.right, - ); - expect(rightFlipper.side, equals(rightFlipper.side)); - }); - }); - - group('body', () { - flameTester.test( - 'is dynamic', - (game) async { - final flipper = Flipper( - side: BoardSide.left, - ); - await game.ensureAdd(flipper); - - expect(flipper.body.bodyType, equals(BodyType.dynamic)); - }, - ); - - flameTester.test( - 'ignores gravity', - (game) async { - final flipper = Flipper( - side: BoardSide.left, - ); - await game.ensureAdd(flipper); - - expect(flipper.body.gravityScale, isZero); - }, - ); - - flameTester.test( - 'has greater mass than Ball', - (game) async { - final flipper = Flipper( - side: BoardSide.left, - ); - final ball = Ball(baseColor: Colors.white); - - await game.ready(); - await game.ensureAddAll([flipper, ball]); - - expect( - flipper.body.getMassData().mass, - greaterThan(ball.body.getMassData().mass), - ); - }, - ); - }); - - group('fixtures', () { - flameTester.test( - 'has three', - (game) async { - final flipper = Flipper( - side: BoardSide.left, - ); - await game.ensureAdd(flipper); - - expect(flipper.body.fixtures.length, equals(3)); - }, - ); - - flameTester.test( - 'has density', - (game) async { - final flipper = Flipper( - side: BoardSide.left, - ); - await game.ensureAdd(flipper); - - final fixtures = flipper.body.fixtures; - final density = fixtures.fold( - 0, - (sum, fixture) => sum + fixture.density, - ); - - expect(density, greaterThan(0)); - }, - ); - }); - - group('onKeyEvent', () { - final leftKeys = UnmodifiableListView([ - LogicalKeyboardKey.arrowLeft, - LogicalKeyboardKey.keyA, - ]); - final rightKeys = UnmodifiableListView([ - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.keyD, - ]); - - group('and Flipper is left', () { - late Flipper flipper; - - setUp(() { - flipper = Flipper( - side: BoardSide.left, - ); - }); - - testRawKeyDownEvents(leftKeys, (event) { - flameTester.test( - 'moves upwards ' - 'when ${event.logicalKey.keyLabel} is pressed', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isPositive); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - - testRawKeyUpEvents(leftKeys, (event) { - flameTester.test( - 'moves downwards ' - 'when ${event.logicalKey.keyLabel} is released', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isNegative); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - - testRawKeyUpEvents(rightKeys, (event) { - flameTester.test( - 'does nothing ' - 'when ${event.logicalKey.keyLabel} is released', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isZero); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - - testRawKeyDownEvents(rightKeys, (event) { - flameTester.test( - 'does nothing ' - 'when ${event.logicalKey.keyLabel} is pressed', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isZero); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - }); - - group('and Flipper is right', () { - late Flipper flipper; - - setUp(() { - flipper = Flipper( - side: BoardSide.right, - ); - }); - - testRawKeyDownEvents(rightKeys, (event) { - flameTester.test( - 'moves upwards ' - 'when ${event.logicalKey.keyLabel} is pressed', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isPositive); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - - testRawKeyUpEvents(rightKeys, (event) { - flameTester.test( - 'moves downwards ' - 'when ${event.logicalKey.keyLabel} is released', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isNegative); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - - testRawKeyUpEvents(leftKeys, (event) { - flameTester.test( - 'does nothing ' - 'when ${event.logicalKey.keyLabel} is released', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isZero); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - - testRawKeyDownEvents(leftKeys, (event) { - flameTester.test( - 'does nothing ' - 'when ${event.logicalKey.keyLabel} is pressed', - (game) async { - await game.ensureAdd(flipper); - flipper.onKeyEvent(event, {}); - - expect(flipper.body.linearVelocity.y, isZero); - expect(flipper.body.linearVelocity.x, isZero); - }, - ); - }); - }); - }); - }, - ); -} diff --git a/test/game/components/kicker_test.dart b/test/game/components/kicker_test.dart index 211ff8ad..333c7fbe 100644 --- a/test/game/components/kicker_test.dart +++ b/test/game/components/kicker_test.dart @@ -4,6 +4,7 @@ import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; void main() { group('Kicker', () {