Linkedin Instagram Facebook X-twitter Welcome to our comprehensive guide on bundling a React library into a reusable component library! In…
Today, we are going to take an example of a game that leverages flutter’s animation support to create a dynamic and engaging user experience for the game. In the code, animations are used to provide feedback to the user, such as indicating successful word completion or updating the currency count. The game screen (HomeScreen.dart) orchestrates these animations and manages the game’s state, while individual components like letter tiles (Tile.dart) and currency display (CurrencyDisplay.dart) handle their respective responsibilities within the game.
To enhance the explanation, let’s delve deeper into Flutter’s animation capabilities and how they are utilized in the codebase. Flutter provides various classes and methods for creating animations, including explicit animations, implicit animations, and custom animations. Below codebase uses explicit animations, which involve directly controlling the animation’s state and properties.
1. Define an AnimationController to control the animation’s duration, curve, and other properties.
2. Create an Animation object that represents the current state of the animation.
3. Animate the widget’s properties using the Animation object within a StatefulWidget’s build method or a custom animation widget.
In addition to the steps outlined above, Flutter’s animation system also allows for the use of animation listeners, which enable developers to execute custom logic at various points during the animation’s lifecycle. This feature is particularly useful for synchronizing animations with other parts of the application or triggering actions based on the animation’s progress.
void updateIndex() {
for (int i = 0; i < wordBloc.addedWords.length; i++) {
if (wordBloc.addedWords[i] == userSelection) {
setState(() {
if (WordScapeState.indexList.last -
WordScapeState
.indexList[WordScapeState.indexList.length - 2] <
0) {
HomeScreen.isReversed = true;
}
HomeScreen.gameIndex = i;
});
}
}
}
Condition Check: It first checks if the showExtraInfo variable in the HomeScreen class is true. This determines whether extra information should be displayed. Then, it checks if the tileId of the current Tile widget matches the lastIndex stored in the HomeScreen class. This ensures that the CurrencyDisplay is only shown for the selected tile.
Alignment Determination: If both conditions are met, it sets the alignment of the CurrencyDisplay widget based on the direction of the word associated with the current tile. If the word direction is vertical (WordDirection.Vertical), it checks if the game is reversed (isReversed). Depending on this, it aligns the CurrencyDisplay either above or below the tile vertically.
If the word direction is horizontal, it aligns the CurrencyDisplay either to the left or right of the tile horizontally, again depending on whether the game is reversed.
Size Configuration: Additionally, it configures the width and height of the CurrencyDisplay widget based on whether the word direction is vertical or horizontal, ensuring it fits appropriately with the layout.
This logic ensures that the CurrencyDisplay widget is displayed next to the selected tile, with its position and size adjusted dynamically based on the game state.
import 'package:my_game/blocs/word_bloc.dart'; import 'package:my_game/utils/base/word_direction.dart'; class Tile extends StatefulWidget { final int tileId; final bool isSelected; final String letter; final Color selectedColor; final int level; final WordBloc wordBloc; Tile( {Key? key, required this.letter, required this.isSelected, required this.tileId, required this.selectedColor, required this.level, required this.wordBloc}) : super(key: key); if (HomeScreen.showExtraInfo) if (widget.tileId == HomeScreen.lastIndex) Align( alignment: widget.wordBloc.wordDirections[HomeScreen.gameIndex] == WordDirection.Vertical ? HomeScreen.isReversed ? Alignment(0, -2.3) : Alignment(0, 2.3) : HomeScreen.isReversed ? Alignment(-2.3, 0) : Alignment(2.3, 0), child: CurrencyDisplay( width: widget.wordBloc.wordDirections[HomeScreen.gameIndex] == WordDirection.Vertical ? FULL_WIDTH : 25, height: widget.wordBloc.wordDirections[HomeScreen.gameIndex] == WordDirection.Vertical ? 25 : FULL_HEIGHT), }
CurrencyDisplay.dart
This file defines the widget responsible for displaying the currency count in the game. It utilizes Flutter’s StatefulWidget to manage its state, particularly the visibility of the currency count. The build() method renders the widget based on its properties (height and width) and the current game state.
Visibility: The widget from material.dart controls the visibility of its child based on the value of the visible parameter. In this case, it determines whether the CurrencyDisplay widget should be visible.
Container: The Container widget serves as the parent widget for the CurrencyDisplay . It defines its width, height, decoration, and child.
Conditional Layout: Depending on whether the width of the Container is greater than its height (widget.width > widget.height), the layout changes: If the width is greater, a Row() widget is used to display the image and the score text horizontally. If the height is greater or equal, a Column widget is used to display them vertically.
Content: The text widget from the auto_size_text package and an image widget is used to display the current score dynamically.
The image is loaded from the assets.
The score text is dynamically updated from GamePoints.score.
Styling: The container has a grey background with a yellow border. The score text is styled with yellow color and bold font weight.
This logic efficiently handles the display of the currency information, adjusting its layout based on available space.
import 'package:flutter/material.dart';
import 'package:my_game/utils/word_points.dart';
import 'package:auto_size_text/auto_size_text.dart';
class CurrencyDisplay extends StatefulWidget {
final double height;
final double width;
CurrencyDisplay({required this.height, required this.width});
static bool isVisible = false;
@override
State<CurrencyDisplay> createState() => _CurrencyDisplayState();
}
class _CurrencyDisplayState extends State<CurrencyDisplay> {
@override
Widget build(BuildContext context) {
return Visibility(
visible: CurrencyDisplay.isVisible,
child: Container(
width: widget.width,
height: widget.height,
decoration: BoxDecoration(
color: Colors.grey[800],
border: Border.all(
color: Colors.yellowAccent,
width: 2,
),
borderRadius: BorderRadius.circular(15),
),
child: widget.width > widget.height
? Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
child: Image.asset(
'assets/images/currency_image.png',
fit: BoxFit.contain,
),
),
Expanded(
flex: 2,
child: AutoSizeText(
"${GamePoints.score}",
style: TextStyle(
color: Colors.yellowAccent,
fontWeight: FontWeight.bold,
),
),
),
],
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Image.asset(
'assets/images/currency_image.png',
fit: BoxFit.contain,
),
),
Expanded(
flex: 2,
child: AutoSizeText(
"${GamePoints.score}",
style: TextStyle(
color: Colors.yellowAccent,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
);
}
}
import'package:animate_do/animate_do.dart';
import'package:flutter/material.dart';
import'package:google_fonts/google_fonts.dart';
class TotalScore extends StatefulWidget{
static int total = 0;
final int pointsEarned;
static bool isScoreChanged = false;
TotalScore({Key? key, this.pointsEarned = 0}) : super(key: key);
@override
State<TotalScore> createState() => _TotalScoreState();
}
class _TotalScoreState extends State <TotalScore> {
@override
Widget build(BuildContext context) {
return Container(
height: 85,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (TotalScore.isScoreChanged)
Stack(
children: [
FadeInUp(
duration: Duration(milliseconds: 500),
animate: true,
curve: Curves.easeOutQuint,
child: Text(
"${widget.pointsEarned > 0 ? '+' : ''}${widget.pointsEarned}",
style: GoogleFonts.gluten(
textStyle: TextStyle(
color: widget.pointsEarned > 0 ? Colors.green : Colors.red,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
Container(
height: 60,
width: MediaQuery.of(context).size.width * 0.25,
decoration: BoxDecoration(
border: Border.all(
color: Colors.green,
width: 4,
style: BorderStyle.solid,
),
borderRadius: BorderRadius.circular(15.0),
color: Colors.white,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text(
"Score",
style: GoogleFonts.gluten(
textStyle: TextStyle(
height: 1,
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
),
),
Container(
child: Text(
"${TotalScore.total}",
style: GoogleFonts.gluten(
textStyle: TextStyle(
height: 0.8,
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: 30,
),
),
),
),
],
),
),
],
),
);
}
}
Introduction to FadeIn Animation
The FadeIn animation is a visual effect used to smoothly transition an element from invisible to visible by gradually increasing its opacity. This animation technique is commonly employed in web and mobile app development to enhance user experience and draw attention to specific elements on the screen.
FadeIn animation modifies the opacity of the target element over a specified duration to create a smooth transition effect. Here’s a detailed explanation of how it works in below code,
1. Widget Composition: The widget to be animated, such as a Text or Image, is wrapped inside a FadeIn widget provided by the animate_do library.
2. Configuration: The FadeIn widget is configured with parameters such as duration, delay, curve, and whether to loop the animation.
3. Opacity Transition: During the animation, the FadeIn widget gradually increases the opacity of its child widget from 0 to 1 over the specified duration. This transition creates the effect of the widget fading in.
4. Curve: The curve parameter determines the rate of change of opacity over time, allowing for customization of the animation’s acceleration and deceleration.
5. Completion: Once the animation is complete, the opacity of the child widget reaches its maximum value of 1, making the widget fully visible.
FadeIn(
duration: Duration(milliseconds: 500),
child: Text(
'Hello, World!',
style: TextStyle(fontSize: 20),
),
)
As Tech Co-Founder at Yugensys, I’m passionate about fostering innovation and propelling technological progress. By harnessing the power of cutting-edge solutions, I lead our team in delivering transformative IT services and Outsourced Product Development. My expertise lies in leveraging technology to empower businesses and ensure their success within the dynamic digital landscape.
Looking to augment your software engineering team with a team dedicated to impactful solutions and continuous advancement, feel free to connect with me. Yugensys can be your trusted partner in navigating the ever-evolving technological landscape.
Linkedin Instagram Facebook X-twitter Welcome to our comprehensive guide on bundling a React library into a reusable component library! In…
Linkedin Instagram Facebook X-twitter In today’s tutorial, we’ll explore creation of stunning diagrams using ChatGPT, along with the assistance of…
Linkedin Instagram Facebook X-twitter Introduction: Augmented reality (AR) has transformed the gaming industry, offering players immersive experiences that blend the virtual…
Linkedin Instagram Facebook X-twitter Use Case: Enhancing word discovery in a mobile game In today’s digital age, there’s a growing…