diff --git a/assets/images/bug.png b/assets/images/bug.png deleted file mode 100644 index e1b091a..0000000 Binary files a/assets/images/bug.png and /dev/null differ diff --git a/assets/images/coin.png b/assets/images/coin.png deleted file mode 100644 index a247944..0000000 Binary files a/assets/images/coin.png and /dev/null differ diff --git a/assets/images/electrecuted-frames.png b/assets/images/electrocuted-frames.png similarity index 100% rename from assets/images/electrecuted-frames.png rename to assets/images/electrocuted-frames.png diff --git a/assets/images/hover-frames.png b/assets/images/hover-frames.png new file mode 100644 index 0000000..a391af9 Binary files /dev/null and b/assets/images/hover-frames.png differ diff --git a/assets/images/platform1.png b/assets/images/platform1.png deleted file mode 100644 index 04853c9..0000000 Binary files a/assets/images/platform1.png and /dev/null differ diff --git a/assets/images/platform2.png b/assets/images/platform2.png deleted file mode 100644 index ea6b3a4..0000000 Binary files a/assets/images/platform2.png and /dev/null differ diff --git a/assets/images/platform3.png b/assets/images/platform3.png deleted file mode 100644 index a30d4cf..0000000 Binary files a/assets/images/platform3.png and /dev/null differ diff --git a/assets/images/wire.png b/assets/images/wire.png deleted file mode 100644 index aa0979e..0000000 Binary files a/assets/images/wire.png and /dev/null differ diff --git a/lib/Coin.dart b/lib/Coin.dart index 332d69e..5adaab4 100644 --- a/lib/Coin.dart +++ b/lib/Coin.dart @@ -1,9 +1,6 @@ -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 CoinState { normal } @@ -26,6 +23,8 @@ class Coin extends MovingObject { current: CoinState.normal, ); + sprite.changePriorityWithoutResorting(COIN_PRIORITY); + var platform = gameRef.platformHolder.getPlatform(0); setSize( @@ -38,8 +37,7 @@ class Coin extends MovingObject { return sprite.position.x + sprite.width; } - @override - void render(Canvas c) { - getSprite().render(c, position: sprite.position, size: sprite.size); + void remove() { + sprite.remove(); } } diff --git a/lib/CoinHolder.dart b/lib/CoinHolder.dart index 43c3ffb..bec361d 100644 --- a/lib/CoinHolder.dart +++ b/lib/CoinHolder.dart @@ -1,12 +1,11 @@ import 'dart:math'; import 'package:flame/flame.dart'; -import 'package:flutter/material.dart'; import 'Coin.dart'; import 'main.dart'; -class Coinholder { +class CoinHolder { var coin; Random random = Random(); @@ -28,19 +27,17 @@ class Coinholder { return false; } double xCordinate = gameRef.platformHolder.getFlushX(); - // if (coins[level].isNotEmpty) { - // xCordinate = coins[level].last.getRightEnd(); - // } xCordinate = xCordinate + gameRef.blockSize * random.nextInt(5) + gameRef.blockSize * 20; - if (xCordinate < gameRef.size.x && random.nextInt(1000000) > 99999) { + if (xCordinate < gameRef.size.x || random.nextInt(100) > 10) { return true; } else { Coin coin = Coin(gameRef); coin.setPosition(xCordinate, gameRef.blockSize * level); coins[level].add(coin); + gameRef.add(coin.sprite); return false; } } @@ -53,14 +50,6 @@ class Coinholder { return total; } - void render(Canvas canvas) { - for (List coinLevel in coins) { - for (Coin p in coinLevel) { - p.render(canvas); - } - } - } - void update(double dt) { for (List coinLevel in coins) { for (Coin p in coinLevel) { @@ -73,6 +62,7 @@ class Coinholder { for (List coinLevel in coins) { for (int i = 0; i < coinLevel.length;) { if (coinLevel[i].sprite.x + coinLevel[i].sprite.width < 0) { + coinLevel[i].sprite.remove(); coinLevel.removeAt(i); continue; } diff --git a/lib/MovingObject.dart b/lib/MovingObject.dart index 77c49ea..fb40968 100644 --- a/lib/MovingObject.dart +++ b/lib/MovingObject.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:firo_runner/main.dart'; import 'package:flame/components.dart'; -class MovingObject extends Component { +class MovingObject { late SpriteAnimationGroupComponent sprite; MyGame gameRef; @@ -21,15 +21,7 @@ class MovingObject extends Component { 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); } @@ -37,17 +29,16 @@ class MovingObject extends Component { String intersect(Rect other) { final collision = sprite.toRect().intersect(other); if (!collision.isEmpty) { - // print(collision); - double ydistance = other.top - sprite.toRect().top; - double xdistance = other.left - sprite.toRect().left; - if (ydistance.abs() > xdistance.abs()) { - if (ydistance > 0) { + double yDistance = other.top - sprite.toRect().top; + double xDistance = other.left - sprite.toRect().left; + if (yDistance.abs() > xDistance.abs()) { + if (yDistance > 0) { return "bottom"; } else { return "top"; } } else { - if (xdistance > 0) { + if (xDistance > 0) { return "right"; } else { return "left"; diff --git a/lib/Platform.dart b/lib/Platform.dart index 6c03ae5..f4f2217 100644 --- a/lib/Platform.dart +++ b/lib/Platform.dart @@ -3,11 +3,12 @@ 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 { + var removeChildren = null; + Platform(MyGame gameRef) : super(gameRef) { var random = Random(); int version = random.nextInt(3) + 1; @@ -28,6 +29,8 @@ class Platform extends MovingObject { current: PlatformState.normal, ); + sprite.changePriorityWithoutResorting(PLATFORM_PRIORITY); + setSize( gameRef.blockSize * (platform!.width / platform!.height / 7), gameRef.blockSize, @@ -38,8 +41,9 @@ class Platform extends MovingObject { return sprite.position.x + sprite.width; } - @override - void render(Canvas c) { - getSprite().render(c, position: sprite.position, size: sprite.size); + void remove() { + if (removeChildren != null) { + removeChildren(); + } } } diff --git a/lib/PlatformHolder.dart b/lib/PlatformHolder.dart index db55fbe..6703150 100644 --- a/lib/PlatformHolder.dart +++ b/lib/PlatformHolder.dart @@ -2,7 +2,6 @@ import 'dart:math'; import 'package:firo_runner/main.dart'; import 'package:flame/flame.dart'; -import 'package:flutter/material.dart'; import 'Platform.dart'; class PlatformHolder { @@ -33,29 +32,22 @@ class PlatformHolder { } bool generatePlatform(MyGame gameRef, int level, bool force) { - double xCordinate = 0; + double xCoordinate = 0; if (platforms[level].isNotEmpty) { - xCordinate = platforms[level].last.getRightEnd(); + xCoordinate = platforms[level].last.getRightEnd(); } - if (xCordinate > gameRef.size.x + 1000) { + if (xCoordinate > gameRef.size.x + 1000) { return true; } else { Platform platform = Platform(gameRef); - platform.setPosition(xCordinate, gameRef.blockSize * level); + platform.setPosition(xCoordinate, gameRef.blockSize * level); + gameRef.add(platform.sprite); platforms[level].add(platform); 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) { @@ -70,6 +62,7 @@ class PlatformHolder { while (platformLevel.isNotEmpty && platformLevel[0].sprite.position.x + platformLevel[0].sprite.width < 0) { + platformLevel[0].sprite.remove(); platformLevel.removeAt(0); removed++; } @@ -81,7 +74,12 @@ class PlatformHolder { double secondToLastPosition = platformLevel.elementAt(secondToLast).sprite.x; if (secondToLastPosition > gameRef.size.x) { + platformLevel[secondToLast].remove(); + platformLevel[secondToLast].sprite.remove(); platformLevel.removeAt(secondToLast); + + platformLevel[secondToLast + 1].remove(); + platformLevel[secondToLast + 1].sprite.remove(); platformLevel.removeAt(secondToLast + 1); } } @@ -98,4 +96,15 @@ class PlatformHolder { }); return platform.sprite.x; } + + Platform? getPlatformOffScreen(int level) { + for (int i = 0; i < platforms[level].length; i++) { + Platform p = platforms[level][i]; + if (p.sprite.x > p.gameRef.size.x) { + int chosenIndex = random.nextInt(platforms[level].length - i) + i; + return platforms[level][chosenIndex]; + } + } + return null; + } } diff --git a/lib/Runner.dart b/lib/Runner.dart index bdbc3c7..64cd5c9 100644 --- a/lib/Runner.dart +++ b/lib/Runner.dart @@ -1,4 +1,5 @@ import 'package:firo_runner/Coin.dart'; +import 'package:firo_runner/Wire.dart'; import 'package:firo_runner/main.dart'; import 'package:flame/effects.dart'; import 'package:flutter/material.dart'; @@ -72,17 +73,16 @@ class Runner extends Component with HasGameRef { break; } runnerState = event; - sprite.current = RunnerState.jump; + sprite.current = RunnerState.float; sprite.addEffect(MoveEffect( path: [ - sprite.position, Vector2(sprite.x, (level - 2) * gameRef.blockSize), ], - speed: 50, + speed: 100, curve: Curves.ease, onComplete: () { updateLevel(); - runnerState = "run"; + this.event("float"); }, )); break; @@ -96,13 +96,8 @@ class Runner extends Component with HasGameRef { speed: 100, curve: Curves.ease, onComplete: () { - if (runnerState == "fall") { - updateLevel(); - sprite.position = Vector2(sprite.x, level * gameRef.blockSize); - this.event("run"); - } else { - this.event("float"); - } + updateLevel(); + this.event("float"); }, )); break; @@ -119,7 +114,7 @@ class Runner extends Component with HasGameRef { sprite.current = RunnerState.float; sprite.addEffect(MoveEffect( path: [sprite.position], - speed: 50, + speed: 500, curve: Curves.ease, onComplete: () { updateLevel(); @@ -227,8 +222,8 @@ class Runner extends Component with HasGameRef { onTopOfPlatform = true; } } else if (side == "bottom") { - // The runner has hit his head on the ceiling and should die. event("die"); + return; } } } @@ -237,6 +232,7 @@ class Runner extends Component with HasGameRef { for (int i = 0; i < coinLevel.length;) { if (coinLevel[i].intersect(runnerRect) != "none") { gameRef.gameState.numCoins++; + coinLevel[i].remove(); coinLevel.removeAt(i); print(gameRef.gameState.numCoins); continue; @@ -245,6 +241,14 @@ class Runner extends Component with HasGameRef { } } + for (List wireLevel in gameRef.wireHolder.wires) { + for (int i = 0; i < wireLevel.length; i++) { + if (wireLevel[i].intersect(runnerRect) != "none") { + event("electro"); + } + } + } + if (!onTopOfPlatform && (runnerState == "run" || runnerState == "kick" || @@ -293,24 +297,24 @@ class Runner extends Component with HasGameRef { ); SpriteAnimation floating = await loadSpriteAnimation( - 'run-frames.png', + 'hover-frames.png', SpriteAnimationData.sequenced( - amount: 1, + amount: 3, stepTime: 0.1, textureSize: Vector2(512, 512), ), ); SpriteAnimation falling = await loadSpriteAnimation( - 'run-frames.png', + 'hover-frames.png', SpriteAnimationData.sequenced( - amount: 1, + amount: 3, stepTime: 0.1, textureSize: Vector2(512, 512), ), ); - SpriteAnimation dieing = await loadSpriteAnimation( + SpriteAnimation dying = await loadSpriteAnimation( 'death-normal-frames.png', SpriteAnimationData.sequenced( amount: 20, @@ -320,8 +324,8 @@ class Runner extends Component with HasGameRef { ), ); - SpriteAnimation dieingElectorcuted = await loadSpriteAnimation( - 'electrecuted-frames.png', + SpriteAnimation dyingElectrocuted = await loadSpriteAnimation( + 'electrocuted-frames.png', SpriteAnimationData.sequenced( amount: 2, stepTime: 0.1, @@ -337,10 +341,12 @@ class Runner extends Component with HasGameRef { RunnerState.kick: kicking, RunnerState.float: floating, RunnerState.fall: falling, - RunnerState.die: dieing, - RunnerState.electro: dieingElectorcuted, + RunnerState.die: dying, + RunnerState.electro: dyingElectrocuted, }, current: RunnerState.run, ); + + changePriorityWithoutResorting(RUNNER_PRIORITY); } } diff --git a/lib/Wire.dart b/lib/Wire.dart new file mode 100644 index 0000000..5de2fe2 --- /dev/null +++ b/lib/Wire.dart @@ -0,0 +1,41 @@ +import 'package:firo_runner/MovingObject.dart'; +import 'package:firo_runner/main.dart'; +import 'package:flame/components.dart'; + +enum WireState { normal } + +class Wire extends MovingObject { + Wire(MyGame gameRef) : super(gameRef) { + var wire = gameRef.wireHolder.getWire(); + SpriteAnimation normal = SpriteAnimation.fromFrameData( + wire, + SpriteAnimationData.sequenced( + amount: 6, + stepTime: 0.1, + textureSize: Vector2(512, 512), + ), + ); + + sprite = SpriteAnimationGroupComponent( + animations: { + WireState.normal: normal, + }, + current: WireState.normal, + ); + + sprite.changePriorityWithoutResorting(WIRE_PRIORITY); + + setSize( + gameRef.blockSize, + gameRef.blockSize, + ); + } + + double getRightEnd() { + return sprite.position.x + sprite.width; + } + + void remove() { + sprite.remove(); + } +} diff --git a/lib/WireHolder.dart b/lib/WireHolder.dart new file mode 100644 index 0000000..9c5e0b7 --- /dev/null +++ b/lib/WireHolder.dart @@ -0,0 +1,103 @@ +import 'dart:math'; + +import 'package:firo_runner/Platform.dart'; +import 'package:flame/flame.dart'; + +import 'Wire.dart'; +import 'main.dart'; + +class WireHolder { + var wire; + Random random = Random(); + + late List> wires = []; + + Future loadWires() async { + wire = await Flame.images.load("wire-frames.png"); + for (int i = 0; i < 9; i++) { + wires.add([]); + } + } + + getWire() { + return wire; + } + + bool generateWire(MyGame gameRef, int level, bool force) { + if (wires[level].isNotEmpty) { + return false; + } + + if (random.nextInt(100) > 100) { + return true; + } else { + int nearestPlatform = level <= 0 + ? 0 + : level <= 3 + ? 2 + : level <= 6 + ? 5 + : 8; + + Platform? platform = + gameRef.platformHolder.getPlatformOffScreen(nearestPlatform); + double xCoordinate = -100; + + if (level == 0) { + xCoordinate = gameRef.size.x; + } else if (platform != null) { + xCoordinate = platform.sprite.x; + } else { + return false; + } + + Wire wire = Wire(gameRef); + if (level % 3 == 0) { + wire.sprite.renderFlipY = true; + wire.setPosition( + xCoordinate, gameRef.blockSize * level - gameRef.blockSize / 6); + } else { + wire.setPosition( + xCoordinate, gameRef.blockSize * level + gameRef.blockSize / 10); + } + wires[level].add(wire); + gameRef.add(wire.sprite); + if (platform != null) { + platform.removeChildren = () { + wires[level].remove(wire); + wire.remove(); + }; + } + return false; + } + } + + int totalWires() { + int total = 0; + for (List levelWires in wires) { + total += levelWires.length; + } + return total; + } + + void update(double dt) { + for (List wireLevel in wires) { + for (Wire p in wireLevel) { + p.update(dt); + } + } + } + + void removePast(MyGame gameRef) { + for (List wireLevel in wires) { + for (int i = 0; i < wireLevel.length;) { + if (wireLevel[i].sprite.x + wireLevel[i].sprite.width < 0) { + wireLevel[i].sprite.remove(); + wireLevel.removeAt(i); + continue; + } + i++; + } + } + } +} diff --git a/lib/main.dart b/lib/main.dart index 0b7fc95..404d166 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,26 +2,27 @@ import 'dart:math'; import 'package:firo_runner/CoinHolder.dart'; import 'package:firo_runner/GameState.dart'; -import 'package:firo_runner/MovingObject.dart'; -import 'package:firo_runner/Platform.dart'; import 'package:firo_runner/PlatformHolder.dart'; +import 'package:firo_runner/Wire.dart'; +import 'package:firo_runner/WireHolder.dart'; import 'package:flame/components.dart'; import 'package:flame/extensions.dart'; import 'package:flame/flame.dart'; import 'package:flame/game.dart'; import 'package:flame/gestures.dart'; import 'package:flame/keyboard.dart'; -import 'package:flame/palette.dart'; import 'package:flame_audio/flame_audio.dart'; import 'package:flutter/material.dart'; -import 'package:flame_audio/bgm.dart'; import 'package:flutter/services.dart'; import 'Runner.dart'; const COLOR = const Color(0xFFDDC0A3); -const SIZE = 52.0; -const GRAVITY = 400.0; -const BOOST = -380.0; + +const RUNNER_PRIORITY = 100; +const PLATFORM_PRIORITY = 50; +const WIRE_PRIORITY = 25; +const COIN_PRIORITY = 70; +const BUG_PRIORITY = 75; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -37,7 +38,8 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { ); late PlatformHolder platformHolder; - late Coinholder coinHolder; + late CoinHolder coinHolder; + late WireHolder wireHolder; Random random = Random(); late Sprite background1; @@ -45,12 +47,6 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { late Runner runner; late GameState gameState; var background; - late var platform1; - late var platform2; - late var platform3; - late var wire; - late var bug; - late var coin; var runnerPosition = Vector2(0, 0); var runnerSize; @@ -60,25 +56,22 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { late double blockSize; bool loaded = false; + late Wire wire; @override Future onLoad() async { - debugMode = true; + // debugMode = true; FlameAudio.bgm.initialize(); background = await Flame.images.load('bg.png'); background1 = Sprite(background); background2 = Sprite(background); - platform1 = await Flame.images.load('platform1.png'); - platform2 = await Flame.images.load('platform2.png'); - platform3 = await Flame.images.load('platform3.png'); - wire = await Flame.images.load('wire.png'); - bug = await Flame.images.load('bug.png'); - coin = await Flame.images.load('coin.png'); platformHolder = PlatformHolder(); await platformHolder.loadPlatforms(); - coinHolder = Coinholder(); + coinHolder = CoinHolder(); await coinHolder.loadCoins(); + wireHolder = WireHolder(); + await wireHolder.loadWires(); gameState = GameState(); await gameState.load(size); @@ -102,9 +95,14 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { void fillScreen() { for (int i = 2; i < 9; i = i + 3) { - while (!platformHolder.generatePlatform(this, i, false)); + while (!platformHolder.generatePlatform(this, i, false)) {} } - int choseCoinLevel = random.nextInt(9); + int wireChosenRegion = random.nextInt(8) + 1; + if (wireChosenRegion % 3 != 2) { + wireHolder.generateWire(this, wireChosenRegion, false); + } + + int choseCoinLevel = random.nextInt(8) + 1; if (choseCoinLevel % 3 != 2) { coinHolder.generateCoin(this, choseCoinLevel, false); } @@ -119,8 +117,6 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { size: Vector2(size.y * (background!.width / background!.height), size.y), ); super.render(canvas); - platformHolder.render(canvas); - coinHolder.render(canvas); final fpsCount = fps(1); textPaint.render( canvas, @@ -133,11 +129,13 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { void update(double dt) { platformHolder.removePast(this); coinHolder.removePast(this); + wireHolder.removePast(this); fillScreen(); super.update(dt); gameState.update(dt); platformHolder.update(dt); coinHolder.update(dt); + wireHolder.update(dt); } @override @@ -157,36 +155,36 @@ class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { } // Mobile controls - late List xdeltas; - late List ydeltas; + late List xDeltas; + late List yDeltas; @override void onPanStart(DragStartInfo info) { - xdeltas = List.empty(growable: true); - ydeltas = List.empty(growable: true); + xDeltas = List.empty(growable: true); + yDeltas = List.empty(growable: true); } @override void onPanUpdate(DragUpdateInfo info) { - xdeltas.add(info.delta.game.x); - ydeltas.add(info.delta.game.y); + xDeltas.add(info.delta.game.x); + yDeltas.add(info.delta.game.y); } @override void onPanEnd(DragEndInfo info) { - double xdelta = xdeltas.isEmpty + double xDelta = xDeltas.isEmpty ? 0 - : xdeltas.reduce((value, element) => value + element); - double ydelta = ydeltas.isEmpty + : xDeltas.reduce((value, element) => value + element); + double yDelta = yDeltas.isEmpty ? 0 - : ydeltas.reduce((value, element) => value + element); - if (xdelta.abs() > ydelta.abs()) { - if (xdelta > 0) { + : yDeltas.reduce((value, element) => value + element); + if (xDelta.abs() > yDelta.abs()) { + if (xDelta > 0) { runner.control("right"); } else { runner.control("left"); } - } else if (xdelta.abs() < ydelta.abs()) { - if (ydelta > 0) { + } else if (xDelta.abs() < yDelta.abs()) { + if (yDelta > 0) { runner.control("down"); } else { runner.control("up");