diff --git a/assets/images/bug-break-frames.png b/assets/images/bug-break-frames.png new file mode 100644 index 0000000..a10bf97 Binary files /dev/null and b/assets/images/bug-break-frames.png differ diff --git a/assets/images/bug-frames.png b/assets/images/bug-frames.png new file mode 100644 index 0000000..33a77a6 Binary files /dev/null and b/assets/images/bug-frames.png differ diff --git a/assets/images/p1-frames.png b/assets/images/p1-frames.png new file mode 100644 index 0000000..551945d Binary files /dev/null and b/assets/images/p1-frames.png differ diff --git a/assets/images/p2-frames.png b/assets/images/p2-frames.png new file mode 100644 index 0000000..0710d46 Binary files /dev/null and b/assets/images/p2-frames.png differ diff --git a/assets/images/p3-frames.png b/assets/images/p3-frames.png new file mode 100644 index 0000000..b2a2f39 Binary files /dev/null and b/assets/images/p3-frames.png differ diff --git a/assets/images/wire-frames.png b/assets/images/wire-frames.png new file mode 100644 index 0000000..66fc018 Binary files /dev/null and b/assets/images/wire-frames.png differ diff --git a/lib/GameState.dart b/lib/GameState.dart new file mode 100644 index 0000000..a7b7055 --- /dev/null +++ b/lib/GameState.dart @@ -0,0 +1,55 @@ +import 'dart:math'; + +import 'package:flame/components.dart'; +import 'package:flutter/material.dart'; + +class GameState extends Component { + int numCoins = 0; + int distance = 0; + late Rect square; + late Color color = Colors.white; + int start = 0; + late ColorTween tween; + static const int CIRCUIT_PERIOD = 500000; + + @override + void update(double dt) { + super.update(dt); + distance = DateTime.now().microsecondsSinceEpoch - start; + color = tween.lerp(sin(distance.toDouble() / CIRCUIT_PERIOD))!; + } + + void addCoin() { + numCoins++; + } + + @override + void render(Canvas c) { + super.render(c); + c.drawRect(square, Paint()..color = color); + } + + Future load(Vector2 size) async { + square = Rect.fromLTWH(0, 0, size.x, size.y); + reset(); + } + + void setSize(Vector2 size) { + square = Rect.fromLTWH(0, 0, size.x, size.y); + } + + void reset() { + start = DateTime.now().microsecondsSinceEpoch; + tween = ColorTween(begin: Colors.yellow, end: Colors.yellowAccent); + } + + double getVelocity() { + if (distance > 50000000) { + return 250.0; + } else if (distance > 10000000) + return 175.0; + else { + return 100.0; + } + } +} diff --git a/lib/MovingObject.dart b/lib/MovingObject.dart new file mode 100644 index 0000000..0be3593 --- /dev/null +++ b/lib/MovingObject.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +import 'package:firo_runner/main.dart'; +import 'package:flame/components.dart'; + +class MovingObject extends Component { + late SpriteAnimationGroupComponent sprite; + MyGame gameRef; + + MovingObject(this.gameRef); + + void setPosition(double x, double y) { + sprite.position = Vector2(x, y); + } + + void setSize(double x, double y) { + sprite.size = Vector2(x, y); + } + + Sprite getSprite() { + return sprite.animation!.getSprite(); + } + + @override + void render(Canvas c) { + super.render(c); + } + + @override + void update(double dt) { + super.update(dt); + sprite.update(dt); + double velocity = gameRef.gameState.getVelocity(); + sprite.position = sprite.position - Vector2(velocity * dt, 0); + } + + @override + void remove() { + super.remove(); + } +} diff --git a/lib/Platform.dart b/lib/Platform.dart new file mode 100644 index 0000000..6c03ae5 --- /dev/null +++ b/lib/Platform.dart @@ -0,0 +1,45 @@ +import 'dart:math'; + +import 'package:firo_runner/MovingObject.dart'; +import 'package:firo_runner/main.dart'; +import 'package:flame/components.dart'; +import 'package:flutter/material.dart'; + +enum PlatformState { normal } + +class Platform extends MovingObject { + Platform(MyGame gameRef) : super(gameRef) { + var random = Random(); + int version = random.nextInt(3) + 1; + var platform = gameRef.platformHolder.getPlatform(version); + SpriteAnimation normal = SpriteAnimation.fromFrameData( + platform, + SpriteAnimationData.sequenced( + amount: 7, + stepTime: 0.1, + textureSize: Vector2(800, 510), + ), + ); + + sprite = SpriteAnimationGroupComponent( + animations: { + PlatformState.normal: normal, + }, + current: PlatformState.normal, + ); + + setSize( + gameRef.blockSize * (platform!.width / platform!.height / 7), + gameRef.blockSize, + ); + } + + double getRightEnd() { + return sprite.position.x + sprite.width; + } + + @override + void render(Canvas c) { + getSprite().render(c, position: sprite.position, size: sprite.size); + } +} diff --git a/lib/PlatformLoader.dart b/lib/PlatformLoader.dart new file mode 100644 index 0000000..0adc630 --- /dev/null +++ b/lib/PlatformLoader.dart @@ -0,0 +1,91 @@ +import 'dart:math'; + +import 'package:firo_runner/main.dart'; +import 'package:flame/flame.dart'; +import 'package:flutter/material.dart'; +import 'Platform.dart'; + +class PlatformHolder { + var platform1; + var platform2; + var platform3; + late List> platforms = []; + Random random = Random(); + + Future loadPlatforms() async { + platform1 = await Flame.images.load('p1-frames.png'); + platform2 = await Flame.images.load('p2-frames.png'); + platform3 = await Flame.images.load('p3-frames.png'); + for (int i = 0; i < 9; i++) { + platforms.add([]); + } + } + + getPlatform(int imageNumber) { + switch (imageNumber) { + case 1: + return platform1; + case 2: + return platform2; + default: + return platform3; + } + } + + bool generatePlatform(MyGame gameRef, int level, bool force) { + double xCordinate = 0; + if (platforms[level].isNotEmpty) { + xCordinate = platforms[level].last.getRightEnd(); + } + + if (xCordinate > gameRef.size.x + 1000) { + return true; + } else { + Platform platform = Platform(gameRef); + platform.setPosition(xCordinate, gameRef.blockSize * level); + platforms[level].add(platform); + print(platforms[0].length); + return false; + } + } + + void render(Canvas canvas) { + for (List platformLevel in platforms) { + for (Platform p in platformLevel) { + p.render(canvas); + } + } + } + + void update(double dt) { + for (List platformLevel in platforms) { + for (Platform p in platformLevel) { + p.update(dt); + } + } + } + + void removePast(MyGame gameRef) { + for (List platformLevel in platforms) { + int removed = 0; + while (platformLevel.isNotEmpty && + platformLevel[0].sprite.position.x + platformLevel[0].sprite.width < + 0) { + platformLevel.removeAt(0); + removed++; + } + if (platformLevel.isNotEmpty && + platformLevel.length > 3 && + random.nextInt(100) > 65 && + removed > 0) { + int secondToLast = platformLevel.length - 3; + double secondToLastPosition = + platformLevel.elementAt(secondToLast).sprite.x; + if (secondToLastPosition > gameRef.size.x) { + platformLevel.removeAt(secondToLast); + platformLevel.removeAt(secondToLast + 1); + } + } + } + } +} diff --git a/lib/Runner.dart b/lib/Runner.dart index 9641164..ed897cf 100644 --- a/lib/Runner.dart +++ b/lib/Runner.dart @@ -70,10 +70,10 @@ class Runner extends Component with HasGameRef { sprite.addEffect(MoveEffect( path: [ sprite.position, - Vector2(sprite.x, (level - 2) * gameRef.blockSize), + Vector2(sprite.x, (level - 3) * gameRef.blockSize), ], speed: 50, - curve: Curves.bounceIn, + curve: Curves.ease, onComplete: () { updateLevel(); runnerState = "run"; @@ -245,7 +245,7 @@ class Runner extends Component with HasGameRef { 'death-normal-frames.png', SpriteAnimationData.sequenced( amount: 20, - stepTime: 0.1, + stepTime: 0.05, textureSize: Vector2(512, 512), loop: false, ), diff --git a/lib/main.dart b/lib/main.dart index 8c7649a..b94326a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,7 @@ +import 'package:firo_runner/GameState.dart'; +import 'package:firo_runner/MovingObject.dart'; +import 'package:firo_runner/Platform.dart'; +import 'package:firo_runner/PlatformLoader.dart'; import 'package:flame/components.dart'; import 'package:flame/extensions.dart'; import 'package:flame/flame.dart'; @@ -29,10 +33,13 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { config: TextPaintConfig(fontSize: 48.0), ); + late PlatformHolder platformHolder; + late Sprite background1; late Sprite background2; late Runner runner; - late var background; + late GameState gameState; + var background; late var platform1; late var platform2; late var platform3; @@ -47,12 +54,16 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { var background2Position; late double blockSize; + bool loaded = false; + @override Future onLoad() async { + debugMode = true; print("load"); FlameAudio.bgm.initialize(); background = await Flame.images.load('bg.png'); background1 = Sprite(background); + print(background.height.toString() + " " + background.width.toString()); background2 = Sprite(background); platform1 = await Flame.images.load('platform1.png'); platform2 = await Flame.images.load('platform2.png'); @@ -61,6 +72,12 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { bug = await Flame.images.load('bug.png'); coin = await Flame.images.load('coin.png'); + platformHolder = PlatformHolder(); + await platformHolder.loadPlatforms(); + + gameState = GameState(); + await gameState.load(size); + runner = Runner(); await runner.load(loadSpriteAnimation); runner.setSize(runnerSize, blockSize); @@ -68,28 +85,48 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { runner.setPosition(runnerPosition); add(runner); + // Generate the first 4 Platforms that will always be there at the start. + for (int i = 0; i < 4; i++) { + platformHolder.generatePlatform(this, 8, true); + } + fillScreen(); + FlameAudio.bgm.play('Infinite_Spankage_M.mp3'); + loaded = true; + } + + void fillScreen() { + for (int i = 2; i < 9; i = i + 3) { + while (!platformHolder.generatePlatform(this, i, false)); + } } @override void render(Canvas canvas) { + gameState.render(canvas); background1.render( canvas, position: Vector2(0, 0), - size: backgroundSize, + size: Vector2(size.y * (background!.width / background!.height), size.y), ); super.render(canvas); + platformHolder.render(canvas); final fpsCount = fps(1); - // textPaint.render( - // canvas, - // fpsCount.toString(), - // Vector2(0, 0), - // ); + textPaint.render( + canvas, + fpsCount.toString(), + Vector2(0, 0), + ); } @override void update(double dt) { + platformHolder.removePast(this); + fillScreen(); super.update(dt); + gameState.update(dt); + platformHolder.update(dt); + // print(gameState.distance); } @override @@ -102,7 +139,11 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { size.y / 9, ); - backgroundSize = Vector2(size.x * 2, size.y); + if (loaded) { + backgroundSize = + Vector2(size.y * (background!.width / background!.height), size.y); + gameState.setSize(size); + } } // Mobile controls