๋ฌดํ•œ๋Œ€๋กœ ์šฐ์ธก์œผ๋กœ ์ด๋™ํ•˜๋ฉด์„œย ์ง€ํ˜• ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค๊ณ  ์žˆ๋Š”๋ฐ


performance monitor๋กœ ํ™•์ธํ•˜๋ฉด Raster(GPU) Thread์—์„œ ์ด๋”ฐ๊ธˆ ๋ ‰? Jank๊ฐ€ ๋ฐœ์ƒํ•จ.


๊ทธ๋ž˜์„œ ์ด๋™์ด ๋ถ€๋“œ๋Ÿฝ๋‹ค๊ฐ€ ํ•œ๋ฒˆ์”ฉ ๋Š๊น€.


๊ธฐ๋Šฅ์—๋Š” ๋ณ„๊ฑฐ ์—†๊ณ  sprite๋Š” 1๊ฐœ๋งŒ instance๋กœ loadํ•˜๊ณ  ๊ทธ sprite๋กœ SpriteComponent Pool์„ ์ƒ์„ฑํ•˜๊ณ 


์ด๋™ ์‹œ ๋งจ ์•ž์— ๋ Œ๋”๋ง๋œ sprite๋ฅผ ๋งจ ๋’ค๋กœ ๋ณด๋‚ด์ฃผ๋Š” ์ค‘.


์šฐ์ธก ์ด๋™์€ camera๊ฐ€ followComponent() ์ค‘์ธ PositionComponent์˜ position.x์— ๊ฐ’์„ ๋”ํ•˜๋Š” ์ค‘.


๋‹ค๋ฅธ๊ฑฐ ๋‹ค ์ฃผ์„ํ•˜๊ณ  ์ด ๊ธฐ๋Šฅ๋งŒ ํ•ด๋„ max 22.7ms/frame์ด ๋ฐœ์ƒ ใ… .


๋””๋ฐ”์ด์Šค ๋ฌธ์ œ์ธ๊ฐ€ ํ•ด์„œ


LG Q9 One, Galaxy S10 Note ๋น„๊ตํ–ˆ๋Š”๋ฐ S10์ด ๋œ ๋ฐœ์ƒํ•˜๊ธด ํ•จ...


๋ณด๋‹ค ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์„๊นŒ์š”?


๋ฐ‘์€ ์ฝ”๋“œ


import 'package:flame/components.dart'; import 'package:flame/flame.dart'; import 'package:flame/game.dart'; import 'package:flutter/material.dart' hide Image; import 'package:flutter/services.dart'; void main() { runApp(const App()); } class App extends StatelessWidget { const App({Key? key}) : super(key: key); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); return MaterialApp( routes: <String, WidgetBuilder>{ '/': (BuildContext context) { return Scaffold( body: Center( child: ElevatedButton( onPressed: () => Navigator.pushNamed(context, '/game'), child: const Text('Start'), )), ); }, '/game': (BuildContext context) { return const Scaffold( body: Center(child: GameScreen()), ); }, }, ); } } class GameScreen extends StatelessWidget { const GameScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return GameWidget(game: MyGame()); } } class MyGame extends FlameGame { final Grid grid = Grid(); final EndlessMap endlessMap = EndlessMap(); final Runner runner = Runner(); double speed = 100.0; @override Future<void>? onLoad() { add(grid); add(endlessMap); add(runner); return super.onLoad(); } } /// Camera follows the runner. class Runner extends PositionComponent with HasGameRef<MyGame> { @override Future<void>? onLoad() { gameRef.camera.followComponent(this); return super.onLoad(); } @override void update(double dt) { x += gameRef.speed * dt; super.update(dt); } } /// Set the size of tile and grid class Grid extends Component with HasGameRef<MyGame> { late int rows = 10; late int columns; late int mapColumns; late double tileSize; @override void onGameResize(Vector2 size) { tileSize = (size.y / rows).floorToDouble(); columns = (size.x / tileSize).ceil(); mapColumns = columns + 2; super.onGameResize(size); } } /// Generate terrains endlessly class EndlessMap extends PositionComponent with HasGameRef<MyGame> { late final Sprite terrainSprite; late final List<SpriteComponent> terrainSpritePool; int firstTerrainIndex = 0; // Init terrain sprite @override Future<void> onLoad() async { terrainSprite = Sprite( await Flame.images.load('terrains.png'), srcPosition: Vector2(4.0, 0.0), srcSize: Vector2(32.0, 32.0 * 10), ); terrainSpritePool = List.generate( gameRef.grid.mapColumns, (index) => SpriteComponent(sprite: terrainSprite), ); for (var i = 0; i < terrainSpritePool.length; i++) { terrainSpritePool[i].size.x = gameRef.grid.tileSize; terrainSpritePool[i].position = Vector2( i * gameRef.grid.tileSize, gameRef.grid.tileSize, ); add(terrainSpritePool[i]); } return super.onLoad(); } @override void update(double dt) { final dx = gameRef.speed * dt; final lastTerrainIndex = firstTerrainIndex == 0 ? terrainSpritePool.length - 1 : firstTerrainIndex - 1; // When the first terrain is behind the camera, if (terrainSpritePool[firstTerrainIndex].position.x + gameRef.grid.tileSize <= gameRef.camera.position.x + dx) { // Move the first terrain to the end terrainSpritePool[firstTerrainIndex].size.x = gameRef.grid.tileSize; terrainSpritePool[firstTerrainIndex].position = Vector2( terrainSpritePool[lastTerrainIndex].position.x + gameRef.grid.tileSize, gameRef.grid.tileSize, ); firstTerrainIndex = (firstTerrainIndex + 1) % terrainSpritePool.length; } super.update(dx); } }