297 lines
No EOL
7.9 KiB
Dart
297 lines
No EOL
7.9 KiB
Dart
import 'package:flame/components.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:shitman/game/components/level_components.dart';
|
|
import 'package:shitman/game/components/vision_cone.dart';
|
|
import 'package:shitman/settings/app_settings.dart';
|
|
import 'dart:math';
|
|
|
|
/// PIR sensor triggered light
|
|
class PIRSensorComponent extends SecurityComponent with AppSettings {
|
|
bool isTriggered = false;
|
|
bool lightsOn = false;
|
|
bool _showDetectionRadius = true;
|
|
|
|
PIRSensorComponent({
|
|
required super.position,
|
|
super.detectionRange = 40.0,
|
|
}) {
|
|
size = Vector2(8, 8);
|
|
}
|
|
|
|
@override
|
|
Future<void> onLoad() async {
|
|
await super.onLoad();
|
|
await initSettings();
|
|
|
|
// Initialize detection radius visibility from settings
|
|
try {
|
|
_showDetectionRadius = appSettings.getBool('game.show_detection_radius');
|
|
} catch (e) {
|
|
_showDetectionRadius = true; // Default to visible
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool detectsPlayer(Vector2 playerPosition, double playerStealthLevel) {
|
|
final distance = (playerPosition - position).length;
|
|
final effectiveRange = getEffectiveDetectionRange(playerStealthLevel);
|
|
|
|
bool detected = distance < effectiveRange;
|
|
|
|
if (detected && !isTriggered) {
|
|
isTriggered = true;
|
|
lightsOn = true;
|
|
appLog.fine('PIR sensor triggered at $position');
|
|
} else if (!detected && isTriggered) {
|
|
// Cool down period before turning off
|
|
Future.delayed(const Duration(seconds: 5), () {
|
|
isTriggered = false;
|
|
lightsOn = false;
|
|
});
|
|
}
|
|
|
|
return detected;
|
|
}
|
|
|
|
@override
|
|
void render(Canvas canvas) {
|
|
// Draw detection radius if enabled
|
|
if (_showDetectionRadius) {
|
|
final radiusPaint = Paint()
|
|
..color = const Color(0xFFFF9800).withValues(alpha: 0.2)
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 2.0;
|
|
canvas.drawCircle(
|
|
Offset(size.x / 2, size.y / 2),
|
|
detectionRange,
|
|
radiusPaint,
|
|
);
|
|
}
|
|
|
|
// Draw PIR sensor as small circle
|
|
final sensorPaint = Paint()
|
|
..color = isTriggered ? const Color(0xFFFF0000) : const Color(0xFF000000);
|
|
canvas.drawCircle(Offset(size.x / 2, size.y / 2), 4, sensorPaint);
|
|
|
|
// Draw light effect if triggered
|
|
if (lightsOn) {
|
|
final lightPaint = Paint()
|
|
..color = const Color(0xFFFFFF00).withValues(alpha: 0.3);
|
|
canvas.drawCircle(
|
|
Offset(size.x / 2, size.y / 2),
|
|
detectionRange,
|
|
lightPaint,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Update detection radius visibility (call when settings change)
|
|
void updateDetectionRadiusVisibility(bool visible) {
|
|
_showDetectionRadius = visible;
|
|
}
|
|
|
|
/// Refresh visibility from current settings
|
|
void refreshVisibilityFromSettings() {
|
|
try {
|
|
final newVisibility = appSettings.getBool('game.show_detection_radius');
|
|
updateDetectionRadiusVisibility(newVisibility);
|
|
} catch (e) {
|
|
// Settings not ready, keep current state
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> reset() async {
|
|
isTriggered = false;
|
|
lightsOn = false;
|
|
}
|
|
}
|
|
|
|
/// Security camera with vision cone
|
|
class SecurityCameraComponent extends SecurityComponent with AppSettings {
|
|
late VisionCone visionCone;
|
|
double direction;
|
|
bool _currentVisionConeVisibility = true;
|
|
|
|
SecurityCameraComponent({
|
|
required super.position,
|
|
required this.direction,
|
|
super.detectionRange = 120.0,
|
|
}) {
|
|
size = Vector2(8, 8);
|
|
}
|
|
|
|
@override
|
|
Future<void> onLoad() async {
|
|
await super.onLoad();
|
|
await initSettings();
|
|
|
|
// Create vision cone with initial visibility based on settings
|
|
try {
|
|
_currentVisionConeVisibility = appSettings.getBool('game.show_vision_cones');
|
|
} catch (e) {
|
|
_currentVisionConeVisibility = true; // Default to visible
|
|
}
|
|
|
|
visionCone = VisionCone(
|
|
origin: Vector2.zero(),
|
|
direction: direction,
|
|
range: detectionRange,
|
|
fov: pi / 2, // 90 degrees
|
|
color: Colors.red,
|
|
opacity: _currentVisionConeVisibility ? 0.3 : 0.0,
|
|
);
|
|
add(visionCone);
|
|
}
|
|
|
|
@override
|
|
bool detectsPlayer(Vector2 playerPosition, double playerStealthLevel) {
|
|
return visionCone.canSee(playerPosition) &&
|
|
visionCone.hasLineOfSight(playerPosition, []);
|
|
}
|
|
|
|
@override
|
|
void render(Canvas canvas) {
|
|
// Draw camera as black circle
|
|
final cameraPaint = Paint()..color = const Color(0xFF000000);
|
|
canvas.drawCircle(Offset(size.x / 2, size.y / 2), 4, cameraPaint);
|
|
}
|
|
|
|
/// Call this method when settings change to update vision cone visibility
|
|
void updateVisionConeVisibility(bool visible) {
|
|
if (_currentVisionConeVisibility != visible) {
|
|
_currentVisionConeVisibility = visible;
|
|
visionCone.updateOpacity(visible ? 0.3 : 0.0);
|
|
}
|
|
}
|
|
|
|
/// Refresh visibility from current settings (call when settings might have changed)
|
|
void refreshVisibilityFromSettings() {
|
|
try {
|
|
final newVisibility = appSettings.getBool('game.show_vision_cones');
|
|
updateVisionConeVisibility(newVisibility);
|
|
} catch (e) {
|
|
// Settings not ready, keep current state
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> reset() async {
|
|
await visionCone.reset();
|
|
}
|
|
}
|
|
|
|
/// Guard dog with patrol area
|
|
class GuardDogComponent extends SecurityComponent with AppSettings {
|
|
Vector2 patrolCenter;
|
|
double patrolRadius;
|
|
double currentAngle = 0;
|
|
bool isPatrolling = true;
|
|
bool _showDetectionRadius = true;
|
|
|
|
GuardDogComponent({
|
|
required super.position,
|
|
required this.patrolCenter,
|
|
this.patrolRadius = 30.0,
|
|
super.detectionRange = 50.0,
|
|
}) {
|
|
size = Vector2(12, 12);
|
|
}
|
|
|
|
@override
|
|
Future<void> onLoad() async {
|
|
await super.onLoad();
|
|
await initSettings();
|
|
|
|
// Initialize detection radius visibility from settings
|
|
try {
|
|
_showDetectionRadius = appSettings.getBool('game.show_detection_radius');
|
|
} catch (e) {
|
|
_showDetectionRadius = true; // Default to visible
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool detectsPlayer(Vector2 playerPosition, double playerStealthLevel) {
|
|
final distance = (playerPosition - position).length;
|
|
final effectiveRange = getEffectiveDetectionRange(playerStealthLevel);
|
|
|
|
return distance < effectiveRange;
|
|
}
|
|
|
|
@override
|
|
void update(double dt) {
|
|
super.update(dt);
|
|
|
|
if (isPatrolling) {
|
|
// Simple circular patrol
|
|
currentAngle += dt * 0.5; // Rotation speed
|
|
final offset = Vector2(
|
|
cos(currentAngle) * patrolRadius,
|
|
sin(currentAngle) * patrolRadius,
|
|
);
|
|
position = patrolCenter + offset;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void render(Canvas canvas) {
|
|
// Draw detection radius if enabled
|
|
if (_showDetectionRadius) {
|
|
final radiusPaint = Paint()
|
|
..color = const Color(0xFFFF9800).withValues(alpha: 0.2)
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 2.0;
|
|
canvas.drawCircle(
|
|
Offset(size.x / 2, size.y / 2),
|
|
detectionRange,
|
|
radiusPaint,
|
|
);
|
|
}
|
|
|
|
// Draw dog house
|
|
final dogHousePaint = Paint()..color = const Color(0xFF8B4513);
|
|
canvas.drawRect(
|
|
Rect.fromLTWH(0, 0, size.x, size.y),
|
|
dogHousePaint,
|
|
);
|
|
|
|
// Draw dog (simple circle)
|
|
final dogPaint = Paint()..color = const Color(0xFF654321);
|
|
canvas.drawCircle(
|
|
Offset(size.x / 2, size.y / 2),
|
|
4,
|
|
dogPaint,
|
|
);
|
|
}
|
|
|
|
void stopPatrol() {
|
|
isPatrolling = false;
|
|
}
|
|
|
|
void startPatrol() {
|
|
isPatrolling = true;
|
|
}
|
|
|
|
/// Update detection radius visibility (call when settings change)
|
|
void updateDetectionRadiusVisibility(bool visible) {
|
|
_showDetectionRadius = visible;
|
|
}
|
|
|
|
/// Refresh visibility from current settings
|
|
void refreshVisibilityFromSettings() {
|
|
try {
|
|
final newVisibility = appSettings.getBool('game.show_detection_radius');
|
|
updateDetectionRadiusVisibility(newVisibility);
|
|
} catch (e) {
|
|
// Settings not ready, keep current state
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> reset() async {
|
|
currentAngle = 0;
|
|
isPatrolling = true;
|
|
position = patrolCenter;
|
|
}
|
|
} |