Files
llm_chat/lib/ecs/system.dart

389 lines
10 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:collection';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:maplibre/maplibre.dart';
import 'package:maplibre_gl/maplibre_gl.dart' as gl;
import '../screens/map_screen.dart';
import 'entity.dart';
import 'component.dart';
/// 系统基类 - 用于处理特定类型的组件
abstract class System {
void update(List<Entity> entities, Duration deltaTime);
}
/// 地图系统 - 处理地图相关的实体和组件
class MapSystem implements System {
gl.MapLibreMapController? mapController;
MapUiBodyState? mapUiBodyState;
final List<String> _plotIds = [];
final List<String> _trailIds = [];
final List<String> _iconIds = [];
// 单例实例
static MapSystem? _instance;
// 工厂构造函数,实现单例
factory MapSystem({gl.MapLibreMapController? mapController, MapUiBodyState? mapUiBodyState}) {
_instance ??= MapSystem._internal(mapController: mapController, mapUiBodyState: mapUiBodyState);
if (mapController != null) _instance!.mapController = mapController;
if (mapUiBodyState != null) _instance!.mapUiBodyState = mapUiBodyState;
return _instance!;
}
// 私有构造函数
MapSystem._internal({this.mapController, this.mapUiBodyState});
/// 获取单例实例
static MapSystem get instance {
_instance ??= MapSystem._internal();
return _instance!;
}
@override
void update(List<Entity> entities, Duration deltaTime) {
// 更新地图上的标绘
for (var entity in entities) {
if (entity.hasComponent<PlotComponent>()) {
_updatePlot(entity.getComponent<PlotComponent>()!);
}
if (entity.hasComponent<IconComponent>()) {
_updateIcon(entity.getComponent<IconComponent>()!);
}
if (entity.hasComponent<TrailComponent>()) {
_updateTrail(entity.getComponent<TrailComponent>()!);
}
if (entity.hasComponent<MovementComponent>()) {
_updateMovement(entity);
}
}
}
void _updatePlot(PlotComponent plot) {
// 实现标绘更新逻辑
// 这里可以根据plotType绘制不同类型的图形
if (plot.coordinates.length >= 2) {
// 示例:绘制线段
// mapController?.addLine() // 这里需要根据实际API实现
}
}
void _updateIcon(IconComponent icon) {
// 实现图标更新逻辑
// mapController?.addMarker() // 这里需要根据实际API实现
}
void _updateTrail(TrailComponent trail) {
// 实现拖尾更新逻辑
// 绘制轨迹线
}
void _updateMovement(Entity entity) {
var movement = entity.getComponent<MovementComponent>();
var plot = entity.getComponent<PlotComponent>();
var icon = entity.getComponent<IconComponent>();
if (movement != null && (plot != null || icon != null)) {
if (movement.target != null) {
// 简单的移动逻辑 - 向目标点移动
double dx = movement.target!.longitude - movement.position.longitude;
double dy = movement.target!.latitude - movement.position.latitude;
double distance = sqrt(dx * dx + dy * dy);
if (distance > 0.0001) { // 如果距离目标足够近就停止
double ratio = movement.speed * 0.0001 / distance;
movement.position = gl.LatLng(
movement.position.latitude + dy * ratio,
movement.position.longitude + dx * ratio,
);
// 更新图标位置
if (icon != null) {
icon.position = movement.position;
}
// 如果有拖尾组件,添加新点
var trail = entity.getComponent<TrailComponent>();
if (trail != null) {
trail.addPoint(movement.position);
}
} else {
movement.target = null; // 到达目标
}
}
}
}
// ==================== 便捷方法:通过 mapUiBodyState 调用地图接口 ====================
/// 添加自定义图片标记
void addCustomMarker(Geographic position, {Map<String, dynamic>? properties}) {
mapUiBodyState?.addCustomMarker(position, properties: properties);
}
/// 添加圆形
void addCircle(
Geographic position, {
double radius = 20,
Color color = Colors.orange,
Color strokeColor = Colors.red,
double strokeWidth = 2,
}) {
mapUiBodyState?.addCircle(
position,
radius: radius,
color: color,
strokeWidth: strokeWidth,
);
}
/// 添加扇形
/// [center] 扇形中心的地理位置
/// [radius] 扇形的半径(单位:米)
/// [startAngle] 起始角度单位0度表示正东方向
/// [endAngle] 结束角度(单位:度)
/// [segments] 扇形的分段数,值越大越平滑
/// [color] 填充颜色
/// [outlineColor] 边框颜色
void addSector(
Geographic center, {
required double radius,
required double startAngle,
required double endAngle,
int segments = 36,
Color color = Colors.lightBlueAccent,
Color outlineColor = Colors.blue,
}) {
mapUiBodyState?.addSector(
center,
radius: radius,
startAngle: startAngle,
endAngle: endAngle,
segments: segments,
color: color,
outlineColor: outlineColor,
);
}
/// 添加长方形
/// [center] 长方形中心的地理位置
/// [width] 长方形的宽度(单位:米)
/// [height] 长方形的高度(单位:米)
/// [color] 填充颜色
/// [outlineColor] 边框颜色
void addRectangle(
Geographic center, {
required double width,
required double height,
Color color = Colors.lightBlueAccent,
Color outlineColor = Colors.blue,
}) {
mapUiBodyState?.addRectangle(
center,
width: width,
height: height,
color: color,
outlineColor: outlineColor,
);
}
/// 清除所有自定义标记
void clearCustomMarkers() {
mapUiBodyState?.clearCustomMarkers();
}
/// 清除所有圆形
void clearCircles() {
mapUiBodyState?.clearCircles();
}
/// 清除所有多边形(包括扇形和长方形)
void clearPolygons() {
mapUiBodyState?.clearPolygons();
}
/// 清除所有自定义图层
void clearAllCustomLayers() {
mapUiBodyState?.clearAllCustomLayers();
}
/// 添加固定大小的圆形(不随地图缩放)
void addFixedCircle(
Geographic position, {
double radius = 20,
Color color = Colors.orange,
Color strokeColor = Colors.red,
double strokeWidth = 2,
}) {
mapUiBodyState?.addFixedCircle(
position,
radius: radius,
color: color,
outlineColor: strokeColor,
);
}
}
/// 音频系统 - 处理音频相关的实体和组件
class AudioSystem implements System {
@override
void update(List<Entity> entities, Duration deltaTime) {
for (var entity in entities) {
if (entity.hasComponent<AudioComponent>()) {
var audioComponent = entity.getComponent<AudioComponent>()!;
_playAudio(audioComponent);
}
}
}
void _playAudio(AudioComponent audio) {
// 实现音频播放逻辑
// 这里可以使用Flutter的音频插件如audioplayers
print("Playing audio: ${audio.audioPath}");
}
}
/// 组件系统 - 管理各种组件的交互
class ComponentSystem implements System {
@override
void update(List<Entity> entities, Duration deltaTime) {
// 处理组件间的交互
for (var entity in entities) {
// 可以根据需要实现组件交互逻辑
if (entity.hasComponent<PlotComponent>() && entity.hasComponent<IconComponent>()) {
// 当一个实体同时有标绘和图标组件时的特殊处理
}
}
}
}
/// ECS管理器 - 管理实体、系统和整个ECS框架
class ECSManager {
static ECSManager? _instance;
factory ECSManager() {
_instance ??= ECSManager._internal();
return _instance!;
}
ECSManager._internal();
/// 获取单例实例
static ECSManager get instance {
_instance ??= ECSManager._internal();
return _instance!;
}
final List<Entity> _entities = [];
final List<System> _systems = [];
final Queue<Entity> _entitiesToAdd = Queue<Entity>();
final Queue<Entity> _entitiesToRemove = Queue<Entity>();
void addEntity(Entity entity) {
_entitiesToAdd.add(entity);
}
void removeEntity(Entity entity) {
_entitiesToRemove.add(entity);
}
void addSystem(System system) {
_systems.add(system);
}
void removeSystem(System system) {
_systems.remove(system);
}
void update(Duration deltaTime) {
// 添加新实体
while (_entitiesToAdd.isNotEmpty) {
_entities.add(_entitiesToAdd.removeFirst());
}
// 更新所有系统
for (var system in _systems) {
system.update(_entities, deltaTime);
}
// 移除实体
while (_entitiesToRemove.isNotEmpty) {
var entity = _entitiesToRemove.removeFirst();
_entities.remove(entity);
}
}
List<Entity> get entities => _entities;
/// 工厂方法:创建一个带位置的实体
Entity createEntityAtPosition({
required String name,
required gl.LatLng position,
String? plotType,
Color plotColor = Colors.red,
double strokeWidth = 2.0,
String? iconPath,
double iconSize = 30.0,
bool hasTrail = false,
Color trailColor = Colors.blue,
double trailMaxLength = 20.0,
bool hasMovement = false,
gl.LatLng? movementTarget,
double movementSpeed = 1.0,
String? audioPath,
bool audioLoop = false,
double audioVolume = 1.0,
}) {
// 创建实体
final entity = Entity(name: name);
// 添加位置相关的组件
if (plotType != null) {
entity.addComponent(PlotComponent(
plotType: plotType,
coordinates: [position],
color: plotColor,
strokeWidth: strokeWidth,
));
}
if (iconPath != null) {
entity.addComponent(IconComponent(
iconPath: iconPath,
position: position,
size: iconSize,
));
}
if (hasTrail) {
entity.addComponent(TrailComponent(
trailColor: trailColor,
maxLength: trailMaxLength,
));
}
if (hasMovement) {
entity.addComponent(MovementComponent(
position: position,
target: movementTarget,
speed: movementSpeed,
));
}
if (audioPath != null) {
entity.addComponent(AudioComponent(
audioPath: audioPath,
loop: audioLoop,
volume: audioVolume,
));
}
// 添加到管理器
addEntity(entity);
return entity;
}
}