-
Flutter/Flame 2D X, Y축 이동이 가능한 2D 게임 만들기 예시 (Example of creating a 2D game with movable X and Y axes)DEV/flutter (dart) 2023. 3. 9. 18:27
1. 시작
저번 시간에 Flutter를 이용하여 2D 횡스크롤 (X 축만 이동) 게임의 기본 기능을 구현해 보았다.
(좌, 우 이동 및 점프 기능 구현)
https://seokbong.tistory.com/184
https://seokbong.tistory.com/185
이번에는 Y축 이동도 가능한 2D 기능을 구현해 보려고 한다.
(정말 이동 기능만 구현한다.)
사실 위 X축 이동에서 Y축 이동에 대한 코드만 작성하면 된다.
(점프 대신에...)
대신 다른 점은 Y축 이동에 따른 캐릭터 움직임 방향이 2개가 더 추가되어야 한다는 점이다.
사실 이미지 소스만 구하면 큰 문제가 되지 않는다.
이번 글에서 사용하는 이미지는 하단 소스를 사용한다. (Author:sheep)
https://opengameart.org/content/alternate-lpc-character-sprites-george
이 글다음에는 케릭터 이름 생성, 채팅 기능을 넣어보고 싶다.
(내가 할까...?)
아무튼 바로 코드 진행해보자.
해당 글을 완독 하면...
2. 개발환경
해당 글은 23년 3월 9일 기준으로 작성되었습니다.
Windows 10
Flutter (Android Studio)
Flame 1.6.0
3. 코드
이번에도 최대한 서순에 맞게 작성하고 싶었다.
근데 또 다 만들고 작성하게 되었다... (--...)
최대한 순서대로 따라 하면 작동하게 서술하고자 한다.
3.1) Flame 1.6.0 Pub get
본인의 Flutter 프로젝트를 생성하고 Flame 1.6.0 dependencies를 추가하자.
이 부분은 모른다면 위의 "2D 횡스크롤 게임 만들기 예시 1" 글을 눌러서 따라하면 된다.
3.2) 파일구성
파일 구성도 저번과 비슷하다.
본인은 다음과 같이 구성하였다.
이 부분도 잘 모르겠다면 위 "2D 횡스크롤 게임 만들기 예시 1"에 아주아주 조금 더 설명이 있다. (진짜 조금 있음)
- project_folder (본인이 생성한 프로젝트) - assets (생성하셈) - images (생성하셈) -player_spritesheet.png (케릭터 넣어주셈, 글 위에 링크 있음) - lib - main.dart - main_game.dart (생성하셈) - components (생성하셈) - player (생성하셈) - player.dart (생성하셈)
3.3 main_game.dart
새로 생성한 main_game.dart의 코드를 다음과 같이 작성하자.
import 'package:flame/game.dart'; import 'package:flame/events.dart'; import 'package:flutter/material.dart'; // FlameGame Extends class MainGame extends FlameGame with HasKeyboardHandlerComponents { @override Future<void> onLoad() async { // TODO 1 } }
아무것도 없는건 정상이다.
당황하지 말자.
3.4) main.dart
나중에 추가 및 수정할 widget을 위해 MaterialApp -> Scaffold -> Stack 으로 구성했다.
근데... 사실 MainGamePage()만 넣어주어도 된다. (아직 다른 기능이 없기 때문에...)
프로젝트 생성 후 main.dart에 자동 생성되는 코드는 지우고 하단 코드로 바꿔주자.
import 'package:flame/game.dart'; import 'package:flutter/material.dart'; import 'package:game_2d_sample/main_game.dart'; void main() { runApp( const MaterialApp( home: Scaffold( backgroundColor: Color.fromRGBO(0, 0, 0, 1), body: Stack( children: [ MainGamePage(), ], ), ), ) ); } class MainGamePage extends StatefulWidget { const MainGamePage({Key? key}) : super(key: key); @override State<MainGamePage> createState() => _MainGamePageState(); } class _MainGamePageState extends State<MainGamePage> { // 결국 main.dart의 알맹이는 요기! late final MainGame _mainGame; @override void initState() { super.initState(); _mainGame = MainGame(); } @override Widget build(BuildContext context) { return GameWidget(game: _mainGame); } }
3.5) player.dart
player 객체를 만들고 player의 이동속도, 방향, 스프라이트 에니메이션을 구현해야 한다.
import 'package:flame/components.dart'; import 'package:flame/sprite.dart'; import 'package:flame/game.dart'; import 'package:flutter/services.dart'; class Player extends SpriteAnimationComponent with KeyboardHandler, HasGameRef { Player() : super(size: Vector2.all(50)); // 케릭터 에니메이션에 대한 속도 final double _animationSpeed = 0.15; // 케릭터 이동에 대한 속도 final Vector2 velocity = Vector2.zero(); final double moveSpeed = 300; // 케릭터의 이동 방향 int horizontalDirection = 0; int verticalDirection = 0; // 케릭터 이동 방향에 따른 에니메이션 late final SpriteAnimation _runDownAnimation; late final SpriteAnimation _runLeftAnimation; late final SpriteAnimation _runUpAnimation; late final SpriteAnimation _runRightAnimation; late final SpriteAnimation _standingAnimation; // Load 됐을 때, @override Future<void> onLoad() async { super.onLoad(); // 케릭터 에니메이션 설정 await _loadAnimations(); // 케릭터 생성 후 스탠딩 모션을 default로 animation = _standingAnimation; } // Update 될 때, @override void update(double dt) { // x, y 축 이동속도 계산 velocity.x = horizontalDirection * moveSpeed; velocity.y = verticalDirection * moveSpeed; // 플레이어 이동 (dt는 마지막 프레임으로 부터 경가된 시간[초]) position += velocity * dt; super.update(dt); } // 에니메이션 로드 Future<void> _loadAnimations() async { final game = FlameGame(); final spriteSheet = SpriteSheet( image: await game.images.load('player_spritesheet.png'), // srcSize : SpriteSheet에서 각 스프라이트의 크기를 지정하는 속성 // player_spritesheet.png 이미지의 각 스프라이트가 29x32로 자르도록 지정 srcSize: Vector2(29.0, 32.0), ); // 위로 움직일 때의 케릭터 에니메이션 _runUpAnimation = spriteSheet.createAnimation( row: 2, stepTime: _animationSpeed, to: 4, ); // 아래로 움직일 때의 케릭터 에니메이션 _runDownAnimation = spriteSheet.createAnimation( row: 0, stepTime: _animationSpeed, to: 4, ); // 왼쪽으로 움직일 때의 케릭터 에니메이션 _runLeftAnimation = spriteSheet.createAnimation( row: 1, stepTime: _animationSpeed, to: 4, ); // 오른쪽으로 움직일 때의 케릭터 에니메이션 _runRightAnimation = spriteSheet.createAnimation( row: 3, stepTime: _animationSpeed, to: 4, ); // 가만히 서있을 때의 케릭터 에니메이션 _standingAnimation = spriteSheet.createAnimation( row: 0, stepTime: _animationSpeed, to: 1, ); } // 키보드 이벤트 처리 @override bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) { horizontalDirection = 0; verticalDirection = 0; bool keyPressed = false; // 움직임에 따라 에니메이션 변경 // 상 화살표가 눌린 경우 verticalDirection +1 if(keysPressed.contains(LogicalKeyboardKey.arrowUp)){ verticalDirection -= 1; animation = _runUpAnimation; keyPressed = true; } // 하 화살표가 눌린 경우 verticalDirection -1 if(keysPressed.contains(LogicalKeyboardKey.arrowDown)){ verticalDirection += 1; animation = _runDownAnimation; keyPressed = true; } // 좌 화살표가 눌린 경우 horizontalDirection -1 if(keysPressed.contains(LogicalKeyboardKey.arrowLeft)){ horizontalDirection -= 1; animation = _runLeftAnimation; keyPressed = true; } // 우 화살표가 눌린 경우 horizontalDirection +1 if(keysPressed.contains(LogicalKeyboardKey.arrowRight)){ horizontalDirection += 1; animation = _runRightAnimation; keyPressed = true; } // 키가 눌리지 않았을 때 if (!keyPressed) { horizontalDirection = 0; verticalDirection = 0; animation = _standingAnimation; } return true; } }
3.6) main_game.dart, 케릭터를 등록하자
Player 객체를 생성하고 등록해야 한다.
main_game.dart에 주석(TODO1) 부분에 코드를 채워주자.
import 'package:flame/game.dart'; import 'package:flame/events.dart'; import 'components/player/player.dart'; // 추가하셈 // FlameGame Extends class MainGame extends FlameGame with HasKeyboardHandlerComponents { final Player _player = Player(); // 추가하셈 @override Future<void> onLoad() async { add(_player); // 추가하셈 } }
여기까지 문제없이 진행되었다면 잘 실행될것이다.
Full code는 아래 주소를 참고하자.
https://github.com/Seokhyeon-Park/game_2d_sample
'DEV > flutter (dart)' 카테고리의 다른 글
Flutter/Flame 2D Game의 Background Image 등록하기 (0) 2023.03.10 Flutter/Flame 2D 횡 스크롤 게임 만들기 예시 2 (Flutter/Flame 2D Horizontal Scroll Game Example 2) (0) 2023.03.08 Flutter/Flame 2D 횡 스크롤 게임 만들기 예시 1 (Flutter/Flame 2D Horizontal Scroll Game Example 1) (0) 2023.03.08 Flutter ChangeNotifier / MultiProvider Provider (0) 2023.02.13 Flutter 위젯 클릭(클릭, 더블클릭, 드레그 등) 시, 이벤트 발생시키는 방법 (0) 2023.02.13