코딩파파 모바일게임 따라하기
파일구조
※ pubspec.yaml
dependencies:
flame: ^0.28.0
assets:
- assets/images/
- assets/audio/
※ main.dart
import 'package:flame/flame.dart';
import 'package:flutter/material.dart';
import 'my_game.dart';
Size size;
var spriteSheet;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
size = await Flame.util.initialDimensions();
spriteSheet = await Flame.images.load("sprites.png");
runApp(MyGame().widget);
}
※ game_state.dart
enum GameState { pause, play, gameover }
GameState gameState = GameState.pause;
※ option.dart
double
GAME_SPEED = 50;
※ components\bird.dart
import 'package:flame/anchor.dart';
import 'package:flame/components/animation_component.dart';
import 'package:flame/flame.dart';
import 'package:flappy_game/game_state.dart';
import 'package:flappy_game/main.dart';
import 'package:flappy_game/options.dart';
final double BIRD_W = 52;
final double BIRD_H = 36.7;
final double GRAVITY = 1200;
class Bird extends AnimationComponent {
Bird()
: super.sequenced(BIRD_W, BIRD_H, 'bird.png', 3,
textureWidth: 17, textureHeight: 12);
double speedY = 0.0;
@override
void update(double t) {
super.update(t);
this.anchor = Anchor.center;
switch (gameState) {
case GameState.pause:
this.y = size.height * 0.4;
this.x = size.width / 2;
break;
case GameState.play:
speedY += (GRAVITY + GAME_SPEED) * t;
this.y += (speedY * t) / 2;
this.x = size.width / 2;
break;
case GameState.gameover:
break;
}
}
void onTap() {
switch (gameState) {
case GameState.pause:
this.speedY = -500;
Flame.audio.play("bubble_pop.mp3", volume: 0.9);
break;
case GameState.play:
this.speedY = -500;
Flame.audio.play("bubble_pop.mp3", volume: 0.9);
break;
case GameState.gameover:
break;
}
}
}
※ components\floor.dart
import 'dart:ui';
import 'package:flame/components/component.dart';
import 'package:flame/position.dart';
import 'package:flame/sprite.dart';
import 'package:flappy_game/game_state.dart';
import 'package:flappy_game/main.dart';
import 'package:flappy_game/options.dart';
class Floor extends Component {
Sprite _floorSprite = Sprite("floor.png");
double xSize = 0;
double ySize = 0;
double xPos = 0;
@override
void render(Canvas c) {
xSize = size.width * 2;
ySize = xSize / 168 * 56;
_floorSprite.renderPosition(c, Position(xPos, size.height - ySize * 0.3),
size: Position(xSize, ySize));
}
@override
void update(double t) {
switch (gameState) {
case GameState.pause:
case GameState.play:
xPos -= t * (30 + GAME_SPEED);
if (xPos.abs() >= size.width) {
xPos = 0;
}
break;
case GameState.gameover:
break;
}
}
Rect toRect() {
return Rect.fromLTWH(0, size.height - ySize * 0.3, xSize, ySize);
}
}
※ components\pipe_set.dart
import 'dart:math';
import 'dart:ui';
import 'package:flame/components/component.dart';
import 'package:flame/position.dart';
import 'package:flame/sprite.dart';
import 'package:flappy_game/game_state.dart';
import 'package:flappy_game/options.dart';
import '../main.dart';
class PipeSet extends Component {
static double pipeH = size.height / 12 * 7;
static double pipeW = pipeH / 160 * 26;
static double pipeGap = 4;
Sprite _pipUp = Sprite("pipe_up.png");
Sprite _pipDown = Sprite("pipe_down.png");
double pipePos = size.width;
int pipeLevel = 1;
bool hadScored = false;
@override
void render(Canvas c) {
_pipUp.renderPosition(c, Position(pipePos, pipeH / 7 * (pipeLevel - 7)),
size: Position(pipeW, pipeH));
_pipDown.renderPosition(
c, Position(pipePos, pipeH / 7 * (pipeLevel + pipeGap)),
size: Position(pipeW, pipeH));
}
@override
void update(double t) {
switch (gameState) {
case GameState.pause:
pipePos = size.width;
hadScored = false;
break;
case GameState.play:
if (pipePos < -pipeW) {
pipePos = size.width;
hadScored = false;
pipeLevel = Random().nextInt(5);
if (pipeLevel == 0) pipeLevel = 6;
}
pipePos -= t * (30 + GAME_SPEED);
break;
case GameState.gameover:
break;
}
}
Rect getPipUpRect() {
return Rect.fromLTWH(pipePos, pipeH / 7 * (pipeLevel - 7), pipeW, pipeH);
}
Rect getPipDownRect() {
return Rect.fromLTWH(
pipePos, pipeH / 7 * (pipeLevel + pipeGap), pipeW, pipeH);
}
void scoreUpdated() {
hadScored = true;
}
}
※ components\score.dart
import 'dart:collection';
import 'dart:ui';
import 'package:flame/components/component.dart';
import 'package:flame/sprite.dart';
import 'package:flappy_game/consts/sprite_dimentions.dart';
import '../main.dart';
class Score extends PositionComponent {
static final double numW = size.width / 20;
static final double numH = numW / 12 * 18;
HashMap<String, Sprite> _digits;
SpriteComponent _oneDigit;
SpriteComponent _twoDigit;
SpriteComponent _threeDigit;
int _score = 0;
Score()
: _digits = HashMap.from({
"0": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.zeroNumberX,
y: SpritePositions.zeroNumberY),
"1": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.firstNumberX,
y: SpritePositions.firstNumberY),
"2": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.secondNumberX,
y: SpritePositions.secondNumberY),
"3": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.thirdNumberX,
y: SpritePositions.thirdNumberY),
"4": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.fourthNumberX,
y: SpritePositions.fourthNumberY),
"5": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.fifthNumberX,
y: SpritePositions.fifthNumberY),
"6": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.sixthNumberX,
y: SpritePositions.sixthNumberY),
"7": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.seventhNumberX,
y: SpritePositions.seventhNumberY),
"8": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.eighthNumberX,
y: SpritePositions.eighthNumberY),
"9": Sprite.fromImage(spriteSheet,
width: SpriteDimentions.numberWidth,
height: SpriteDimentions.numberHeight,
x: SpritePositions.ninethNumberX,
y: SpritePositions.ninethNumberY),
}) {
_oneDigit = SpriteComponent.fromSprite(numW, numH, _digits["0"]);
_twoDigit = SpriteComponent.fromSprite(numW, numH, _digits["0"]);
_threeDigit = SpriteComponent.fromSprite(numW, numH, _digits["0"]);
_oneDigit.x = numW * 8;
_twoDigit.x = numW * 1.5;
_threeDigit.x = numW * 1.5;
_oneDigit.y = numH * 1.5;
}
void addScore() {
_score++;
}
void resetScore() {
_score = 0;
}
@override
void render(Canvas c) {
String scoreInStr = _score.toString().padLeft(3, "0");
_oneDigit.sprite = _digits[scoreInStr[0]];
_twoDigit.sprite = _digits[scoreInStr[1]];
_threeDigit.sprite = _digits[scoreInStr[2]];
_oneDigit.render(c);
_twoDigit.render(c);
_threeDigit.render(c);
}
}
※ components\titles.dart
import 'dart:ui';
import 'package:flame/components/component.dart';
import 'package:flame/position.dart';
import 'package:flame/sprite.dart';
import 'package:flappy_game/game_state.dart';
import 'package:flappy_game/main.dart';
class Titles extends Component {
Sprite _getReady =
Sprite.fromImage(spriteSheet, x: 295, y: 59, width: 92, height: 25);
Sprite _gameOver =
Sprite.fromImage(spriteSheet, x: 395, y: 59, width: 96, height: 25);
double xSize = 0;
double ySize = 0;
@override
void render(Canvas c) {
switch (gameState) {
case GameState.pause:
xSize = size.width * 0.6;
ySize = xSize / 92 * 25;
_getReady.renderPosition(
c, Position(size.width * 0.2, size.height * 0.2),
size: Position(xSize, ySize));
break;
case GameState.play:
break;
case GameState.gameover:
xSize = size.width * 0.6;
ySize = xSize / 96 * 25;
_gameOver.renderPosition(
c, Position(size.width * 0.2, size.height * 0.2),
size: Position(xSize, ySize));
break;
}
}
@override
void update(double t) {
// TODO: implement update
}
}
※ contents\sprite_dimentions.dart
class SpriteDimentions {
static double numberWidth = 12.0;
static double numberHeight = 18.0;
}
class SpritePositions {
static double zeroNumberX = 496.0;
static double zeroNumberY = 60.0;
static double firstNumberX = 136.0;
static double firstNumberY = 455.0;
static double secondNumberX = 292.0;
static double secondNumberY = 160.0;
static double thirdNumberX = 306.0;
static double thirdNumberY = 160.0;
static double fourthNumberX = 320.0;
static double fourthNumberY = 160.0;
static double fifthNumberX = 334.0;
static double fifthNumberY = 160.0;
static double sixthNumberX = 292.0;
static double sixthNumberY = 184.0;
static double seventhNumberX = 306.0;
static double seventhNumberY = 184.0;
static double eighthNumberX = 320.0;
static double eighthNumberY = 184.0;
static double ninethNumberX = 334.0;
static double ninethNumberY = 184.0;
}
※ my_game.dart
import 'dart:ui';
import 'package:flame/components/component.dart';
import 'package:flame/flame.dart';
import 'package:flame/gestures.dart';
import 'package:flame/sprite.dart';
import 'package:flappy_game/components/bird.dart';
import 'package:flappy_game/components/floor.dart';
import 'package:flappy_game/components/pipe_set.dart';
import 'package:flappy_game/components/score.dart';
import 'package:flappy_game/components/titles.dart';
import 'package:flappy_game/game_state.dart';
import 'package:flappy_game/main.dart';
import 'package:flame/game/base_game.dart';
class MyGame extends BaseGame with TapDetector {
Bird _bird;
Floor _floor;
Titles _titles;
PipeSet _pipeSet;
Score _score;
MyGame() {
_bird = Bird();
_floor = Floor();
_titles = Titles();
_pipeSet = PipeSet();
_score = Score();
this
..add(
SpriteComponent.fromSprite(size.width, size.height, Sprite("bg.png")))
..add(_pipeSet)
..add(_bird)
..add(_floor)
..add(_titles)
..add(_score);
}
@override
void update(double t) {
super.update(t);
if (gameState == GameState.play) {
//새가 바닥에 부딪혔을때
if (checkIf2CompoCollision(_bird.toRect(), _floor.toRect())) {
setGameOver();
}
//새가 위 파이프에 부딪혔을때
if (checkIf2CompoCollision(_bird.toRect(), _pipeSet.getPipUpRect())) {
setGameOver();
}
//새가 아래 파이프에 부딪혔을때
if (checkIf2CompoCollision(_bird.toRect(), _pipeSet.getPipDownRect())) {
setGameOver();
}
checkIfBirdPassedPipe();
}
}
void setGameOver() {
Flame.audio.play("hit.wav");
Flame.audio.play("die.mp3");
gameState = GameState.gameover;
}
@override
void onTap() {
_bird.onTap();
switch (gameState) {
case GameState.pause:
gameState = GameState.play;
break;
case GameState.play:
break;
case GameState.gameover:
gameState = GameState.pause;
_score.resetScore();
break;
}
}
bool checkIf2CompoCollision(Rect item1, Rect item2) {
var intersectedRect = item1.intersect(item2);
return intersectedRect.width > 2 && intersectedRect.height > 2;
}
//새가 파이프를 통과했을때
void checkIfBirdPassedPipe() {
if (_pipeSet.hadScored) return;
if (_pipeSet.getPipUpRect().right < _bird.toRect().left) {
Flame.audio.play("point.mp3");
_score.addScore();
_pipeSet.scoreUpdated();
}
}
}
코딩파파
www.youtube.com/watch?v=CVdGjaFI5Bw
'코딩(개발) > Flutter' 카테고리의 다른 글
ListView / AnimateList (0) | 2021.03.04 |
---|---|
TextField (0) | 2021.03.04 |
체크박스 있는 리스트뷰 (0) | 2021.02.09 |
DatePicker (0) | 2021.02.09 |
webview (0) | 2021.02.04 |
댓글