mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 19:12:31 +08:00
264 lines
7.3 KiB
Dart
264 lines
7.3 KiB
Dart
import 'dart:math';
|
|
import 'dart:ui';
|
|
|
|
import 'package:box2d_flame/box2d.dart';
|
|
import 'package:flame/components/joystick/joystick_component.dart';
|
|
import 'package:flame/components/joystick/joystick_events.dart';
|
|
import 'package:flame/gestures.dart';
|
|
import 'package:flame/sprite.dart';
|
|
import 'package:flame/vector2.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
import '../../vector2.dart';
|
|
|
|
enum JoystickActionAlign { TOP_LEFT, BOTTOM_LEFT, TOP_RIGHT, BOTTOM_RIGHT }
|
|
|
|
class JoystickAction {
|
|
final int actionId;
|
|
final Sprite sprite;
|
|
final Sprite spritePressed;
|
|
final Sprite spriteBackgroundDirection;
|
|
final double size;
|
|
final double sizeFactorBackgroundDirection;
|
|
final EdgeInsets margin;
|
|
final JoystickActionAlign align;
|
|
final bool enableDirection;
|
|
final Color color;
|
|
final double opacityBackground;
|
|
final double opacityKnob;
|
|
|
|
bool isPressed = false;
|
|
Rect _rectAction;
|
|
Rect _rectBackgroundDirection;
|
|
bool _dragging = false;
|
|
Sprite _spriteAction;
|
|
Offset _dragPosition;
|
|
Paint _paintBackground;
|
|
Paint _paintAction;
|
|
Paint _paintActionPressed;
|
|
JoystickController _joystickController;
|
|
double _sizeBackgroundDirection;
|
|
DragEvent _currentDragEvent;
|
|
double _tileSize;
|
|
|
|
JoystickAction({
|
|
@required this.actionId,
|
|
this.sprite,
|
|
this.spritePressed,
|
|
this.spriteBackgroundDirection,
|
|
this.enableDirection = false,
|
|
this.size = 50,
|
|
this.sizeFactorBackgroundDirection = 1.5,
|
|
this.margin = EdgeInsets.zero,
|
|
this.color = Colors.blueGrey,
|
|
this.align = JoystickActionAlign.BOTTOM_RIGHT,
|
|
this.opacityBackground = 0.5,
|
|
this.opacityKnob = 0.8,
|
|
}) {
|
|
_spriteAction = sprite;
|
|
_sizeBackgroundDirection = sizeFactorBackgroundDirection * size;
|
|
_tileSize = _sizeBackgroundDirection / 2;
|
|
}
|
|
|
|
void initialize(Vector2 _screenSize, JoystickController joystickController) {
|
|
_joystickController = joystickController;
|
|
final double radius = size / 2;
|
|
double dx = 0, dy = 0;
|
|
switch (align) {
|
|
case JoystickActionAlign.TOP_LEFT:
|
|
dx = margin.left + radius;
|
|
dy = margin.top + radius;
|
|
break;
|
|
case JoystickActionAlign.BOTTOM_LEFT:
|
|
dx = margin.left + radius;
|
|
dy = _screenSize.y - (margin.bottom + radius);
|
|
break;
|
|
case JoystickActionAlign.TOP_RIGHT:
|
|
dx = _screenSize.x - (margin.right + radius);
|
|
dy = margin.top + radius;
|
|
break;
|
|
case JoystickActionAlign.BOTTOM_RIGHT:
|
|
dx = _screenSize.x - (margin.right + radius);
|
|
dy = _screenSize.y - (margin.bottom + radius);
|
|
break;
|
|
}
|
|
_rectAction = Rect.fromCircle(
|
|
center: Offset(dx, dy),
|
|
radius: radius,
|
|
);
|
|
_rectBackgroundDirection = Rect.fromCircle(
|
|
center: Offset(dx, dy),
|
|
radius: _sizeBackgroundDirection / 2,
|
|
);
|
|
|
|
if (spriteBackgroundDirection == null) {
|
|
_paintBackground = Paint()
|
|
..color = color.withOpacity(opacityBackground)
|
|
..style = PaintingStyle.fill;
|
|
}
|
|
|
|
if (sprite == null) {
|
|
_paintAction = Paint()
|
|
..color = color.withOpacity(opacityKnob)
|
|
..style = PaintingStyle.fill;
|
|
}
|
|
|
|
if (spritePressed == null) {
|
|
_paintActionPressed = Paint()
|
|
..color = color.withOpacity(opacityBackground)
|
|
..style = PaintingStyle.fill;
|
|
}
|
|
|
|
_dragPosition = _rectAction.center;
|
|
}
|
|
|
|
void render(Canvas c) {
|
|
if (_rectBackgroundDirection != null && _dragging && enableDirection) {
|
|
if (spriteBackgroundDirection == null) {
|
|
final double radiusBackground = _rectBackgroundDirection.width / 2;
|
|
c.drawCircle(
|
|
Offset(
|
|
_rectBackgroundDirection.left + radiusBackground,
|
|
_rectBackgroundDirection.top + radiusBackground,
|
|
),
|
|
radiusBackground,
|
|
_paintBackground,
|
|
);
|
|
} else {
|
|
spriteBackgroundDirection.renderRect(c, _rectBackgroundDirection);
|
|
}
|
|
}
|
|
|
|
if (_spriteAction != null) {
|
|
if (_rectAction != null) {
|
|
_spriteAction.renderRect(c, _rectAction);
|
|
}
|
|
} else {
|
|
final double radiusAction = _rectAction.width / 2;
|
|
c.drawCircle(
|
|
Offset(
|
|
_rectAction.left + radiusAction,
|
|
_rectAction.top + radiusAction,
|
|
),
|
|
radiusAction,
|
|
isPressed ? _paintActionPressed : _paintAction,
|
|
);
|
|
}
|
|
}
|
|
|
|
void update(double dt) {
|
|
if (_dragging) {
|
|
final double _radAngle = atan2(
|
|
_dragPosition.dy - _rectBackgroundDirection.center.dy,
|
|
_dragPosition.dx - _rectBackgroundDirection.center.dx,
|
|
);
|
|
|
|
// Distance between the center of joystick background & drag position
|
|
final centerPosition =
|
|
Vector2Operations.fromOffset(_rectBackgroundDirection.center);
|
|
final dragPosition = Vector2Operations.fromOffset(_dragPosition);
|
|
double dist = centerPosition.distanceTo(dragPosition);
|
|
|
|
// The maximum distance for the knob position to the edge of
|
|
// the background + half of its own size. The knob can wander in the
|
|
// background image, but not outside.
|
|
dist = min(dist, _tileSize);
|
|
|
|
// Calculate the knob position
|
|
final double nextX = dist * cos(_radAngle);
|
|
final double nextY = dist * sin(_radAngle);
|
|
final Offset nextPoint = Offset(nextX, nextY);
|
|
|
|
final Offset diff = Offset(
|
|
_rectBackgroundDirection.center.dx + nextPoint.dx,
|
|
_rectBackgroundDirection.center.dy + nextPoint.dy,
|
|
) -
|
|
_rectAction.center;
|
|
|
|
_rectAction = _rectAction.shift(diff);
|
|
|
|
final double _intensity = dist / _tileSize;
|
|
|
|
_joystickController.joystickAction(
|
|
JoystickActionEvent(
|
|
id: actionId,
|
|
event: ActionEvent.MOVE,
|
|
intensity: _intensity,
|
|
radAngle: _radAngle,
|
|
),
|
|
);
|
|
} else {
|
|
if (_rectAction != null) {
|
|
final Offset diff = _dragPosition - _rectAction.center;
|
|
_rectAction = _rectAction.shift(diff);
|
|
}
|
|
}
|
|
}
|
|
|
|
void onReceiveDrag(DragEvent event) {
|
|
if (!_dragging && (_rectAction?.contains(event.initialPosition) ?? false)) {
|
|
if (enableDirection) {
|
|
_dragPosition = event.initialPosition;
|
|
_dragging = true;
|
|
}
|
|
_joystickController.joystickAction(
|
|
JoystickActionEvent(
|
|
id: actionId,
|
|
event: ActionEvent.DOWN,
|
|
),
|
|
);
|
|
tapDown();
|
|
_currentDragEvent = event;
|
|
_currentDragEvent
|
|
..onUpdate = onPanUpdate
|
|
..onEnd = onPanEnd
|
|
..onCancel = onPanCancel;
|
|
}
|
|
}
|
|
|
|
void tapDown() {
|
|
isPressed = true;
|
|
if (spritePressed != null) {
|
|
_spriteAction = spritePressed;
|
|
}
|
|
}
|
|
|
|
void tapUp() {
|
|
isPressed = false;
|
|
_spriteAction = sprite;
|
|
}
|
|
|
|
void onPanUpdate(DragUpdateDetails details) {
|
|
if (_dragging) {
|
|
_dragPosition = details.localPosition;
|
|
}
|
|
}
|
|
|
|
void onPanEnd(DragEndDetails p1) {
|
|
_currentDragEvent = null;
|
|
_dragging = false;
|
|
_dragPosition = _rectBackgroundDirection.center;
|
|
_joystickController.joystickAction(
|
|
JoystickActionEvent(
|
|
id: actionId,
|
|
event: ActionEvent.UP,
|
|
),
|
|
);
|
|
tapUp();
|
|
}
|
|
|
|
void onPanCancel() {
|
|
_currentDragEvent = null;
|
|
_dragging = false;
|
|
_dragPosition = _rectBackgroundDirection.center;
|
|
_joystickController.joystickAction(
|
|
JoystickActionEvent(
|
|
id: actionId,
|
|
event: ActionEvent.CANCEL,
|
|
),
|
|
);
|
|
tapUp();
|
|
}
|
|
}
|