Skip to content

Commit

Permalink
piece: Add more animations
Browse files Browse the repository at this point in the history
  • Loading branch information
calcitem committed Oct 16, 2024
1 parent e8a057e commit 74a5689
Show file tree
Hide file tree
Showing 71 changed files with 1,378 additions and 286 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class DisplaySettings {
this.markedPieceImagePath = '',
this.boardImagePath = '',
this.vignetteEffectEnabled = false,
this.placeEffectAnimation = 'Default',
this.removeEffectAnimation = 'Default',
});

/// Encodes a Json style map into a [DisplaySettings] object
Expand Down Expand Up @@ -174,6 +176,12 @@ class DisplaySettings {
@HiveField(27, defaultValue: false)
final bool vignetteEffectEnabled;

@HiveField(28, defaultValue: 'Default')
final String placeEffectAnimation;

@HiveField(29, defaultValue: 'Default')
final String removeEffectAnimation;

/// Decodes a Json from a [DisplaySettings] object
Map<String, dynamic> toJson() => _$DisplaySettingsToJson(this);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ import '../../shared/themes/app_theme.dart';
import '../../shared/widgets/snackbars/scaffold_messenger.dart';
import '../models/color_settings.dart';
import '../models/display_settings.dart';
import 'piece_effect_selection_page.dart';

part 'package:sanmill/appearance_settings/widgets/modals/point_painting_style_modal.dart';
part 'package:sanmill/appearance_settings/widgets/pickers/background_image_picker.dart';
part 'package:sanmill/appearance_settings/widgets/pickers/board_image_picker.dart';
part 'package:sanmill/appearance_settings/widgets/pickers/piece_image_picker.dart';
part 'package:sanmill/appearance_settings/widgets/pickers/language_picker.dart';
part 'package:sanmill/appearance_settings/widgets/pickers/piece_image_picker.dart';
part 'package:sanmill/appearance_settings/widgets/sliders/animation_duration_slider.dart';
part 'package:sanmill/appearance_settings/widgets/sliders/board_boarder_line_width_slider.dart';
part 'package:sanmill/appearance_settings/widgets/sliders/board_inner_line_width_slider.dart';
Expand Down Expand Up @@ -108,6 +109,42 @@ class AppearanceSettingsPage extends StatelessWidget {
builder: (_) => const _AnimationDurationSlider(),
);

Future<void> setPlaceEffectAnimation(BuildContext context) async {
final EffectItem? selectedEffect = await Navigator.push<EffectItem>(
context,
MaterialPageRoute<EffectItem>(
builder: (BuildContext context) => const PieceEffectSelectionPage(),
),
);

if (selectedEffect != null) {
DB().displaySettings = DB().displaySettings.copyWith(
placeEffectAnimation: selectedEffect.name,
);

logger
.t("[config] Selected PlaceEffectAnimation: ${selectedEffect.name}");
}
}

Future<void> setRemoveEffectAnimation(BuildContext context) async {
final EffectItem? selectedEffect = await Navigator.push<EffectItem>(
context,
MaterialPageRoute<EffectItem>(
builder: (BuildContext context) => const PieceEffectSelectionPage(),
),
);

if (selectedEffect != null) {
DB().displaySettings = DB().displaySettings.copyWith(
removeEffectAnimation: selectedEffect.name,
);

logger
.t("[config] Selected RemoveEffectAnimation: ${selectedEffect.name}");
}
}

void setBackgroundImage(BuildContext context) => showModalBottomSheet(
context: context,
builder: (_) => const _BackgroundImagePicker(),
Expand Down Expand Up @@ -585,6 +622,14 @@ class AppearanceSettingsPage extends StatelessWidget {
titleString: S.of(context).animationDuration,
onTap: () => setAnimationDuration(context),
),
SettingsListTile(
titleString: S.of(context).placeEffectAnimation,
onTap: () => setPlaceEffectAnimation(context),
),
SettingsListTile(
titleString: S.of(context).removeEffectAnimation,
onTap: () => setRemoveEffectAnimation(context),
),
SettingsListTile.switchTile(
value: displaySettings.vignetteEffectEnabled,
onChanged: (bool val) => DB().displaySettings =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
// This file is part of Sanmill.
// Copyright (C) 2019-2024 The Sanmill developers
//
// Sanmill is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Sanmill is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../../game_page/services/painters/animations/piece_effect_animation.dart';
import '../../generated/intl/l10n.dart';
import '../../shared/themes/app_theme.dart';

/// Effect item model to hold the name and animation instance.
class EffectItem {
EffectItem({required this.name, required this.animation});
final String name;
final PieceEffectAnimation animation;
}

/// The main page that displays the animations in a grid.
class PieceEffectSelectionPage extends StatefulWidget {
const PieceEffectSelectionPage({super.key});

@override
PieceEffectSelectionPageState createState() =>
PieceEffectSelectionPageState();
}

class PieceEffectSelectionPageState extends State<PieceEffectSelectionPage> {
late List<EffectItem> effects;

@override
void initState() {
super.initState();

// Initialize the list of effect items.
effects = <EffectItem>[
EffectItem(name: 'Aura', animation: AuraPieceEffectAnimation()),
EffectItem(name: 'Echo', animation: EchoPieceEffectAnimation()),
EffectItem(name: 'Expand', animation: ExpandPieceEffectAnimation()),
EffectItem(name: 'Explode', animation: ExplodePieceEffectAnimation()),
EffectItem(name: 'Orbit', animation: OrbitPieceEffectAnimation()),
EffectItem(
name: 'ParticleBurst',
animation: ParticleBurstPieceEffectAnimation()),
EffectItem(name: 'Radial', animation: RadialPieceEffectAnimation()),
EffectItem(name: 'Ripple', animation: RipplePieceEffectAnimation()),
EffectItem(name: 'Rotate', animation: RotatePieceEffectAnimation()),
EffectItem(name: 'Spiral', animation: SpiralPieceEffectAnimation()),
EffectItem(name: 'Shatter', animation: ShatterPieceEffectAnimation()),
EffectItem(name: 'Disperse', animation: DispersePieceEffectAnimation()),
EffectItem(name: 'Radiate', animation: RadiatePieceEffectAnimation()),
EffectItem(name: 'StarBurst', animation: StarBurstPieceEffectAnimation()),
EffectItem(name: 'Vanish', animation: VanishPieceEffectAnimation()),
EffectItem(name: 'Fade', animation: FadePieceEffectAnimation()),
EffectItem(name: 'Melt', animation: MeltPieceEffectAnimation()),
];
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
S.of(context).settings,
style: AppTheme.appBarTheme.titleTextStyle,
),
),
body: GridView.builder(
padding: const EdgeInsets.all(8.0),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 3 items per row
crossAxisSpacing: 8.0,
mainAxisSpacing: 8.0,
),
itemCount: effects.length,
itemBuilder: (BuildContext context, int index) {
final EffectItem effectItem = effects[index];
return EffectGridItem(
effectItem: effectItem,
onTap: () {
// Handle the selection logic here.
if (kDebugMode) {
print('Selected effect: ${effectItem.name}');
}

Navigator.pop(context,
effectItem); // Return the selected effect to the previous page.
},
);
},
),
);
}
}

/// Widget representing each grid item in the selection page.
class EffectGridItem extends StatefulWidget {
const EffectGridItem({
super.key,
required this.effectItem,
required this.onTap,
});
final EffectItem effectItem;
final VoidCallback onTap;

@override
EffectGridItemState createState() => EffectGridItemState();
}

class EffectGridItemState extends State<EffectGridItem>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;

@override
void initState() {
super.initState();

// Initialize the animation controller.
_controller = AnimationController(
duration: const Duration(seconds: 2), // Duration of each animation cycle.
vsync: this,
);

_animation = CurvedAnimation(parent: _controller, curve: Curves.linear);

// Repeat the animation indefinitely.
_controller.repeat();
}

@override
void dispose() {
// Dispose the animation controller to free resources.
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
// GestureDetector to handle taps on the grid item.
return GestureDetector(
onTap: widget.onTap,
child: Column(
children: <Widget>[
// Use Expanded and AspectRatio to maintain a square shape.
Expanded(
child: AspectRatio(
aspectRatio: 1.0,
// AnimatedBuilder to rebuild the CustomPaint when the animation updates.
child: AnimatedBuilder(
animation: _animation,
builder: (BuildContext context, Widget? child) {
return CustomPaint(
painter: EffectPainter(
animation: widget.effectItem.animation,
animationValue: _animation.value,
),
);
},
),
),
),
const SizedBox(height: 4.0),
// Display the name of the effect.
Text(widget.effectItem.name),
],
),
);
}
}

/// Custom painter that uses the PieceEffectAnimation to draw the effect.
class EffectPainter extends CustomPainter {
EffectPainter({required this.animation, required this.animationValue});
final PieceEffectAnimation animation;
final double animationValue;

@override
void paint(Canvas canvas, Size size) {
// Calculate the center and diameter based on the size of the widget.
final Offset center = Offset(size.width / 2, size.height / 2);
final double diameter = min(size.width, size.height);

// Use the animation's draw method to render the effect.
animation.draw(canvas, center, diameter, animationValue);
}

@override
bool shouldRepaint(covariant EffectPainter oldDelegate) {
// Repaint when the animation value changes.
return oldDelegate.animationValue != animationValue ||
oldDelegate.animation != animation;
}
}
Loading

0 comments on commit 74a5689

Please sign in to comment.