Skip to content
This repository has been archived by the owner on Mar 6, 2024. It is now read-only.

feat: collect wings to increase the chance to get higher score #186

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lib/game/bloc/game_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:math';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

Expand All @@ -10,6 +12,8 @@ class GameBloc extends Bloc<GameEvent, GameState> {
on<GameScoreDecreased>(_onGameScoreDecreased);
on<GameOver>(_onGameOver);
on<GameSectionCompleted>(_onGameSectionCompleted);
on<GameWingsIncreased>(_onGameWingsIncreased);
on<GameWingsDecreased>(_onGameWingsDecreased);
}

void _onGameScoreIncreased(
Expand All @@ -34,6 +38,28 @@ class GameBloc extends Bloc<GameEvent, GameState> {
);
}

void _onGameWingsIncreased(
GameWingsIncreased event,
Emitter<GameState> emit,
) {
emit(
state.copyWith(
wingsQty: min(state.wingsQty + event.by, GameState.maxWingsQty),
),
);
}

void _onGameWingsDecreased(
GameWingsDecreased event,
Emitter<GameState> emit,
) {
emit(
state.copyWith(
wingsQty: state.wingsQty - event.by,
),
);
}

void _onGameOver(
GameOver event,
Emitter<GameState> emit,
Expand Down
18 changes: 18 additions & 0 deletions lib/game/bloc/game_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ final class GameScoreDecreased extends GameEvent {
List<Object> get props => [by];
}

final class GameWingsIncreased extends GameEvent {
const GameWingsIncreased({this.by = 1});

final int by;

@override
List<Object> get props => [by];
}

final class GameWingsDecreased extends GameEvent {
const GameWingsDecreased({this.by = 1});

final int by;

@override
List<Object> get props => [by];
}

final class GameOver extends GameEvent {
const GameOver();
}
Expand Down
9 changes: 8 additions & 1 deletion lib/game/bloc/game_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,38 @@ part of 'game_bloc.dart';
class GameState extends Equatable {
const GameState({
required this.score,
required this.wingsQty,
required this.currentLevel,
required this.currentSection,
});

const GameState.initial()
: score = 0,
wingsQty = 0,
currentLevel = 1,
currentSection = 0;

final int score;
final int wingsQty;
final int currentLevel;
final int currentSection;

static const maxWingsQty = 5;

GameState copyWith({
int? score,
int? wingsQty,
int? currentLevel,
int? currentSection,
}) {
return GameState(
score: score ?? this.score,
wingsQty: wingsQty ?? this.wingsQty,
currentLevel: currentLevel ?? this.currentLevel,
currentSection: currentSection ?? this.currentSection,
);
}

@override
List<Object?> get props => [score, currentLevel, currentSection];
List<Object?> get props => [score, wingsQty, currentLevel, currentSection];
}
17 changes: 13 additions & 4 deletions lib/game/entities/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class Player extends JumperCharacter<SuperDashGame> {
late final PlayerStateBehavior stateBehavior =
findBehavior<PlayerStateBehavior>();

bool hasGoldenFeather = false;
bool isPlayerInvincible = false;
bool isPlayerTeleporting = false;
bool isPlayerRespawning = false;
Expand All @@ -42,6 +41,8 @@ class Player extends JumperCharacter<SuperDashGame> {
@override
int get priority => 1;

bool get hasGoldenFeather => gameRef.state.wingsQty > 0;

void jumpEffects() {
final jumpSound = hasGoldenFeather ? Sfx.phoenixJump : Sfx.jump;
gameRef.audioController.playSfx(jumpSound);
Expand Down Expand Up @@ -125,7 +126,9 @@ class Player extends JumperCharacter<SuperDashGame> {
}

void addPowerUp() {
hasGoldenFeather = true;
gameRef.gameBloc.add(
const GameWingsIncreased(),
);

if (stateBehavior.state == DashState.idle) {
stateBehavior.state = DashState.phoenixIdle;
Expand Down Expand Up @@ -172,7 +175,10 @@ class Player extends JumperCharacter<SuperDashGame> {
}

// If player has a golden feather, use it to avoid death.
hasGoldenFeather = false;
gameRef.gameBloc.add(
const GameWingsDecreased(),
);

return respawn();
}

Expand Down Expand Up @@ -213,7 +219,10 @@ class Player extends JumperCharacter<SuperDashGame> {
}

// If player has a golden feather, use it to avoid death.
hasGoldenFeather = false;
gameRef.gameBloc.add(
const GameWingsDecreased(),
);

return respawn();
}
}
Expand Down
17 changes: 14 additions & 3 deletions lib/game/widgets/score_label.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class ScoreLabel extends StatelessWidget {
Widget build(BuildContext context) {
final l10n = context.l10n;
final textTheme = Theme.of(context).textTheme;
final score = context.select(
(GameBloc bloc) => bloc.state.score,
final state = context.select(
(GameBloc bloc) => (score: bloc.state.score, wings: bloc.state.wingsQty),
);

return SafeArea(
Expand All @@ -37,7 +37,18 @@ class ScoreLabel extends StatelessWidget {
),
const SizedBox(width: 10),
Text(
l10n.gameScoreLabel(score),
l10n.gameScoreLabel(state.score),
style: textTheme.titleLarge?.copyWith(
color: const Color(0xFF4D5B92),
),
),
const SizedBox(width: 10),
Assets.images.powerfulWingsInstruction.image(
width: 40,
height: 40,
),
Text(
l10n.wingsQtyLabel(state.wings),
style: textTheme.titleLarge?.copyWith(
color: const Color(0xFF4D5B92),
),
Expand Down
9 changes: 9 additions & 0 deletions lib/l10n/arb/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,15 @@
}
}
},
"wingsQtyLabel": "{points}x Wings",
"@wingsQtyLabel": {
"description": "Text shown on the game wings label",
"placeholders": {
"points": {
"type": "int"
}
}
},
"leaderboardPageLeaderboardHeadline": "Leaderboard",
"@leaderboardPageLeaderboardHeadline": {
"description": "Text shown in the leaderboard page headline"
Expand Down
30 changes: 30 additions & 0 deletions test/game/bloc/game_bloc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ void main() {
score: 100,
currentLevel: 2,
currentSection: 2,
wingsQty: 2,
),
act: (bloc) => bloc.add(GameOver()),
expect: () => const [GameState.initial()],
Expand All @@ -35,5 +36,34 @@ void main() {
act: (bloc) => bloc.add(GameScoreDecreased(by: 2)),
expect: () => [const GameState.initial().copyWith(score: 98)],
);

blocTest<GameBloc, GameState>(
'emits GameState with wings increased correctly '
'when dash collect a wing',
build: GameBloc.new,
seed: () => const GameState.initial().copyWith(wingsQty: 1),
act: (bloc) => bloc.add(GameWingsIncreased()),
expect: () => [const GameState.initial().copyWith(wingsQty: 2)],
);

blocTest<GameBloc, GameState>(
'emits GameState with wings decreased correctly '
'when dash lost a wing',
build: GameBloc.new,
seed: () => const GameState.initial().copyWith(wingsQty: 1),
act: (bloc) => bloc.add(GameWingsDecreased()),
expect: () => [const GameState.initial().copyWith(wingsQty: 0)],
);

blocTest<GameBloc, GameState>(
'not emits GameState when dash collect a '
'new wing and exceed the max wings qty',
build: GameBloc.new,
seed: () => const GameState.initial().copyWith(
wingsQty: GameState.maxWingsQty,
),
act: (bloc) => bloc.add(GameWingsIncreased()),
expect: () => <GameState>[],
);
});
}
13 changes: 10 additions & 3 deletions test/game/bloc/game_state_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void main() {
test('returns object with updated score when score is passed', () {
expect(
GameState.initial().copyWith(score: 100),
GameState(score: 100, currentLevel: 1, currentSection: 0),
GameState(score: 100, currentLevel: 1, currentSection: 0, wingsQty: 0),
);
});

Expand All @@ -30,15 +30,22 @@ void main() {
() {
expect(
GameState.initial().copyWith(currentLevel: 2),
GameState(score: 0, currentLevel: 2, currentSection: 0),
GameState(score: 0, currentLevel: 2, currentSection: 0, wingsQty: 0),
);
},
);

test('returns object with updated currentSection when score is passed', () {
expect(
GameState.initial().copyWith(currentSection: 3),
GameState(score: 0, currentLevel: 1, currentSection: 3),
GameState(score: 0, currentLevel: 1, currentSection: 3, wingsQty: 0),
);
});

test('returns object with updated wings when wings is passed', () {
expect(
GameState.initial().copyWith(wingsQty: 2),
GameState(score: 0, currentLevel: 1, currentSection: 0, wingsQty: 2),
);
});
});
Expand Down