160 lines
No EOL
3.7 KiB
Dart
160 lines
No EOL
3.7 KiB
Dart
import 'package:flame/components.dart';
|
|
import 'package:flame/effects.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'dart:math';
|
|
|
|
enum PoopBagState { placed, lit, burning, extinguished }
|
|
|
|
class PoopBag extends CircleComponent {
|
|
PoopBagState state = PoopBagState.placed;
|
|
double burnTimer = 0.0;
|
|
static const double burnDuration = 3.0; // seconds to burn
|
|
static const double bagSize = 16.0;
|
|
|
|
late Vector2 smokeOffset;
|
|
List<SmokeParticle> smokeParticles = [];
|
|
|
|
@override
|
|
Future<void> onLoad() async {
|
|
await super.onLoad();
|
|
|
|
radius = bagSize / 2;
|
|
paint = Paint()..color = const Color(0xFF8B4513); // Brown color
|
|
|
|
smokeOffset = Vector2(0, -radius - 5);
|
|
}
|
|
|
|
void lightOnFire() {
|
|
if (state == PoopBagState.placed) {
|
|
state = PoopBagState.lit;
|
|
burnTimer = 0.0;
|
|
|
|
// Add flame effect
|
|
add(
|
|
ScaleEffect.to(
|
|
Vector2.all(1.2),
|
|
EffectController(duration: 0.5, infinite: true, reverseDuration: 0.5),
|
|
),
|
|
);
|
|
|
|
debugPrint('Poop bag is now on fire!');
|
|
}
|
|
}
|
|
|
|
@override
|
|
void update(double dt) {
|
|
super.update(dt);
|
|
|
|
if (state == PoopBagState.lit) {
|
|
burnTimer += dt;
|
|
|
|
// Generate smoke particles
|
|
if (burnTimer % 0.2 < dt) { // Every 0.2 seconds
|
|
generateSmokeParticle();
|
|
}
|
|
|
|
// Check if fully burned
|
|
if (burnTimer >= burnDuration) {
|
|
state = PoopBagState.burning;
|
|
extinguish();
|
|
}
|
|
}
|
|
|
|
// Update smoke particles
|
|
smokeParticles.removeWhere((particle) {
|
|
particle.update(dt);
|
|
return particle.shouldRemove;
|
|
});
|
|
}
|
|
|
|
void generateSmokeParticle() {
|
|
final random = Random();
|
|
final particle = SmokeParticle(
|
|
position: position + smokeOffset + Vector2(
|
|
random.nextDouble() * 10 - 5,
|
|
random.nextDouble() * 5,
|
|
),
|
|
);
|
|
smokeParticles.add(particle);
|
|
}
|
|
|
|
void extinguish() {
|
|
state = PoopBagState.extinguished;
|
|
removeAll(children.whereType<Effect>());
|
|
|
|
// Change to burnt color
|
|
paint = Paint()..color = const Color(0xFF2F2F2F);
|
|
|
|
debugPrint('Poop bag has burned out');
|
|
}
|
|
|
|
@override
|
|
void render(Canvas canvas) {
|
|
super.render(canvas);
|
|
|
|
// Draw flame effect when lit
|
|
if (state == PoopBagState.lit) {
|
|
final flamePaint = Paint()
|
|
..color = Color.lerp(
|
|
const Color(0xFFFF4500),
|
|
const Color(0xFFFFD700),
|
|
sin(burnTimer * 10) * 0.5 + 0.5,
|
|
)!;
|
|
|
|
// Draw flickering flame
|
|
canvas.drawCircle(
|
|
Offset(0, -radius - 5),
|
|
radius * 0.6 + sin(burnTimer * 15) * 2,
|
|
flamePaint,
|
|
);
|
|
}
|
|
|
|
// Render smoke particles
|
|
for (final particle in smokeParticles) {
|
|
particle.render(canvas);
|
|
}
|
|
}
|
|
|
|
bool isNearPosition(Vector2 targetPosition, {double threshold = 30.0}) {
|
|
return (position - targetPosition).length < threshold;
|
|
}
|
|
}
|
|
|
|
class SmokeParticle {
|
|
Vector2 position;
|
|
Vector2 velocity;
|
|
double life;
|
|
double maxLife;
|
|
bool shouldRemove = false;
|
|
|
|
SmokeParticle({required this.position})
|
|
: velocity = Vector2(
|
|
Random().nextDouble() * 20 - 10,
|
|
-Random().nextDouble() * 30 - 20,
|
|
),
|
|
life = 2.0,
|
|
maxLife = 2.0;
|
|
|
|
void update(double dt) {
|
|
position += velocity * dt;
|
|
velocity *= 0.98; // Slight air resistance
|
|
life -= dt;
|
|
|
|
if (life <= 0) {
|
|
shouldRemove = true;
|
|
}
|
|
}
|
|
|
|
void render(Canvas canvas) {
|
|
final alpha = (life / maxLife).clamp(0.0, 1.0);
|
|
final smokePaint = Paint()
|
|
..color = Color(0xFF666666).withOpacity(alpha * 0.3);
|
|
|
|
canvas.drawCircle(
|
|
Offset(position.x, position.y),
|
|
6.0 * (1.0 - life / maxLife),
|
|
smokePaint,
|
|
);
|
|
}
|
|
} |