From 9b52d1179a20b44eed263c6c4ee48c8cbf67baf2 Mon Sep 17 00:00:00 2001 From: Dan Lopez Date: Thu, 12 Oct 2023 23:57:34 -0500 Subject: [PATCH] feat: create new game Down with the first flow to detect collisions and add score --- lib/main.dart | 6 + lib/pages/home.dart | 1 + lib/pages/mini-games/mini_games.dart | 6 +- lib/pages/mini-games/up/buttons.dart | 53 ++--- lib/pages/mini-games/up/down.dart | 239 +++++++++++++++++++++ lib/pages/mini-games/up/objects/box.dart | 62 +++++- lib/pages/mini-games/up/objects/dino.dart | 15 +- lib/pages/mini-games/up/objects/floor.dart | 37 +++- lib/pages/mini-games/up/up.dart | 10 +- lib/pages/my-dinogrow/my_dinogrow.dart | 5 +- pubspec.lock | 4 +- pubspec.yaml | 4 +- 12 files changed, 386 insertions(+), 56 deletions(-) create mode 100644 lib/pages/mini-games/up/down.dart diff --git a/lib/main.dart b/lib/main.dart index 313925f..f56bcca 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:dinogrow/pages/setup_account.dart'; import 'package:dinogrow/pages/setup_password.dart'; import 'package:dinogrow/pages/mini-games/mini_games.dart'; import 'package:dinogrow/pages/mini-games/up/up.dart'; +import 'package:dinogrow/pages/mini-games/up/down.dart'; import 'package:dinogrow/pages/mini-games/coming_soon.dart'; void main() { @@ -60,6 +61,11 @@ final GoRouter _router = GoRouter(routes: [ builder: (context, state) { return GameWidgetUp(game: UpGame()); }), + GoRoute( + path: '/mini_games/down', + builder: (context, state) { + return GameWidgetDown(game: DownGame()); + }), GoRoute( path: '/mini_games/comming_soon', builder: (context, state) { diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 6f053f6..bf902ae 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -115,6 +115,7 @@ class _HomeScreenState extends State { ), ), child: TabBarView( + physics: const NeverScrollableScrollPhysics(), children: [ const MiniGamesScreen(), RankingScreen(), diff --git a/lib/pages/mini-games/mini_games.dart b/lib/pages/mini-games/mini_games.dart index 005af61..52929a8 100644 --- a/lib/pages/mini-games/mini_games.dart +++ b/lib/pages/mini-games/mini_games.dart @@ -28,11 +28,11 @@ class _MiniGamesPageState extends State { children: [ GameCardWidget( text: 'UP', - route: "/mini_games/up", + route: "/mini_games/comming_soon", ), GameCardWidget( - text: 'COMING SOON', - route: "/mini_games/comming_soon", + text: 'DOWN', + route: "/mini_games/down", ), GameCardWidget( text: 'COMING SOON', diff --git a/lib/pages/mini-games/up/buttons.dart b/lib/pages/mini-games/up/buttons.dart index 685f1da..006d5fa 100644 --- a/lib/pages/mini-games/up/buttons.dart +++ b/lib/pages/mini-games/up/buttons.dart @@ -1,49 +1,52 @@ import 'package:flame/components.dart'; import 'package:flame/palette.dart'; import 'package:flutter/material.dart'; +import 'package:dinogrow/pages/mini-games/up/up.dart'; class VirtualPadButtons extends PositionComponent { List buttons = []; List vpadbuttons() { - CircleComponent btnLeftCircle; - final circlePaintLeft = BasicPalette.gray.paint(); - btnLeftCircle = CircleComponent(radius: 0.15, paint: circlePaintLeft); - btnLeftCircle.position = Vector2(0.3, 6.8); + RectangleComponent btnLeftCircle; + final circlePaintLeft = BasicPalette.yellow.paint(); + btnLeftCircle = + RectangleComponent.square(size: 0.95, paint: circlePaintLeft); + btnLeftCircle.position = Vector2(0, worldSize.y - 5.7); btnLeftCircle.anchor = Anchor.topLeft; buttons.add(btnLeftCircle); - CircleComponent btnRightCircle; - final circlePaintRight = BasicPalette.gray.paint(); - btnRightCircle = CircleComponent(radius: 0.15, paint: circlePaintRight); - btnRightCircle.position = Vector2(1, 6.8); + RectangleComponent btnRightCircle; + final circlePaintRight = BasicPalette.yellow.paint(); + btnRightCircle = + RectangleComponent.square(size: 0.95, paint: circlePaintRight); + btnRightCircle.position = Vector2(3, worldSize.y - 5.7); btnRightCircle.anchor = Anchor.topLeft; buttons.add(btnRightCircle); - CircleComponent btnJumpCircle; + RectangleComponent btnJumpCircle; final circlePaintJump = BasicPalette.gray.paint(); - btnJumpCircle = CircleComponent(radius: 0.15, paint: circlePaintJump); - btnJumpCircle.position = Vector2(2.7, 6.3); + btnJumpCircle = + RectangleComponent.square(size: 0.95, paint: circlePaintJump); + btnJumpCircle.position = Vector2(1, worldSize.y - 5.7); btnJumpCircle.anchor = Anchor.topLeft; buttons.add(btnJumpCircle); - CircleComponent btnAttackCircle; - final circlePaintAttack = - BasicPalette.gray.paint(); - btnAttackCircle = CircleComponent(radius: 0.15, paint: circlePaintAttack); - btnAttackCircle.position = Vector2(3, 6.8); + RectangleComponent btnAttackCircle; + final circlePaintAttack = BasicPalette.gray.paint(); + btnAttackCircle = + RectangleComponent.square(size: 0.95, paint: circlePaintAttack); + btnAttackCircle.position = Vector2(2, worldSize.y - 5.7); btnAttackCircle.anchor = Anchor.topLeft; buttons.add(btnAttackCircle); final btnStyleLetters = TextPaint( - style: const TextStyle( - fontSize: 20, - color: Colors.black, - fontFamily: 'ComicNeue Bold', - ) - ); + style: const TextStyle( + fontSize: 20, + color: Colors.black, + fontFamily: 'ComicNeue Bold', + )); final textJump = TextComponent( - text:'J', + text: 'J', textRenderer: btnStyleLetters, position: Vector2(2.7, 6.3), ); @@ -51,12 +54,12 @@ class VirtualPadButtons extends PositionComponent { buttons.add(textJump); final textAttack = TextComponent( - text:'A', + text: 'A', textRenderer: btnStyleLetters, position: Vector2(3, 6.8), priority: 1, ); - + buttons.add(textAttack); return buttons; diff --git a/lib/pages/mini-games/up/down.dart b/lib/pages/mini-games/up/down.dart new file mode 100644 index 0000000..3722afe --- /dev/null +++ b/lib/pages/mini-games/up/down.dart @@ -0,0 +1,239 @@ +import 'package:dinogrow/pages/mini-games/up/buttons.dart'; +import 'package:dinogrow/pages/mini-games/up/objects/dino.dart'; +import 'package:flame/palette.dart'; +import 'package:flame/components.dart'; +import 'package:flame/game.dart'; +import 'package:flame/input.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'objects/floor.dart'; +import 'objects/box.dart'; +import 'package:flame/timer.dart' as timer_flame; + +final screenSize = Vector2(720, 1280); + +// Scaled viewport size +final worldSize = Vector2(7.2, 12.8); + +class DownGame extends Forge2DGame with TapDetector { + // setup the game camera to match the device size + DownGame() : super(zoom: 100, gravity: Vector2(0, 15)); + + //get the dino object and sprite animation + final dino = Dino(); + + //set initial state of the game buttons + bool isJumpPressed = false; + bool isLeftPressed = false; + bool isRightPressed = false; + bool isAttackPressed = false; + + //Timer callbacks + timer_flame.Timer timer = timer_flame.Timer(0); + + //set initial score + int score = 0; + late TextComponent scoreText; + + // get the buttons + final btnLeft = VirtualPadButtons().vpadbuttons()[0]; + final btnRight = VirtualPadButtons().vpadbuttons()[1]; + final btnJump = VirtualPadButtons().vpadbuttons()[2]; + final btnAttack = VirtualPadButtons().vpadbuttons()[3]; + final btnJumpText = VirtualPadButtons().vpadbuttons()[4]; + final btnAttackText = VirtualPadButtons().vpadbuttons()[5]; + + // check and verify if the button is pressed + bool isInsideButton(Vector2 tapPosition, RectangleComponent button) { + final buttonRect = button.toRect(); + return buttonRect.contains(tapPosition.toOffset()); + } + + @override + bool onTapDown(TapDownInfo info) { + final tapPosition = info.eventPosition.game; + + if (isInsideButton(tapPosition, btnLeft)) { + isLeftPressed = true; + } + if (isInsideButton(tapPosition, btnRight)) { + isRightPressed = true; + } + if (isInsideButton(tapPosition, btnJump)) { + isJumpPressed = true; + } + if (isInsideButton(tapPosition, btnAttack)) { + isAttackPressed = true; + } + + if (isLeftPressed) { + btnLeft.paint.color = const Color.fromARGB(255, 91, 92, 91); + dino.walkLeft(); + + timer = + timer_flame.Timer(0.25, onTick: () => dino.walkLeft(), repeat: true); + } + if (isRightPressed) { + dino.walkRight(); + btnRight.paint.color = const Color.fromARGB(255, 91, 92, 91); + + timer = + timer_flame.Timer(0.25, onTick: () => dino.walkRight(), repeat: true); + } + // if (isJumpPressed) { + // dino.jump(); + // score += 10; + // scoreText.text = 'Score: ${score.toString().padLeft(3, '0')}'; + // btnJump.paint.color = const Color.fromARGB(255, 91, 92, 91); + // } + // if (isAttackPressed) { + // dino.run(); + // btnAttack.paint.color = const Color.fromARGB(255, 91, 92, 91); + // } + + return true; + } + + @override + bool onTapUp(TapUpInfo info) { + if (isLeftPressed) { + isLeftPressed = false; + btnLeft.paint.color = BasicPalette.yellow.color; + } + if (isRightPressed) { + isRightPressed = false; + btnRight.paint.color = BasicPalette.yellow.color; + } + // if (isJumpPressed) { + // isJumpPressed = false; + // btnJump.paint.color = BasicPalette.gray.color; + // } + // if (isAttackPressed) { + // isAttackPressed = false; + // btnAttack.paint.color = BasicPalette.gray.color; + // } + timer.stop(); + + return true; + } + + @override + Future onLoad() async { + await super.onLoad(); + + final camera = + CameraComponent.withFixedResolution(width: 720, height: 1280); + final background = _Background(size: screenSize); + camera.viewport.add(background); + if (dino.isLoaded) { + camera.follow(dino.currentComponent, verticalOnly: true); + } + // camera.follow(dino.c,verticalOnly: true); + + // add(FpsTextComponent( + // position: Vector2(0, 7.8), + // scale: Vector2(0.01, 0.01), + // anchor: Anchor.topLeft, + // windowSize: 60, + // textRenderer: TextPaint(style: const TextStyle(color: Colors.white)))); + + add(Floor()); + add(LeftWall()); + add(RightWall()); + + //Testing + // Add instance of Box + + finishGame() { + print('End game with $score points in score'); + } + + newBoxAndScore() { + score += 10; + scoreText.text = 'Score: ${score.toString().padLeft(3, '0')}'; + add(Box(newBoxAndScore, finishGame)); + } + + add(Box(newBoxAndScore, finishGame)); + + // add the player to the game + add(dino); + + // add the buttons to the game + add(btnLeft); + add(btnRight); + // add(btnJump); + // add(btnAttack); + add(btnJumpText); + add(btnAttackText); + + // Score text + final btnStyleLetters = TextPaint( + style: const TextStyle( + fontSize: 0.2, + color: Colors.white, + fontFamily: 'ComicNeue Bold', + )); + + scoreText = TextComponent( + text: 'Score: 000', + anchor: Anchor.topRight, + position: Vector2(3.7, 0.65), + textRenderer: btnStyleLetters, + ); + + add(scoreText); + } + + @override + Color backgroundColor() => const Color(0x00077777); + + @override + void update(double dt) { + super.update(dt); + timer.update(dt); + } +} + +class _Background extends PositionComponent { + _Background({super.size}); + @override + void render(Canvas canvas) { + canvas.drawRect(Rect.fromLTWH(0, 0, size.x, size.y), + Paint()..color = const Color.fromARGB(255, 56, 53, 53)); + } +} + +class GameWidgetDown extends StatelessWidget { + final DownGame game; + + const GameWidgetDown({super.key, required this.game}); + + @override + Widget build(BuildContext context) { + return Scaffold( + extendBodyBehindAppBar: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + GoRouter.of(context).pop(); + }, + ), + ), + body: Container( + height: MediaQuery.of(context).size.height, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/images/up/maps/01/up_map_1.jpeg"), + fit: BoxFit.cover, + ), + ), + child: GameWidget(game: game), + ), + ); + } +} diff --git a/lib/pages/mini-games/up/objects/box.dart b/lib/pages/mini-games/up/objects/box.dart index 63d3be9..e4dd9fe 100644 --- a/lib/pages/mini-games/up/objects/box.dart +++ b/lib/pages/mini-games/up/objects/box.dart @@ -1,12 +1,58 @@ +import 'dart:math'; + +import 'package:dinogrow/pages/mini-games/up/objects/floor.dart'; import 'package:flame/components.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; + +import 'dino.dart'; + +class Box extends BodyComponent with ContactCallbacks { + final Function onCollisionBox; + final Function onCollisionDino; + + Box(this.onCollisionBox, this.onCollisionDino) : super(priority: 1); + + @override + Future onLoad() async { + await super.onLoad(); + + add( + SpriteComponent( + sprite: await Sprite.load('up/maps/01/box.png'), + size: Vector2(1, 1), + position: Vector2(-.5, -.5), + ), + ); + } + + @override + void beginContact(Object other, Contact contact) { + removeFromParent(); + if (other is Floor) { + onCollisionBox(); + } else if (other is Dino) { + onCollisionDino(); + } + } + + @override + Body createBody() { + final rnd = Random(); + + final bodyDef = BodyDef( + userData: this, + //position: Vector2(worldSize.x / 2, worldSize.y - 3), change dino position later + position: Vector2(rnd.nextDouble() * 3, 0), + type: BodyType.dynamic, + gravityOverride: Vector2(0, rnd.nextDouble() * 3 + 1), + ); -class Box extends SpriteComponent { - Box() : super(priority: 1); + final shape = PolygonShape()..setAsBoxXY(.5, .5); - Future loadImage() async { - // load the image to be used as the box - sprite = await Sprite.load('up/maps/01/box.png'); - width = 0.5; - height = 0.5; + final fixtureDef = FixtureDef(shape) + ..density = 0 + ..friction = 0 + ..restitution = 0; + return world.createBody(bodyDef)..createFixture(fixtureDef); } -} \ No newline at end of file +} diff --git a/lib/pages/mini-games/up/objects/dino.dart b/lib/pages/mini-games/up/objects/dino.dart index 45ef32c..c02444e 100644 --- a/lib/pages/mini-games/up/objects/dino.dart +++ b/lib/pages/mini-games/up/objects/dino.dart @@ -10,9 +10,9 @@ enum DinoState { } class Dino extends BodyComponent with KeyboardHandler { - final _size = Vector2(1.80, 2.4); + final _size = Vector2(1.70, 2.4); // componentPosition is the position of the dino in the screen - final _componentPosition = Vector2(0, -.325); + final _componentPosition = Vector2(0, 0); DinoState state = DinoState.idle; late final SpriteAnimationComponent runComponent; @@ -244,11 +244,11 @@ class Dino extends BodyComponent with KeyboardHandler { if (walking == true && walkStep != 0) { velocity.x = accelerationX * 3; body.linearVelocity = velocity; - }else{ + } else { velocity.x = 0; body.linearVelocity = velocity; } - + if (state == DinoState.jump) { _setComponent(jumpComponent, accelerationX); } else if (state == DinoState.dead) { @@ -263,7 +263,6 @@ class Dino extends BodyComponent with KeyboardHandler { } void _setComponent(PositionComponent component, int xAcceleration) { - if (xAcceleration < 0) { if (!component.isFlippedHorizontally) { component.flipHorizontally(); @@ -285,14 +284,14 @@ class Dino extends BodyComponent with KeyboardHandler { final bodyDef = BodyDef( userData: this, //position: Vector2(worldSize.x / 2, worldSize.y - 3), change dino position later - position: Vector2(2, 0), + position: Vector2(2, 3), type: BodyType.dynamic, ); - final shape = PolygonShape()..setAsBoxXY(_size.x / 2, .90); + final shape = PolygonShape()..setAsBoxXY(.4, .9); final fixtureDef = FixtureDef(shape) - ..density = 15 + ..density = 0 ..friction = 0 ..restitution = 0; return world.createBody(bodyDef)..createFixture(fixtureDef); diff --git a/lib/pages/mini-games/up/objects/floor.dart b/lib/pages/mini-games/up/objects/floor.dart index 233a8a5..821f62a 100644 --- a/lib/pages/mini-games/up/objects/floor.dart +++ b/lib/pages/mini-games/up/objects/floor.dart @@ -5,7 +5,8 @@ class Floor extends BodyComponent { @override Body createBody() { final bodyDef = BodyDef( - position: Vector2(0, worldSize.y - 4.8), + userData: this, + position: Vector2(0, worldSize.y - 5.7), type: BodyType.static, ); @@ -15,4 +16,36 @@ class Floor extends BodyComponent { return world.createBody(bodyDef)..createFixture(fixtureDef); } -} \ No newline at end of file +} + +class LeftWall extends BodyComponent { + @override + Body createBody() { + final bodyDef = BodyDef( + position: Vector2(-0.3, 0), + type: BodyType.static, + ); + + final shape = EdgeShape()..set(Vector2(0, worldSize.y), Vector2.zero()); + + final fixtureDef = FixtureDef(shape)..friction = .7; + + return world.createBody(bodyDef)..createFixture(fixtureDef); + } +} + +class RightWall extends BodyComponent { + @override + Body createBody() { + final bodyDef = BodyDef( + position: Vector2(worldSize.x - 3, 0), + type: BodyType.static, + ); + + final shape = EdgeShape()..set(Vector2(0, worldSize.y), Vector2.zero()); + + final fixtureDef = FixtureDef(shape)..friction = .7; + + return world.createBody(bodyDef)..createFixture(fixtureDef); + } +} diff --git a/lib/pages/mini-games/up/up.dart b/lib/pages/mini-games/up/up.dart index 288c6b7..0be2363 100644 --- a/lib/pages/mini-games/up/up.dart +++ b/lib/pages/mini-games/up/up.dart @@ -127,11 +127,11 @@ class UpGame extends Forge2DGame with TapDetector { //Testing // Add instance of Box - final box = Box() - ..x = 0 - ..y = 5.5; - await box.loadImage(); - add(box); + // final box = Box() + // ..x = 0 + // ..y = 5.5; + // await box.loadImage(); + // add(box); // add the player to the game add(dino); diff --git a/lib/pages/my-dinogrow/my_dinogrow.dart b/lib/pages/my-dinogrow/my_dinogrow.dart index 17f5cbf..61ca493 100644 --- a/lib/pages/my-dinogrow/my_dinogrow.dart +++ b/lib/pages/my-dinogrow/my_dinogrow.dart @@ -247,7 +247,10 @@ class _MydinogrowScreenState extends State { if (mounted) { setState(() { - userNfts = arrayAssets.where((nft) => nft['imageUrl'] != '').toList(); + userNfts = arrayAssets + .where((nft) => + nft['imageUrl'] != '' && nft['collectionName'] == 'DINOGROW') + .toList(); showDinos = true; }); } diff --git a/pubspec.lock b/pubspec.lock index bf3db5a..4a33caa 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -293,10 +293,10 @@ packages: dependency: "direct main" description: name: flame - sha256: f1ed45b49db36f6650882900f3216516d5c2628400bad8b4e92d83c116d79b12 + sha256: bd2b45f9fc0ec4939031b85c0b0a97cf09357c12ecd072d44389a4c577a2c0f0 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.8.2" flame_forge2d: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 9e2767f..5787225 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,8 +14,8 @@ dependencies: bip39: ^1.0.6 flutter_secure_storage: ^8.0.0 flutter_dotenv: ^5.1.0 - flame: ^1.8.2 - flame_forge2d: ^0.14.1+1 + flame: 1.8.2 + flame_forge2d: 0.14.1+1 flutter_joystick: ^0.0.3 url_launcher: ^6.1.14 qr_flutter: ^4.1.0