shitman/lib/game/components/neighborhood.dart
zeyus 76408247b0
Some checks failed
/ build-web (push) Has been cancelled
some basic movement
2025-07-22 22:35:21 +02:00

309 lines
8.1 KiB
Dart

import 'package:flame/components.dart';
import 'package:flutter/material.dart';
import 'package:shitman/game/components/vision_cone.dart';
import 'package:shitman/game/shitman_game.dart';
import 'dart:math';
class Neighborhood extends Component {
static const double streetWidth = 60.0;
static const double houseSize = 80.0;
static const double yardSize = 40.0;
List<House> houses = [];
late List<Vector2> streetPaths;
@override
Future<void> onLoad() async {
await super.onLoad();
generateNeighborhood();
}
void generateNeighborhood() {
houses.clear();
removeAll(children);
// Create a simple 3x3 grid of houses
final random = Random();
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
// Skip center for street intersection
if (row == 1 && col == 1) continue;
final housePosition = Vector2(
col * (houseSize + streetWidth) + streetWidth,
row * (houseSize + streetWidth) + streetWidth,
);
final house = House(
position: housePosition,
isTarget: false, // Target will be set separately
houseType: random.nextInt(3), // 3 different house types
);
houses.add(house);
add(house);
}
}
// Generate street paths
generateStreetPaths();
}
void generateStreetPaths() {
streetPaths = [];
// Horizontal streets
for (int i = 0; i < 4; i++) {
streetPaths.add(Vector2(0, i * (houseSize + streetWidth)));
streetPaths.add(Vector2(800, i * (houseSize + streetWidth)));
}
// Vertical streets
for (int i = 0; i < 4; i++) {
streetPaths.add(Vector2(i * (houseSize + streetWidth), 0));
streetPaths.add(Vector2(i * (houseSize + streetWidth), 600));
}
}
House? getRandomHouse() {
if (houses.isEmpty) return null;
final random = Random();
return houses[random.nextInt(houses.length)];
}
@override
void render(Canvas canvas) {
super.render(canvas);
// Draw streets
final streetPaint = Paint()..color = const Color(0xFF333333);
// Horizontal streets
for (int row = 0; row <= 3; row++) {
canvas.drawRect(
Rect.fromLTWH(
0,
row * (houseSize + streetWidth) - streetWidth / 2,
800,
streetWidth,
),
streetPaint,
);
}
// Vertical streets
for (int col = 0; col <= 3; col++) {
canvas.drawRect(
Rect.fromLTWH(
col * (houseSize + streetWidth) - streetWidth / 2,
0,
streetWidth,
600,
),
streetPaint,
);
}
}
}
class House extends RectangleComponent with HasGameReference<ShitmanGame> {
bool isTarget;
int houseType;
bool hasLights = false;
bool hasSecurityCamera = false;
bool hasWatchDog = false;
Vector2? doorPosition;
Vector2? yardCenter;
VisionCone? visionCone;
House({
required Vector2 position,
required this.isTarget,
required this.houseType,
}) : super(position: position, size: Vector2.all(Neighborhood.houseSize));
@override
Future<void> onLoad() async {
await super.onLoad();
// Set house color based on type
paint = Paint()..color = _getHouseColor();
// Calculate door and yard positions
doorPosition = position + Vector2(size.x / 2, size.y);
yardCenter = position + size / 2;
// Randomly add security features
final random = Random();
hasLights = random.nextBool();
hasSecurityCamera = random.nextDouble() < 0.3;
hasWatchDog = random.nextDouble() < 0.2;
// Create vision cone for houses with security cameras
if (hasSecurityCamera) {
_createVisionCone();
}
}
void _createVisionCone() {
// Create vision cone facing towards the street
final cameraPosition = Vector2(size.x * 0.9, size.y * 0.1);
final direction = _getOptimalCameraDirection();
visionCone = VisionCone(
origin: cameraPosition,
direction: direction,
range: 120.0,
fov: pi / 2, // 90 degrees
color: Colors.red,
opacity: 0.2,
);
add(visionCone!);
}
double _getOptimalCameraDirection() {
// Point camera towards street/center area
final centerOfMap = Vector2(400, 300);
final houseCenter = position + size / 2;
final toCenter = centerOfMap - houseCenter;
return atan2(toCenter.y, toCenter.x);
}
Color _getHouseColor() {
switch (houseType) {
case 0:
return isTarget
? const Color(0xFFFF6B6B)
: const Color(0xFF8B4513); // Brown/Red if target
case 1:
return isTarget
? const Color(0xFFFF6B6B)
: const Color(0xFF4682B4); // Blue/Red if target
case 2:
return isTarget
? const Color(0xFFFF6B6B)
: const Color(0xFF228B22); // Green/Red if target
default:
return const Color(0xFF696969);
}
}
@override
void render(Canvas canvas) {
super.render(canvas);
// Draw door
final doorPaint = Paint()..color = const Color(0xFF654321);
canvas.drawRect(
Rect.fromLTWH(size.x / 2 - 8, size.y - 4, 16, 4),
doorPaint,
);
// Draw windows
final windowPaint =
Paint()
..color =
hasLights ? const Color(0xFFFFFF00) : const Color(0xFF87CEEB);
// Left window
canvas.drawRect(
Rect.fromLTWH(size.x * 0.2, size.y * 0.3, 12, 12),
windowPaint,
);
// Right window
canvas.drawRect(
Rect.fromLTWH(size.x * 0.7, size.y * 0.3, 12, 12),
windowPaint,
);
// Draw security features
if (hasSecurityCamera) {
final cameraPaint = Paint()..color = const Color(0xFF000000);
canvas.drawCircle(Offset(size.x * 0.9, size.y * 0.1), 4, cameraPaint);
}
if (hasWatchDog) {
// Draw dog house in yard
final dogHousePaint = Paint()..color = const Color(0xFF8B4513);
canvas.drawRect(Rect.fromLTWH(-20, size.y + 10, 15, 15), dogHousePaint);
}
// Draw detection radius if setting is enabled
try {
if (game.appSettings.getBool('game.show_detection_radius')) {
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),
getDetectionRadius(),
radiusPaint,
);
}
} catch (e) {
// Settings not ready, skip rendering
}
// Draw target indicator
if (isTarget) {
final targetPaint =
Paint()
..color = const Color(0xFFFF0000)
..style = PaintingStyle.stroke
..strokeWidth = 3.0;
canvas.drawCircle(
Offset(size.x / 2, size.y / 2),
size.x / 2 + 10,
targetPaint,
);
}
}
double getDetectionRadius() {
double radius = 30.0; // Reduced base radius
if (hasLights) radius += 10.0; // Reduced light bonus
if (hasSecurityCamera) radius += 20.0; // Reduced camera bonus
if (hasWatchDog) radius += 15.0; // Reduced dog bonus
return radius;
}
bool canDetectPlayer(Vector2 playerPosition, double playerStealthLevel) {
// Basic radius detection
final distance = (playerPosition - yardCenter!).length;
final detectionRadius = getDetectionRadius() * (1.0 - playerStealthLevel);
bool radiusDetection = distance < detectionRadius;
// Vision cone detection for security cameras
bool visionDetection = false;
if (hasSecurityCamera && visionCone != null) {
visionDetection =
visionCone!.canSee(playerPosition) &&
visionCone!.hasLineOfSight(playerPosition, []);
}
return radiusDetection || visionDetection;
}
@override
void update(double dt) {
super.update(dt);
// Update vision cone visibility based on settings
if (visionCone != null) {
try {
final showVisionCones = game.appSettings.getBool(
'game.show_vision_cones',
);
visionCone!.updateOpacity(showVisionCones ? 0.3 : 0.0);
} catch (e) {
visionCone!.updateOpacity(0.0); // Hide if settings not ready
}
}
}
}