Flutter 위에 구축된 게임 엔진인 Flame Engine

37057 단어 fluttermobilegamedev
Flutter , 플랫폼 간 아름다운 UI를 구축할 수 있는 최신 UI 툴킷입니다. 하지만 게임 개발에도 사용할 수 있다는 사실을 알고 계십니까?

모든 종류의 2D 게임을 만들고 모바일, 웹 및 데스크톱과 같은 모든 Flutter 지원 플랫폼에서 실행할 수 있는 Flutter 위에 구축된 2D 게임 프레임워크Flame Engine를 소개합니다.

📽 Video version available on YouTube and Odysee





이 기사에서는 Flame을 시작하기 위한 3가지 빠른 샘플을 보여드리겠습니다. 샘플을 찾을 수 있습니다here.

간단한 2D 이동



시작하려면 pubspec.yaml에 flame 종속성을 추가합니다.

dependencies:
  flame: 1.1.0


다음 스니펫(코드 내 주석)을 사용하십시오.

import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

// Create a class that extends from FlameGame, use the 
// KeyboardEvents mixin to receive keyboard input events
class Basic2DMovement extends FlameGame with KeyboardEvents {
  // This will be the size of the moving object
  static const _size = 100.0;

  // With this paint we will give it a color
  final paint = Paint()..color = Colors.lightGreen;

  // Use this variables to store the position of the object
  double _x = 0.0;
  double _y = 0.0;

  // This render function will be called in 
  // each frame to paint the object
  @override
  void render(Canvas canvas) {
    super.render(canvas);

    // This rect represents our object (a square)
    final rect = Rect.fromLTWH(_x, _y, _size, _size);
    // Draw the object with the provided Canvas
    canvas.drawRect(rect, paint);
  }

  @override
  KeyEventResult onKeyEvent(
    RawKeyEvent event,
    Set<LogicalKeyboardKey> keysPressed,
  ) {
    // Store if the key is down
    final isKeyDown = event is RawKeyDownEvent;

    // Alter the x, y values according to the current keys pressed
    if (keysPressed.contains(LogicalKeyboardKey.arrowLeft) && isKeyDown) {
      _x -= 10.0;
    } else if (keysPressed.contains(LogicalKeyboardKey.arrowRight) &&
        isKeyDown) {
      _x += 10.0;
    }

    if (keysPressed.contains(LogicalKeyboardKey.arrowUp) && isKeyDown) {
      _y -= 10.0;
    } else if (keysPressed.contains(LogicalKeyboardKey.arrowDown) &&
        isKeyDown) {
      _y += 10.0;
    }

    // Return this value to acknowledge that the input 
    // has been managed
    return KeyEventResult.handled;
  }
}


이 샘플을 실행하려면 이 클래스를 runApp()에서 호출된 GameObject 내에서 래핑해야 합니다.

void main() {
  runApp(GameWidget(game: Basic2DMovement()));
}


고급 2D 이동




import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class Advanced2DMovement extends FlameGame with KeyboardEvents {
  static const _size = 100.0;

  final paint = Paint()..color = Colors.lightGreen;

  // This will be the speed of the object
  static const double _speed = 100.0;
  // This friction will apply if there are no input so the object
  // does not stop immediately
  static const double _friction = 0.9;

  // Store the position in a Vector2
  Vector2 _position = Vector2.zero();
  // This vector is the current momentum of the object
  Vector2 _movementVector = Vector2.zero();

  // This booleans will indicate us the current pressed keys
  bool _isPressingLeft = false;
  bool _isPressingRight = false;
  bool _isPressingUp = false;
  bool _isPressingDown = false;

  // The update function will be called in each frame
  // with the time from the last frame as the delta value, 
  // this way we can ensure a framerate
  // independent movement
  @override
  void update(double delta) {
    super.update(delta);

    // Create a vector to store the current input
    final Vector2 inputVector = Vector2.zero();

    // Alter the input vector according to the current pressed keys
    if (_isPressingLeft) {
      inputVector.x -= 1.0;
    } else if (_isPressingRight) {
      inputVector.x += 1.0;
    }

    if (_isPressingUp) {
      inputVector.y -= 1.0;
    } else if (_isPressingDown) {
      inputVector.y += 1.0;
    }

    // If there are some input...
    if (!inputVector.isZero()) {
      // Assign the input vector to the movement vector
      _movementVector = inputVector;

      // Normalize the movement vector so the speed 
      // will be always the same in all directions
      _movementVector.normalize();
      // Apply the speed and the delta time for a 
      // framerate independent movement
      _movementVector *= _speed * delta;
    } else {
      // If no keys are pressed, apply a friction to the vector to make
      // the object stop gradually
      _movementVector *= _friction;
    }

    // Apply movement vector to the current position
    _position += _movementVector;
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);

    final rect = Rect.fromLTWH(_position.x, _position.y, _size, _size);
    canvas.drawRect(rect, paint);
  }

  @override
  KeyEventResult onKeyEvent(
    RawKeyEvent event,
    Set<LogicalKeyboardKey> keysPressed,
  ) {
    if (keysPressed.contains(LogicalKeyboardKey.arrowLeft) &&
        event is RawKeyDownEvent) {
      _isPressingLeft = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowLeft) {
      _isPressingLeft = false;
    }

    if (keysPressed.contains(LogicalKeyboardKey.arrowRight) &&
        event is RawKeyDownEvent) {
      _isPressingRight = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowRight) {
      _isPressingRight = false;
    }

    if (keysPressed.contains(LogicalKeyboardKey.arrowUp) &&
        event is RawKeyDownEvent) {
      _isPressingUp = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowUp) {
      _isPressingUp = false;
    }

    if (keysPressed.contains(LogicalKeyboardKey.arrowDown) &&
        event is RawKeyDownEvent) {
      _isPressingDown = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowDown) {
      _isPressingDown = false;
    }

    return KeyEventResult.handled;
  }
}


스프라이트를 추가하고 로직을 Player 클래스로 이동




import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

// We are going to move all the logic regarding 
// the player to this class, the KeyboardHandler 
// will allow us to capture keyboard events from within.
// All the previous logic has been moved to this class 
// almost without changes.
//
// This time we are going to extend from SpriteComponent, 
// which will allow us to add a sprite to this element.
class Player extends SpriteComponent with KeyboardHandler {
  static const _size = 128.0;

  static const double _speed = 100.0;
  static const double _friction = 0.9;

  Vector2 _movementVector = Vector2.zero();

  bool _isPressingLeft = false;
  bool _isPressingRight = false;
  bool _isPressingUp = false;
  bool _isPressingDown = false;

  // The onLoad() function is called at the beginning 
  // to make an initial load of resources
  @override
  Future<void> onLoad() async {
    await super.onLoad();
    size = Vector2(_size, _size);
    // Calling Sprite.load() we can asign to this 
    // component the given image
    sprite = await Sprite.load('flutter.png');
  }

  @override
  void update(double delta) {
    super.update(delta);

    final Vector2 inputVector = Vector2.zero();

    if (_isPressingLeft) {
      inputVector.x -= 1.0;
    } else if (_isPressingRight) {
      inputVector.x += 1.0;
    }

    if (_isPressingUp) {
      inputVector.y -= 1.0;
    } else if (_isPressingDown) {
      inputVector.y += 1.0;
    }

    if (!inputVector.isZero()) {
      _movementVector = inputVector;

      _movementVector.normalize();
      _movementVector *= _speed * delta;
    } else {
      _movementVector *= _friction;
    }

    position += _movementVector;
  }

  @override
  bool onKeyEvent(
    RawKeyEvent event,
    Set<LogicalKeyboardKey> keysPressed,
  ) {
    if (keysPressed.contains(LogicalKeyboardKey.arrowLeft) &&
        event is RawKeyDownEvent) {
      _isPressingLeft = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowLeft) {
      _isPressingLeft = false;
    }

    if (keysPressed.contains(LogicalKeyboardKey.arrowRight) &&
        event is RawKeyDownEvent) {
      _isPressingRight = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowRight) {
      _isPressingRight = false;
    }

    if (keysPressed.contains(LogicalKeyboardKey.arrowUp) &&
        event is RawKeyDownEvent) {
      _isPressingUp = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowUp) {
      _isPressingUp = false;
    }

    if (keysPressed.contains(LogicalKeyboardKey.arrowDown) &&
        event is RawKeyDownEvent) {
      _isPressingDown = true;
    } else if (event is RawKeyUpEvent &&
        event.data.logicalKey == LogicalKeyboardKey.arrowDown) {
      _isPressingDown = false;
    }

    return true;
  }
}

class SpriteExample extends FlameGame with HasKeyboardHandlerComponents {
  // Declare the player as a variable
  late final Player _player;

  // Let's modify the background color
  @override
  Color backgroundColor() => const Color(0xFF353935);

  @override
  Future<void> onLoad() async {
    await super.onLoad();

    // Add the player to this game
    _player = Player();
    await add(_player);
  }
}

좋은 웹페이지 즐겨찾기