Fixing random target with setState using Splitter
Splitter is a timing and precision game where players try to cut a cucumber according to a target percentage. Every round should feel fresh and different. One of the most important systems inside the game is the random target generator.
If the random target does not update properly the game quickly becomes repetitive. Players may keep seeing the same target again and again. This makes the gameplay boring and predictable.
In Flutter the most common way to refresh values on the screen is by using setState. This method tells Flutter that something changed and the user interface must rebuild with new values.
In this tutorial you will learn how to fix random target generation inside Splitter using setState. You will also understand how random numbers work in Dart and how state updates affect game screens.
This tutorial is designed for beginners who want to improve their Flutter game development skills while building cleaner and more responsive gameplay systems.
Understanding the target system
Before fixing the problem you first need to understand how the target system works inside Splitter.
Every round generates a target percentage. This target tells the player how the cucumber should be divided.
Examples include fifty fifty sixty forty or seventy thirty.
The target percentage appears on the screen and changes whenever the player starts a new round.
A simple target variable may look like this.
int targetPercentage = 50;
This variable stores the current target shown to the player.
Why the target sometimes fails to update
Many beginners create a random number correctly but forget to refresh the user interface. This causes the value to change internally while the screen still shows the old target.
Here is an incorrect example.
void generateTarget() {
Random random = Random();
targetPercentage = random.nextInt(100);
}
The number changes inside memory but Flutter does not know the screen should rebuild.
Because of this the player still sees the old percentage.
Fixing the issue using setState
The correct solution is wrapping the target update inside setState.
void generateTarget() {
Random random = Random();
setState(() {
targetPercentage = random.nextInt(100);
});
}
Now Flutter rebuilds the screen immediately after the value changes.
The player instantly sees the new target percentage.
Importing the random library
Random numbers require the Dart math library.
import 'dart:math';
Without this import Random will not work.
The math library includes useful tools for randomness calculations and advanced game logic.
Creating a complete target system
Let us now build a proper target generator for Splitter.
import 'dart:math';
int targetPercentage = 50;
void generateTarget() {
Random random = Random();
setState(() {
targetPercentage = random.nextInt(81) + 10;
});
}
This version generates values between ten and ninety.
Preventing extremely small or large percentages improves gameplay balance because targets like one percent or ninety nine percent are frustrating for players.
Displaying the target on screen
Once the target updates correctly it must appear visually inside the user interface.
Text(
'$targetPercentage%',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
),
)
Whenever setState runs the text automatically refreshes.
This is one of the biggest advantages of Flutter reactive design.
Generating a target after every round
Splitter should create a fresh target whenever the player finishes a cut.
This keeps gameplay exciting and prevents repetition.
void finishRound() {
generateTarget();
}
Now every completed round creates a new challenge.
Creating readable ratio text
Players usually understand ratios better when displayed as two values instead of a single percentage.
For example seventy thirty feels clearer than simply showing seventy percent.
String getRatioText() {
int secondPart = 100 - targetPercentage;
return '$targetPercentage $secondPart';
}
This creates a balanced ratio display for the player.
Showing the ratio on screen
Text(
getRatioText(),
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w600,
),
)
The displayed ratio changes automatically whenever the target updates.
Preventing duplicate targets
Sometimes random systems accidentally generate the same target repeatedly. This can make gameplay feel repetitive.
A simple solution compares the new target against the old one.
void generateTarget() {
Random random = Random();
int newTarget = targetPercentage;
while (newTarget == targetPercentage) {
newTarget = random.nextInt(81) + 10;
}
setState(() {
targetPercentage = newTarget;
});
}
This guarantees a fresh percentage every round.
Understanding how setState works
Many beginners use setState without fully understanding its purpose.
Flutter user interfaces are built using widgets. These widgets only update visually when Flutter rebuilds them.
setState tells Flutter that the current widget contains updated data and needs rebuilding.
Without setState the screen keeps displaying old values even though variables changed internally.
Creating a full Splitter example
Here is a simplified game structure using random targets and setState together.
import 'dart:math';
import 'package:flutter/material.dart';
class SplitterGame extends StatefulWidget {
@override
State<SplitterGame> createState() {
return _SplitterGameState();
}
}
class _SplitterGameState extends State<SplitterGame> {
int targetPercentage = 50;
@override
void initState() {
super.initState();
generateTarget();
}
void generateTarget() {
Random random = Random();
int newTarget = targetPercentage;
while (newTarget == targetPercentage) {
newTarget = random.nextInt(81) + 10;
}
setState(() {
targetPercentage = newTarget;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'$targetPercentage%',
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 30),
ElevatedButton(
onPressed: generateTarget,
child: Text('Next Target'),
),
],
),
),
);
}
}
This example demonstrates a fully working target generator with proper screen updates.
Adding score calculations
Splitter becomes more rewarding when players earn points based on accuracy.
Accuracy can be calculated by comparing the player cut against the target.
double calculateDifference(
double playerCut,
double target,
) {
return (playerCut - target).abs();
}
Smaller differences mean better precision.
Creating a score system
int calculateScore(
double difference,
) {
int score = (100 - difference).toInt();
if (score < 0) {
score = 0;
}
return score;
}
Perfect cuts give the highest scores while inaccurate cuts reduce points.
Refreshing scores using setState
Scores also need proper screen rebuilding.
int playerScore = 0;
void updateScore(
int newScore,
) {
setState(() {
playerScore = newScore;
});
}
This instantly refreshes the visible score.
Using animation with random targets
Splitter feels more polished when targets appear with animation.
Animated transitions improve visual quality and make gameplay more satisfying.
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: Text(
'$targetPercentage%',
key: ValueKey(targetPercentage),
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
),
),
)
Every new target now fades smoothly onto the screen.
Improving replay value
Random targets are important because they increase replay value.
If the same target appeared repeatedly players would quickly memorize solutions and lose interest.
Dynamic target generation creates uncertainty and keeps the game fresh.
Testing randomness properly
Developers should test random systems carefully.
-
Verify targets update every round
-
Prevent repeated numbers
-
Ensure percentages remain fair
-
Confirm screen updates instantly
-
Check gameplay difficulty balance
Testing is essential because even small logic mistakes can affect the entire player experience.
Common beginner mistakes
Many new Flutter developers make similar mistakes while working with setState and randomness.
-
Forgetting to import dart math
-
Updating variables outside setState
-
Generating impossible target values
-
Repeating the same target constantly
-
Forgetting to refresh score displays
Avoiding these mistakes creates cleaner and more reliable gameplay systems.
Why random targets matter in game design
Randomness creates excitement because players never fully know what challenge comes next.
In Splitter every new target changes how players judge movement and timing.
Some targets are easier while others require extreme precision. This variety keeps gameplay engaging for long periods.
Good randomness improves replay value without requiring massive amounts of content.
Combining timing and randomness
Splitter works because it combines two important gameplay systems.
-
Random target generation
-
Precise player timing
The player must constantly adapt to changing situations while improving reaction speed and visual judgment.
This combination creates a simple but addictive arcade experience.
Final thoughts
Fixing random targets with setState is one of the most important lessons beginners learn in Flutter game development.
Proper state management ensures the user interface always reflects the latest game data. Without it gameplay becomes confusing and unresponsive.
Splitter is a great example because the entire game depends on dynamic percentages and visual updates. By combining randomness with setState you create smoother gameplay and a better player experience.
Once you understand these concepts you can expand them into advanced systems like difficulty scaling combo multipliers animated transitions and adaptive gameplay mechanics.
Mastering random target updates will help you build more interactive Flutter games that feel polished responsive and enjoyable across both mobile and desktop devices.