diff --git a/lib/characters/character.dart b/lib/characters/character.dart index bc68037..00b20bd 100644 --- a/lib/characters/character.dart +++ b/lib/characters/character.dart @@ -3,6 +3,14 @@ import 'package:flame/components.dart'; import 'package:pacman/game.dart'; +enum Direction { + left, + right, + up, + down, + idle, +} + class Character extends SpriteAnimationComponent with HasGameRef { @@ -17,14 +25,11 @@ class Character extends SpriteAnimationComponent with HasGameRef { ); Vector2 velocity = Vector2.zero(); - double _moveSpeed = 100.0; + double moveSpeed = 100.0; + Direction direction = Direction.idle; - set setMoveSpeed(double speed) { - _moveSpeed = speed; - } - get moveSpeed => _moveSpeed; } diff --git a/lib/characters/enemy.dart b/lib/characters/enemy.dart index 96fa77e..788fa06 100644 --- a/lib/characters/enemy.dart +++ b/lib/characters/enemy.dart @@ -12,7 +12,7 @@ class Enemy extends Character { Enemy() { - setMoveSpeed = enemySpeed; + moveSpeed = enemySpeed; } diff --git a/lib/characters/player.dart b/lib/characters/player.dart index 38a51a1..1c9fe3f 100644 --- a/lib/characters/player.dart +++ b/lib/characters/player.dart @@ -4,23 +4,18 @@ import 'package:flame/components.dart'; import 'package:flame/palette.dart'; import 'package:flutter/services.dart'; import 'package:pacman/core/constants.dart'; +import 'package:pacman/level/map.dart'; import 'character.dart'; -class Player extends Character with KeyboardHandler { - - - Player() { - setMoveSpeed = playerSpeed; - } - +class Player extends Character with KeyboardHandler, CollisionCallbacks { @override FutureOr onLoad() async { super.onLoad(); - debugMode = true; + moveSpeed = playerSpeed; animation = SpriteAnimation.fromFrameData( game.images.fromCache('ember.png'), @@ -45,18 +40,114 @@ class Player extends Character with KeyboardHandler { } - LogicalKeyboardKey? lastPressedKey; + + + @override + void update(double dt) { + position += velocity * dt; + keepMoving(dt); + super.update(dt); + } @override bool onKeyEvent(RawKeyEvent event, Set keysPressed) { if (event is RawKeyDownEvent) { - lastPressedKey = event.logicalKey; + switch(event.logicalKey) { + case LogicalKeyboardKey.arrowUp || LogicalKeyboardKey.keyW: + direction = Direction.up; + break; + case LogicalKeyboardKey.arrowDown || LogicalKeyboardKey.keyS: + direction = Direction.down; + break; + case LogicalKeyboardKey.arrowLeft || LogicalKeyboardKey.keyA: + direction = Direction.left; + break; + case LogicalKeyboardKey.arrowRight || LogicalKeyboardKey.keyD: + direction = Direction.right; + break; + default: + direction = Direction.idle; + break; + } } return false; } + bool canMoveInDirection(Direction direction) { + return true; + int nextX = position.x ~/ tileSize; + int nextY = position.y ~/ tileSize; + final map = Level.map; + + switch (direction) { + case Direction.left: + nextX -= 1; + break; + case Direction.right: + nextX += 1; + break; + case Direction.up: + nextY -= 1; + break; + case Direction.down: + nextY += 1; + break; + default: + return false; // Неверное направление + } + + // Проверка находится ли следующая клетка внутри карты и не является ли стеной + if (nextX < 0 || nextX >= map[0].length || nextY < 0 || nextY >= map.length || map[nextY][nextX] == '#') { + return false; + } + + return true; + } + + + void keepMoving(double dt) { + + switch (direction) { + case Direction.left: + if (canMoveInDirection(Direction.left)) { + velocity = Vector2(-moveSpeed, 0); + } + else { + velocity = Vector2.zero(); + } + break; + case Direction.right: + if (canMoveInDirection(Direction.right)) { + velocity = Vector2(moveSpeed, 0); + } + else { + velocity = Vector2.zero(); + } + break; + case Direction.up: + if (canMoveInDirection(Direction.up)) { + velocity = Vector2(0, -moveSpeed); + } + else { + velocity = Vector2.zero(); + } + break; + case Direction.down: + if (canMoveInDirection(Direction.down)) { + velocity = Vector2(0, moveSpeed); + } + else { + velocity = Vector2.zero(); + } + break; + case Direction.idle: + velocity = Vector2.zero(); + break; + } + + } } diff --git a/lib/components/my_component.dart b/lib/components/my_component.dart deleted file mode 100644 index 015ce67..0000000 --- a/lib/components/my_component.dart +++ /dev/null @@ -1,269 +0,0 @@ - - -import 'dart:async'; - -import 'package:flame/collisions.dart'; -import 'package:flame/components.dart'; -import 'package:flame/geometry.dart'; -import 'package:flutter/material.dart'; -import 'package:pacman/core/extensions/extensions.dart'; -import 'package:pacman/core/mixins/internal_checker.dart'; -import 'package:pacman/core/mixins/sensor.dart'; -import 'package:pacman/game.dart'; - -abstract class MyComponent extends PositionComponent with HasGameRef, HasPaint, CollisionCallbacks, InternalChecker { - final String _keyIntervalCheckIsVisible = "CHECK_VISIBLE"; - final int _intervalCheckIsVisible = 100; - Map? properties; - - /// When true this component render above all components in game. - bool renderAboveComponents = false; - - /// Param checks if this component is visible on the screen - bool _isVisibleInScreen = false; - - bool get isVisible => _visible ? _isVisibleInScreen : false; - set isVisible(bool visible) { - _visible = visible; - } - - /// Param used to enable or disable the render. - bool _visible = true; - - bool enabledCheckIsVisible = true; - // - // / Get BuildContext - // BuildContext get context => gameRef.context; - - double lastAngle = 0; - - @override - set angle(double a) { - lastAngle = super.angle; - super.angle = a; - } - - Rect? _rectCollision; - - // @override - // int get priority { - // if (renderAboveComponents && hasGameRef) { - // return LayerPriority.getAbovePriority(gameRef.highestPriority); - // } - // return LayerPriority.getComponentPriority(rectCollision.bottom.floor()); - // } - - @override - @mustCallSuper - void update(double dt) { - super.update(dt); - _checkIsVisible(dt); - } - - void _checkIsVisible(double dt) { - // if (!enabledCheckIsVisible) return; - // if (checkInterval( - // _keyIntervalCheckIsVisible, - // _intervalCheckIsVisible, - // dt, - // )) { - // _onSetIfVisible(); - // } - } - - /// Return screen position of this component. - Vector2 screenPosition() { - // if (hasGameRef) { - // return gameRef.worldToScreen( - // position, - // ); - // } - return Vector2.zero(); - } - - /// Method that checks if this component is visible on the screen - // @mustCallSuper - // bool isVisibleInCamera() { - // return hasGameRef ? gameRef.isVisibleInCamera(this) : false; - // } - - // @override - // @mustCallSuper - // void onRemove() { - // (gameRef as BonfireGame).removeVisible(this); - // super.onRemove(); - // } - - // void _onSetIfVisible() { - // if (!_visible) return; - // bool nowIsVisible = isVisibleInCamera(); - // if (isHud) { - // nowIsVisible = true; - // enabledCheckIsVisible = false; - // } - // if (nowIsVisible && !isVisible) { - // (gameRef as BonfireGame).addVisible(this); - // } - // if (!nowIsVisible && isVisible) { - // (gameRef as BonfireGame).removeVisible(this); - // } - // _isVisibleInScreen = nowIsVisible; - // } - - @override - Future addAll(Iterable components) { - components.forEach(_confHitBoxRender); - return addAll(components); - } - - @override - FutureOr add(Component component) async { - _confHitBoxRender(component); - if (component is ShapeHitbox) { - _rectCollision = null; - } - return super.add(component); - } - - void onGameDetach() {} - - void _confHitBoxRender(Component component) { - if (component is ShapeHitbox) { - // if (gameRef.showCollisionArea) { - var paintCollition = Paint() - ..color = const Color(0xffffffff); - if (component is Sensor) { - paintCollition.color = sensorColor; - } - component.paint = paintCollition; - component.renderShape = true; - // } - } - } - - bool get containsShapeHitbox { - return shapeHitboxes.isNotEmpty; - } - - List get shapeHitboxes => children.query(); - - Rect get rectCollision { - if (_rectCollision == null) { - var list = children.query(); - if (list.isNotEmpty) { - _rectCollision = children.query().fold( - list.first.toRect(), - (previousValue, element) { - return previousValue!.expandToInclude(element.toRect()); - }, - ); - } - } - var absoluteRect = toAbsoluteRect(); - - if (_rectCollision != null) { - return _rectCollision!.translate(absoluteRect.left, absoluteRect.top); - } else { - return absoluteRect; - } - } - - RaycastResult? raycast( - Vector2 direction, { - Vector2? origin, - double? maxDistance, - List? ignoreHitboxes, - }) { - try { - return gameRef.collisionDetection.raycast( - Ray2( - origin: origin ?? rectCollision.center.toVector2(), - direction: direction, - ), - maxDistance: maxDistance, - ignoreHitboxes: [ - ...children.query(), - ..._getSensorsHitbox(), - ...ignoreHitboxes ?? [], - ], - ); - } catch (e) { - return null; - } - } - - List> raycastAll( - int numberOfRays, { - Vector2? origin, - double? maxDistance, - double startAngle = 0, - double sweepAngle = tau, - List? rays, - List? ignoreHitboxes, - }) { - try { - return gameRef.collisionDetection.raycastAll( - origin ?? rectCollision.center.toVector2(), - numberOfRays: numberOfRays, - maxDistance: maxDistance, - startAngle: startAngle, - sweepAngle: sweepAngle, - rays: rays, - ignoreHitboxes: [ - ...children.query(), - ..._getSensorsHitbox(), - ...ignoreHitboxes ?? [], - ], - ); - } catch (e) { - return []; - } - } - - Iterable> raytrace( - Ray2 ray, { - int maxDepth = 10, - List? ignoreHitboxes, - }) { - try { - return gameRef.collisionDetection.raytrace( - ray, - maxDepth: maxDepth, - ignoreHitboxes: [ - ...children.query(), - ..._getSensorsHitbox(), - ...ignoreHitboxes ?? [], - ], - ); - } catch (e) { - return []; - } - } - - - final List _visibleComponents = List.empty(growable: true); - final List _visibleCollisions = List.empty(growable: true); - - List _getSensorsHitbox() { - var sensorHitBox = []; - query(onlyVisible: true).forEach((e) { - sensorHitBox.addAll(e.children.query()); - }); - return sensorHitBox; - } - - - Iterable query({bool onlyVisible = false}) { - if (onlyVisible) { - return _visibleComponents.whereType(); - } - return gameRef.world.children.query(); - } - - - @override - void onMount() { - paint.isAntiAlias = false; - super.onMount(); - } -} diff --git a/lib/core/mixins/internal_checker.dart b/lib/core/mixins/internal_checker.dart deleted file mode 100644 index fa1a983..0000000 --- a/lib/core/mixins/internal_checker.dart +++ /dev/null @@ -1,88 +0,0 @@ - -import 'package:flutter/cupertino.dart'; - -mixin InternalChecker { - /// Map available to store times that can be used to control the frequency of any action. - Map? _timers; - - /// Returns true if for each time the defined millisecond interval passes. - /// Like a `Timer.periodic` - /// Used in flows involved in the [update] - bool checkInterval( - String key, - int intervalInMilli, - double dt, { - bool firstCheckIsTrue = true, - }) { - _timers ??= {}; - if (_timers![key]?.interval != intervalInMilli) { - _timers![key] = IntervalTick(intervalInMilli); - return firstCheckIsTrue; - } else { - return _timers![key]?.update(dt) ?? false; - } - } - - void resetInterval(String key) { - _timers?[key]?.reset(); - } - - void tickInterval(String key) { - _timers?[key]?.tick(); - } - - void pauseEffectController(String key) { - _timers?[key]?.pause(); - } - - void playInterval(String key) { - _timers?[key]?.play(); - } - - bool invervalIsRunning(String key) { - return _timers?[key]?.running ?? false; - } -} - - -class IntervalTick { - late int interval; // in Milliseconds - final VoidCallback? onTick; - double _currentTime = 0; - bool _running = true; - late double _intervalSeconds; - IntervalTick(this.interval, {this.onTick}) { - _intervalSeconds = interval / 1000; - } - - bool update(double dt) { - if (_running) { - _currentTime += dt; - if (_currentTime >= _intervalSeconds) { - onTick?.call(); - reset(); - return true; - } - } - - return false; - } - - void reset() { - _currentTime = 0; - } - - void pause() { - _running = false; - } - - void play() { - _running = true; - } - - void tick() { - _currentTime = _intervalSeconds; - } - - bool get running => _running; -} \ No newline at end of file diff --git a/lib/core/mixins/sensor.dart b/lib/core/mixins/sensor.dart deleted file mode 100644 index e8d4135..0000000 --- a/lib/core/mixins/sensor.dart +++ /dev/null @@ -1,65 +0,0 @@ - - -import 'dart:ui'; - -import 'package:flame/collisions.dart'; -import 'package:flame/components.dart'; -import 'package:pacman/components/my_component.dart'; - -final Color sensorColor = const Color(0xFFF44336).withOpacity(0.5); - -/// Mixin responsible for adding trigger to detect other objects above -/// T is a type that Sensor will be find contact. -mixin Sensor on MyComponent { - static const _sensorIntervalKey = 'SensorContact'; - int _intervalCallback = 100; - MyComponent? componentIncontact; - bool sensorEnabled = true; - - void onContact(T component) {} - void onContactExit(T component) {} - - void setSensorInterval(int intervalCallback) { - _intervalCallback = intervalCallback; - } - - @override - void update(double dt) { - super.update(dt); - if (componentIncontact != null && sensorEnabled) { - if (checkInterval(_sensorIntervalKey, _intervalCallback, dt)) { - onContact(componentIncontact! as T); - } - } - } - - @override - Future onLoad() async { - await super.onLoad(); - bool containsShape = children.query().isNotEmpty; - if (!containsShape) { - add(RectangleHitbox(size: size, isSolid: true)); - } - } - - @override - void onCollision(Set intersectionPoints, PositionComponent other) { - if (other is T) { - componentIncontact = other; - } - super.onCollision(intersectionPoints, other); - } - - @override - void onCollisionEnd(PositionComponent other) { - if (componentIncontact == other) { - componentIncontact = null; - onContactExit(other as T); - resetInterval(_sensorIntervalKey); - } - super.onCollisionEnd(other); - } - - @override - int get priority => 1; -} \ No newline at end of file diff --git a/lib/decorations/wall.dart b/lib/decorations/wall.dart index 3daf9cd..e39a3be 100644 --- a/lib/decorations/wall.dart +++ b/lib/decorations/wall.dart @@ -1,5 +1,4 @@ import 'dart:ui'; - import 'package:flame/collisions.dart'; import 'package:flame/components.dart'; import 'package:flame/palette.dart'; @@ -22,7 +21,6 @@ class Wall extends PositionComponent with HasGameRef, CollisionCallb await super.onLoad(); add( - RectangleHitbox( size: Vector2.all(tileSize), ) @@ -31,7 +29,6 @@ class Wall extends PositionComponent with HasGameRef, CollisionCallb ..debugMode = false ..priority = 1 ..renderShape = true - ); } @@ -42,5 +39,6 @@ class Wall extends PositionComponent with HasGameRef, CollisionCallb } + } diff --git a/lib/level/map.dart b/lib/level/map.dart index b4fa49d..3f3ea96 100644 --- a/lib/level/map.dart +++ b/lib/level/map.dart @@ -25,6 +25,9 @@ class Level extends World with HasGameRef { "#######################" ]; + + final walls = []; + @override Future onLoad() async { @@ -37,9 +40,11 @@ class Level extends World with HasGameRef { if (char == '#') { - add(Wall() - ..position = Vector2(x * tileSize, y * tileSize) - ); + final wall = Wall() + ..position = Vector2(x * tileSize, y * tileSize); + + add(wall); + walls.add(wall); continue; }