shitman/lib/game/shitman_game.dart
zeyus f7a08a5099
All checks were successful
/ build-web (push) Successful in 3m24s
Added touch controls.
2025-08-04 11:50:47 +02:00

225 lines
5.9 KiB
Dart

import 'package:flame/game.dart';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:shitman/game/components/player.dart';
import 'package:shitman/game/levels/operation_shitstorm.dart';
import 'package:shitman/game/shitman_world.dart';
import 'package:shitman/ui/touch_controls.dart';
import 'package:shitman/settings/app_settings.dart';
/// Shitman Game
/// A 2D top-down "hitman" style game, but instead of assassinating people,
/// your objective is to place flaming bags of dog poop on the doorsteps of
/// your targets without getting caught.
enum GameState { mainMenu, playing, paused, gameOver, missionComplete }
class ShitmanGame extends FlameGame
with HasKeyboardHandlerComponents, HasCollisionDetection, AppSettings {
late Player player;
late OperationShitstorm currentLevel;
late CameraComponent gameCamera;
GameState gameState = GameState.mainMenu;
int missionScore = 0;
int totalMissions = 0;
bool infiniteMode = false;
@override
Future<void> onLoad() async {
await super.onLoad();
await initSettings();
world = ShitmanWorld();
// Setup camera
gameCamera = CameraComponent.withFixedResolution(
world: world,
width: 800,
height: 600,
);
camera = gameCamera;
addAll([world]);
// Initialize debug mode from settings
try {
debugMode = appSettings.getBool('game.debug_mode');
} catch (e) {
debugMode = false; // Fallback if settings not ready
}
}
void _initializeTouchControls() {
try {
final touchControlsEnabled = appSettings.getBool('ui.touch_enabled');
if (touchControlsEnabled) {
overlays.add('TouchControls');
}
} catch (e) {
// If setting doesn't exist, auto-detect based on platform
if (TouchDetection.isTouchDevice) {
// Enable touch controls by default on touch devices
try {
appSettings.setBool('ui.touch_enabled', true);
overlays.add('TouchControls');
} catch (e) {
// Settings not ready, just add overlay
overlays.add('TouchControls');
}
}
}
}
Future<void> startGame() async {
gameState = GameState.playing;
await initializeLevel();
// Initialize touch controls when game starts
_initializeTouchControls();
}
Future<void> startInfiniteMode() async {
infiniteMode = true;
overlays.remove('MainMenu');
overlays.add('InGameUI');
await startGame();
}
void stopGame() {
gameState = GameState.mainMenu;
world.removeAll(world.children);
missionScore = 0;
// Remove touch controls when stopping game
overlays.remove('TouchControls');
}
void pauseGame() {
gameState = GameState.paused;
// Keep touch controls visible during pause for consistency
}
void resumeGame() {
gameState = GameState.playing;
// Touch controls remain visible
}
Future<void> initializeLevel() async {
// Clear previous level
world.removeAll(world.children);
// Create the Operation Shitstorm level
currentLevel = OperationShitstorm();
// Add and wait for the level to load
await world.add(currentLevel);
// Start the level
await currentLevel.startLevel();
// Get the player from the level
player = currentLevel.player;
// Setup camera to follow player
gameCamera.follow(player);
}
void completeCurrentMission() {
gameState = GameState.missionComplete;
missionScore += 100;
totalMissions++;
if (infiniteMode) {
// Generate new mission after delay, but keep allowing input
Future.delayed(Duration(seconds: 2), () {
currentLevel.selectRandomTarget();
gameState = GameState.playing;
});
}
}
void failMission() {
gameState = GameState.gameOver;
// TODO: Show game over screen
}
@override
KeyEventResult onKeyEvent(
KeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
super.onKeyEvent(event, keysPressed);
if (gameState != GameState.playing &&
gameState != GameState.missionComplete &&
gameState != GameState.gameOver) {
return KeyEventResult.ignored;
}
// Handle pause
if (keysPressed.contains(LogicalKeyboardKey.escape)) {
pauseGame();
overlays.add('PauseMenu');
return KeyEventResult.handled;
}
// Handle player input
player.handleInput(keysPressed);
// Handle action keys on key down
if (event is KeyDownEvent) {
player.handleAction(event.logicalKey);
}
// Mission completion is now handled by the player's escape sequence
// No automatic completion when near target
return KeyEventResult.handled;
}
/// Handle touch movement from virtual joystick
void handleTouchMovement(Vector2 input) {
if (gameState == GameState.playing) {
player.handleTouchMovement(input);
}
}
/// Handle poop bag action from touch
void handleTouchPoopBag() {
if (gameState == GameState.playing) {
player.handleTouchPoopBag();
}
}
/// Handle doorbell action from touch
void handleTouchDoorbell() {
if (gameState == GameState.playing) {
player.handleTouchDoorbell();
}
}
/// Toggle touch controls on/off
void toggleTouchControls(bool enabled) {
try {
appSettings.setBool('ui.touch_enabled', enabled);
if (enabled && (gameState == GameState.playing || gameState == GameState.paused || gameState == GameState.missionComplete || gameState == GameState.gameOver)) {
// Only show touch controls during actual gameplay states
overlays.add('TouchControls');
} else {
overlays.remove('TouchControls');
}
} catch (e) {
// Handle settings error
}
}
@override
void update(double dt) {
super.update(dt);
// Only update game logic when playing
if (gameState != GameState.playing) return;
// Game-specific update logic here
}
}