Skip to content

Commit

Permalink
Add zoom
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Sep 18, 2024
1 parent b532b6b commit 080a6ed
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 26 deletions.
9 changes: 9 additions & 0 deletions app/lib/bloc/world/bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ class WorldBloc extends Bloc<PlayableWorldEvent, ClientWorldState> {
on<DrawerViewChanged>((event, emit) {
emit(state.copyWith(drawerView: event.view));
});
on<ZoomChanged>((event, emit) {
var zoom = event.zoom;
if (zoom != null) {
zoom += state.zoom;
zoom = zoom.clamp(0.5, 2.0);
}
zoom ??= 1;
emit(state.copyWith(zoom: zoom));
});
}

Future<void> save() async {
Expand Down
8 changes: 8 additions & 0 deletions app/lib/bloc/world/local.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ final class DrawerViewChanged extends LocalWorldEvent

DrawerViewChanged(this.view);
}

@MappableClass()
final class ZoomChanged extends LocalWorldEvent with ZoomChangedMappable {
final double? zoom;

ZoomChanged(this.zoom);
ZoomChanged.reset() : zoom = null;
}
112 changes: 112 additions & 0 deletions app/lib/bloc/world/local.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -727,3 +727,115 @@ class _DrawerViewChangedCopyWithImpl<$R, $Out>
Then<$Out2, $R2> t) =>
_DrawerViewChangedCopyWithImpl($value, $cast, t);
}

class ZoomChangedMapper extends SubClassMapperBase<ZoomChanged> {
ZoomChangedMapper._();

static ZoomChangedMapper? _instance;
static ZoomChangedMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = ZoomChangedMapper._());
LocalWorldEventMapper.ensureInitialized().addSubMapper(_instance!);
}
return _instance!;
}

@override
final String id = 'ZoomChanged';

static double? _$zoom(ZoomChanged v) => v.zoom;
static const Field<ZoomChanged, double> _f$zoom = Field('zoom', _$zoom);

@override
final MappableFields<ZoomChanged> fields = const {
#zoom: _f$zoom,
};

@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'ZoomChanged';
@override
late final ClassMapperBase superMapper =
LocalWorldEventMapper.ensureInitialized();

static ZoomChanged _instantiate(DecodingData data) {
return ZoomChanged(data.dec(_f$zoom));
}

@override
final Function instantiate = _instantiate;

static ZoomChanged fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<ZoomChanged>(map);
}

static ZoomChanged fromJson(String json) {
return ensureInitialized().decodeJson<ZoomChanged>(json);
}
}

mixin ZoomChangedMappable {
String toJson() {
return ZoomChangedMapper.ensureInitialized()
.encodeJson<ZoomChanged>(this as ZoomChanged);
}

Map<String, dynamic> toMap() {
return ZoomChangedMapper.ensureInitialized()
.encodeMap<ZoomChanged>(this as ZoomChanged);
}

ZoomChangedCopyWith<ZoomChanged, ZoomChanged, ZoomChanged> get copyWith =>
_ZoomChangedCopyWithImpl(this as ZoomChanged, $identity, $identity);
@override
String toString() {
return ZoomChangedMapper.ensureInitialized()
.stringifyValue(this as ZoomChanged);
}

@override
bool operator ==(Object other) {
return ZoomChangedMapper.ensureInitialized()
.equalsValue(this as ZoomChanged, other);
}

@override
int get hashCode {
return ZoomChangedMapper.ensureInitialized().hashValue(this as ZoomChanged);
}
}

extension ZoomChangedValueCopy<$R, $Out>
on ObjectCopyWith<$R, ZoomChanged, $Out> {
ZoomChangedCopyWith<$R, ZoomChanged, $Out> get $asZoomChanged =>
$base.as((v, t, t2) => _ZoomChangedCopyWithImpl(v, t, t2));
}

abstract class ZoomChangedCopyWith<$R, $In extends ZoomChanged, $Out>
implements LocalWorldEventCopyWith<$R, $In, $Out> {
@override
$R call({double? zoom});
ZoomChangedCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}

class _ZoomChangedCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ZoomChanged, $Out>
implements ZoomChangedCopyWith<$R, ZoomChanged, $Out> {
_ZoomChangedCopyWithImpl(super.value, super.then, super.then2);

@override
late final ClassMapperBase<ZoomChanged> $mapper =
ZoomChangedMapper.ensureInitialized();
@override
$R call({Object? zoom = $none}) =>
$apply(FieldCopyWithData({if (zoom != $none) #zoom: zoom}));
@override
ZoomChanged $make(CopyWithData data) =>
ZoomChanged(data.get(#zoom, or: $value.zoom));

@override
ZoomChangedCopyWith<$R2, ZoomChanged, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_ZoomChangedCopyWithImpl($value, $cast, t);
}
2 changes: 2 additions & 0 deletions app/lib/bloc/world/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ final class ClientWorldState extends WorldState with ClientWorldStateMappable {
final ItemLocation? selectedDeck;
final bool showHand, switchCellOnMove;
final DrawerView drawerView;
final double zoom;

const ClientWorldState({
required this.multiplayer,
Expand All @@ -48,6 +49,7 @@ final class ClientWorldState extends WorldState with ClientWorldStateMappable {
super.messages,
required super.data,
this.drawerView = DrawerView.chat,
this.zoom = 1.0,
});

QuokkaFileSystem get fileSystem => assetManager.fileSystem;
Expand Down
19 changes: 14 additions & 5 deletions app/lib/bloc/world/state.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ class ClientWorldStateMapper extends ClassMapperBase<ClientWorldState> {
static DrawerView _$drawerView(ClientWorldState v) => v.drawerView;
static const Field<ClientWorldState, DrawerView> _f$drawerView =
Field('drawerView', _$drawerView, opt: true, def: DrawerView.chat);
static double _$zoom(ClientWorldState v) => v.zoom;
static const Field<ClientWorldState, double> _f$zoom =
Field('zoom', _$zoom, opt: true, def: 1.0);

@override
final MappableFields<ClientWorldState> fields = const {
Expand All @@ -192,6 +195,7 @@ class ClientWorldStateMapper extends ClassMapperBase<ClientWorldState> {
#messages: _f$messages,
#data: _f$data,
#drawerView: _f$drawerView,
#zoom: _f$zoom,
};

static ClientWorldState _instantiate(DecodingData data) {
Expand All @@ -212,7 +216,8 @@ class ClientWorldStateMapper extends ClassMapperBase<ClientWorldState> {
teamMembers: data.dec(_f$teamMembers),
messages: data.dec(_f$messages),
data: data.dec(_f$data),
drawerView: data.dec(_f$drawerView));
drawerView: data.dec(_f$drawerView),
zoom: data.dec(_f$zoom));
}

@override
Expand Down Expand Up @@ -302,7 +307,8 @@ abstract class ClientWorldStateCopyWith<$R, $In extends ClientWorldState, $Out>
Map<String, Set<int>>? teamMembers,
List<ChatMessage>? messages,
QuokkaData? data,
DrawerView? drawerView});
DrawerView? drawerView,
double? zoom});
ClientWorldStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
Expand Down Expand Up @@ -360,7 +366,8 @@ class _ClientWorldStateCopyWithImpl<$R, $Out>
Map<String, Set<int>>? teamMembers,
List<ChatMessage>? messages,
QuokkaData? data,
DrawerView? drawerView}) =>
DrawerView? drawerView,
double? zoom}) =>
$apply(FieldCopyWithData({
if (multiplayer != null) #multiplayer: multiplayer,
if (colorScheme != null) #colorScheme: colorScheme,
Expand All @@ -378,7 +385,8 @@ class _ClientWorldStateCopyWithImpl<$R, $Out>
if (teamMembers != null) #teamMembers: teamMembers,
if (messages != null) #messages: messages,
if (data != null) #data: data,
if (drawerView != null) #drawerView: drawerView
if (drawerView != null) #drawerView: drawerView,
if (zoom != null) #zoom: zoom
}));
@override
ClientWorldState $make(CopyWithData data) => ClientWorldState(
Expand All @@ -399,7 +407,8 @@ class _ClientWorldStateCopyWithImpl<$R, $Out>
teamMembers: data.get(#teamMembers, or: $value.teamMembers),
messages: data.get(#messages, or: $value.messages),
data: data.get(#data, or: $value.data),
drawerView: data.get(#drawerView, or: $value.drawerView));
drawerView: data.get(#drawerView, or: $value.drawerView),
zoom: data.get(#zoom, or: $value.zoom));

@override
ClientWorldStateCopyWith<$R2, ClientWorldState, $Out2> $chain<$R2, $Out2>(
Expand Down
2 changes: 1 addition & 1 deletion app/lib/board/cell.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class GameCell extends PositionComponent
}

VectorDefinition toDefinition() =>
(position.clone()..divide(grid.cellSize)).toDefinition();
(position.clone()..divide(grid.cellSizeWithZoom)).toDefinition();

GlobalVectorDefinition toGlobalDefinition(ClientWorldState state) =>
GlobalVectorDefinition.fromLocal(state.tableName, toDefinition());
Expand Down
57 changes: 42 additions & 15 deletions app/lib/board/grid.dart
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:quokka/bloc/world/bloc.dart';
import 'package:quokka/bloc/world/state.dart';
import 'package:quokka/board/cell.dart';

class BoardGrid extends PositionComponent with HasGameRef {
class BoardGrid extends PositionComponent
with HasGameRef, FlameBlocListenable<WorldBloc, ClientWorldState> {
final Vector2 cellSize;
static const _padding = 3.0;
Rect? _lastViewport;
double _zoom = 1.0;

BoardGrid({
required this.cellSize,
});

Rect get viewport {
final Rect viewport = game.camera.visibleWorldRect;
final currentSize = cellSizeWithZoom;
return Rect.fromLTRB(
(viewport.left / cellSize.x - _padding).floor() * cellSize.x,
(viewport.top / cellSize.y - _padding).floor() * cellSize.y,
(viewport.right / cellSize.x + _padding).ceil() * cellSize.x,
(viewport.bottom / cellSize.y + _padding).ceil() * cellSize.y,
(viewport.left / currentSize.x - _padding).floor() * currentSize.x,
(viewport.top / currentSize.y - _padding).floor() * currentSize.y,
(viewport.right / currentSize.x + _padding).ceil() * currentSize.x,
(viewport.bottom / currentSize.y + _padding).ceil() * currentSize.y,
);
}

Expand All @@ -32,6 +38,7 @@ class BoardGrid extends PositionComponent with HasGameRef {
void _updateGrid() {
if (!shouldReset()) return;
final viewport = this.viewport;
final currentSize = cellSizeWithZoom;
// Remove components that are out of the viewport
removeAll(children.where((element) {
if (element is! PositionComponent) return false;
Expand All @@ -41,38 +48,40 @@ class BoardGrid extends PositionComponent with HasGameRef {
final last = _lastViewport ?? Rect.zero;
// Add components that are in the viewport
// Top and bottom
for (var x = viewport.left; x < viewport.right; x += cellSize.x) {
for (var y = viewport.top; y < last.top; y += cellSize.y) {
for (var x = viewport.left; x < viewport.right; x += currentSize.x) {
for (var y = viewport.top; y < last.top; y += currentSize.y) {
add(_createCell(
position: Vector2(x, y),
size: cellSize,
size: currentSize,
));
}
for (var y = last.bottom; y < viewport.bottom; y += cellSize.y) {
for (var y = last.bottom; y < viewport.bottom; y += currentSize.y) {
add(_createCell(
position: Vector2(x, y),
size: cellSize,
size: currentSize,
));
}
}
// Left and right
for (var y = last.top; y < last.bottom; y += cellSize.y) {
for (var x = viewport.left; x < last.left; x += cellSize.x) {
for (var y = last.top; y < last.bottom; y += currentSize.y) {
for (var x = viewport.left; x < last.left; x += currentSize.x) {
add(_createCell(
position: Vector2(x, y),
size: cellSize,
size: currentSize,
));
}
for (var x = last.right; x < viewport.right; x += cellSize.x) {
for (var x = last.right; x < viewport.right; x += currentSize.x) {
add(_createCell(
position: Vector2(x, y),
size: cellSize,
size: currentSize,
));
}
}
_lastViewport = viewport;
}

Vector2 get cellSizeWithZoom => cellSize * _zoom;

@override
void update(double dt) {
super.update(dt);
Expand All @@ -90,4 +99,22 @@ class BoardGrid extends PositionComponent with HasGameRef {
position: position,
size: size,
);

@override
void onInitialState(ClientWorldState state) {
_zoom = state.zoom;
}

@override
bool listenWhen(ClientWorldState previousState, ClientWorldState newState) =>
previousState.zoom != newState.zoom;

@override
void onNewState(ClientWorldState state) {
if (_zoom != state.zoom) {
_zoom = state.zoom;
_lastViewport = null;
removeAll(children);
}
}
}
2 changes: 1 addition & 1 deletion app/lib/helpers/vector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:flame/components.dart';
import 'package:quokka_api/quokka_api.dart';

extension VectorToDefinition on Vector2 {
VectorDefinition toDefinition() => VectorDefinition(x.toInt(), y.toInt());
VectorDefinition toDefinition() => VectorDefinition(x.round(), y.round());
}

extension DefinitionToVector on VectorDefinition {
Expand Down
6 changes: 5 additions & 1 deletion app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,9 @@
"highContrast": "High contrast",
"noServers": "There are no servers available",
"expand": "Expand",
"collapse": "Collapse"
"collapse": "Collapse",
"zoom": "Zoom",
"zoomIn": "Zoom in",
"zoomOut": "Zoom out",
"resetZoom": "Reset zoom"
}
Loading

0 comments on commit 080a6ed

Please sign in to comment.