- Add gridWidth and gridHeight properties to level configuration - Update GameGrid to accept custom dimensions instead of using constants - Modify GridComponent to calculate gem size based on grid dimensions - Update MatchThreeGame constructor to pass grid dimensions - Ensure proper scaling and positioning for variable grid sizes
142 lines
3.5 KiB
Dart
142 lines
3.5 KiB
Dart
import 'package:flame/components.dart';
|
|
import 'package:flame/effects.dart';
|
|
import 'package:flame/events.dart';
|
|
import 'package:flutter/material.dart';
|
|
import '../models/gem.dart';
|
|
import '../systems/physics_system.dart';
|
|
import 'grid_component.dart';
|
|
import 'particle_system.dart';
|
|
import '../../utils/constants.dart';
|
|
|
|
class GemComponent extends RectangleComponent with TapCallbacks {
|
|
final Gem gem;
|
|
final GridComponent gridComponent;
|
|
bool isSelected = false;
|
|
|
|
static const List<Color> gemColors = [
|
|
Colors.red,
|
|
Colors.blue,
|
|
Colors.green,
|
|
Colors.yellow,
|
|
Colors.purple,
|
|
Colors.orange,
|
|
];
|
|
|
|
GemComponent({required this.gem, required this.gridComponent})
|
|
: super(
|
|
size: Vector2.all(gridComponent.gemSize - 4),
|
|
paint: Paint()..color = gemColors[gem.type % gemColors.length],
|
|
);
|
|
|
|
@override
|
|
bool onTapDown(TapDownEvent event) {
|
|
if (!gridComponent.canInterract) return false;
|
|
gridComponent.onGemTapped(gem);
|
|
_animateSelection();
|
|
PhysicsSystem.animatePop(this);
|
|
return true;
|
|
}
|
|
|
|
void _animateSelection() {
|
|
isSelected = !isSelected;
|
|
final scaleEffect = ScaleEffect.to(
|
|
Vector2.all(isSelected ? 1.1 : 1.0),
|
|
EffectController(duration: 0.2),
|
|
);
|
|
add(scaleEffect);
|
|
}
|
|
|
|
animateMatch() async {
|
|
// Add particle explosion
|
|
final explosion = ParticleSystem.createMatchExplosion(
|
|
position + size / 2,
|
|
gemColors[gem.type % gemColors.length],
|
|
);
|
|
parent?.add(explosion);
|
|
|
|
// Animate gem destruction
|
|
PhysicsSystem.animateMatch(this);
|
|
|
|
// Remove after animation
|
|
await Future.delayed(
|
|
Duration(milliseconds: (GameConstants.matchDuration * 1000).round()),
|
|
() {
|
|
removeFromParent();
|
|
});
|
|
}
|
|
|
|
animateFall(Vector2 targetPosition) async {
|
|
await PhysicsSystem.animateFall(this, targetPosition);
|
|
}
|
|
|
|
animateCombo() {
|
|
final comboEffect = ParticleSystem.createComboEffect(position + size / 2);
|
|
parent?.add(comboEffect);
|
|
}
|
|
|
|
@override
|
|
void render(Canvas canvas) {
|
|
super.render(canvas);
|
|
|
|
// Add gradient effect
|
|
final gradient = RadialGradient(
|
|
colors: [
|
|
gemColors[gem.type % gemColors.length].withOpacity(0.9),
|
|
gemColors[gem.type % gemColors.length],
|
|
],
|
|
);
|
|
|
|
final gradientPaint = Paint()
|
|
..shader = gradient.createShader(size.toRect());
|
|
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(
|
|
size.toRect(),
|
|
const Radius.circular(8),
|
|
),
|
|
gradientPaint,
|
|
);
|
|
|
|
// Add border and glow effect
|
|
final borderColor = isSelected ? Colors.white : Colors.black26;
|
|
final borderWidth = isSelected ? 3.0 : 1.0;
|
|
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(
|
|
size.toRect(),
|
|
const Radius.circular(8),
|
|
),
|
|
Paint()
|
|
..color = borderColor
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = borderWidth,
|
|
);
|
|
|
|
if (isSelected) {
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(
|
|
size.toRect().inflate(2),
|
|
const Radius.circular(10),
|
|
),
|
|
Paint()
|
|
..color = Colors.white.withOpacity(0.3)
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 2,
|
|
);
|
|
}
|
|
|
|
// Add shine effect
|
|
final shinePaint = Paint()
|
|
..color = Colors.white.withOpacity(0.3)
|
|
..style = PaintingStyle.fill;
|
|
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(
|
|
Rect.fromLTWH(size.x * 0.2, size.y * 0.1, size.x * 0.3, size.y * 0.2),
|
|
const Radius.circular(4),
|
|
),
|
|
shinePaint,
|
|
);
|
|
}
|
|
}
|