diff --git a/assets/images/button.png b/assets/images/button.png index a4ad799..22ee8d5 100644 Binary files a/assets/images/button.png and b/assets/images/button.png differ diff --git a/lib/circuit_background.dart b/lib/circuit_background.dart index b9d178e..661713a 100644 --- a/lib/circuit_background.dart +++ b/lib/circuit_background.dart @@ -1,396 +1,396 @@ -import 'package:firo_runner/moving_object.dart'; -import 'package:firo_runner/main.dart'; -import 'package:flame/components.dart'; -import 'package:flame/flame.dart'; -import 'package:flame/extensions.dart'; - -enum WindowState { - first, - second, - third, - fourth, - fifth, - sixth, - seventh, -} - -enum OverlayState { - first, - second, - third, - fourth, - fifth, - sixth, - seventh, -} - -class CircuitBackground extends MovingObject { - late Image background; - - late Image overlay0; - late Image overlay1; - late Image overlay2; - late Image overlay3; - late Image overlay4; - late Image overlay5; - late Image overlay6; - - late Image windows0; - late Image windows1; - late Image windows2; - late Image windows3; - late Image windows4; - late Image windows5; - late Image windows6; - - late Sprite background1; - late Sprite background2; - late SpriteAnimationGroupComponent windowA; - late SpriteAnimationGroupComponent windowB; - late SpriteAnimationGroupComponent overlayA; - late SpriteAnimationGroupComponent overlayB; - Vector2 background1Size = Vector2(0, 0); - Vector2 background2Size = Vector2(0, 0); - Vector2 background1Position = Vector2(0, 0); - Vector2 background2Position = Vector2(0, 0); - - CircuitBackground(MyGame gameRef) : super(gameRef); - - Future load() async { - background = await Flame.images.load("bg.png"); - background1 = Sprite(background); - background2 = Sprite(background); - - overlay0 = await Flame.images.load("overlay100.png"); - overlay1 = await Flame.images.load("overlay90.png"); - overlay2 = await Flame.images.load("overlay80.png"); - overlay3 = await Flame.images.load("overlay70.png"); - overlay4 = await Flame.images.load("overlay60.png"); - overlay5 = await Flame.images.load("overlay50.png"); - overlay6 = await Flame.images.load("overlay40.png"); - - SpriteAnimation firstOverlay = SpriteAnimation.fromFrameData( - overlay0, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation secondOverlay = SpriteAnimation.fromFrameData( - overlay1, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation thirdOverlay = SpriteAnimation.fromFrameData( - overlay2, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation fourthOverlay = SpriteAnimation.fromFrameData( - overlay3, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation fifthOverlay = SpriteAnimation.fromFrameData( - overlay4, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation sixthOverlay = SpriteAnimation.fromFrameData( - overlay5, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation seventhOverlay = SpriteAnimation.fromFrameData( - overlay6, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - overlayA = SpriteAnimationGroupComponent( - animations: { - OverlayState.first: firstOverlay, - OverlayState.second: secondOverlay, - OverlayState.third: thirdOverlay, - OverlayState.fourth: fourthOverlay, - OverlayState.fifth: fifthOverlay, - OverlayState.sixth: sixthOverlay, - OverlayState.seventh: seventhOverlay, - }, - current: OverlayState.first, - ); - - overlayB = SpriteAnimationGroupComponent( - animations: { - OverlayState.first: firstOverlay, - OverlayState.second: secondOverlay, - OverlayState.third: thirdOverlay, - OverlayState.fourth: fourthOverlay, - OverlayState.fifth: fifthOverlay, - OverlayState.sixth: sixthOverlay, - OverlayState.seventh: seventhOverlay, - }, - current: OverlayState.first, - ); - - overlayA.changePriorityWithoutResorting(WINDOW_PRIORITY - 1); - - overlayA.changePriorityWithoutResorting(WINDOW_PRIORITY - 1); - - windows0 = await Flame.images.load("windows-0.png"); - windows1 = await Flame.images.load("windows-1.png"); - windows2 = await Flame.images.load("windows-2.png"); - windows3 = await Flame.images.load("windows-3.png"); - windows4 = await Flame.images.load("windows-4.png"); - windows5 = await Flame.images.load("windows-5.png"); - windows6 = await Flame.images.load("windows-6.png"); - - SpriteAnimation firstWindow = SpriteAnimation.fromFrameData( - windows0, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation secondWindow = SpriteAnimation.fromFrameData( - windows1, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation thirdWindow = SpriteAnimation.fromFrameData( - windows2, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation fourthWindow = SpriteAnimation.fromFrameData( - windows3, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation fifthWindow = SpriteAnimation.fromFrameData( - windows4, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation sixthWindow = SpriteAnimation.fromFrameData( - windows5, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - SpriteAnimation seventhWindow = SpriteAnimation.fromFrameData( - windows6, - SpriteAnimationData.sequenced( - amount: 1, - stepTime: 1, - textureSize: Vector2(2048, 683), - loop: false)); - - windowA = SpriteAnimationGroupComponent( - animations: { - WindowState.first: firstWindow, - WindowState.second: secondWindow, - WindowState.third: thirdWindow, - WindowState.fourth: fourthWindow, - WindowState.fifth: fifthWindow, - WindowState.sixth: sixthWindow, - WindowState.seventh: seventhWindow, - }, - current: WindowState.first, - ); - - windowB = SpriteAnimationGroupComponent( - animations: { - WindowState.first: firstWindow, - WindowState.second: secondWindow, - WindowState.third: thirdWindow, - WindowState.fourth: fourthWindow, - WindowState.fifth: fifthWindow, - WindowState.sixth: sixthWindow, - WindowState.seventh: seventhWindow, - }, - current: WindowState.first, - ); - - windowA.changePriorityWithoutResorting(WINDOW_PRIORITY); - - windowA.changePriorityWithoutResorting(WINDOW_PRIORITY); - - setUp(); - } - - void setUp() { - windowA.current = WindowState.first; - windowB.current = WindowState.first; - overlayA.current = OverlayState.first; - overlayB.current = OverlayState.first; - background1Position = Vector2(0, 0); - background1Size = Vector2( - gameRef.viewport.canvasSize.y * (background.width / background.height), - gameRef.viewport.canvasSize.y); - windowA.position = background1Position; - windowA.size = background1Size; - overlayA.position = background1Position; - overlayA.size = background1Size; - - background2Position = - Vector2(background1Position.x + background1Size.x - 1, 0); - background2Size = Vector2( - gameRef.viewport.canvasSize.y * (background.width / background.height), - gameRef.viewport.canvasSize.y); - windowB.position = background2Position; - windowB.size = background2Size; - overlayB.position = background2Position; - overlayB.size = background2Size; - } - - @override - void update(double dt) { - switch (gameRef.gameState.getScoreLevel()) { - case 12: - windowA.current = WindowState.seventh; - windowB.current = WindowState.seventh; - break; - case 11: - overlayA.current = OverlayState.seventh; - overlayB.current = OverlayState.seventh; - break; - case 10: - windowA.current = WindowState.sixth; - windowB.current = WindowState.sixth; - break; - case 9: - overlayA.current = OverlayState.sixth; - overlayB.current = OverlayState.sixth; - break; - case 8: - windowA.current = WindowState.fifth; - windowB.current = WindowState.fifth; - break; - case 7: - overlayA.current = OverlayState.fifth; - overlayB.current = OverlayState.fifth; - break; - case 6: - windowA.current = WindowState.fourth; - windowB.current = WindowState.fourth; - break; - case 5: - overlayA.current = OverlayState.fourth; - overlayB.current = OverlayState.fourth; - break; - case 4: - windowA.current = WindowState.third; - windowB.current = WindowState.third; - break; - case 3: - overlayA.current = OverlayState.third; - overlayB.current = OverlayState.third; - break; - case 2: - windowA.current = WindowState.second; - windowB.current = WindowState.second; - break; - case 1: - overlayA.current = OverlayState.second; - overlayB.current = OverlayState.second; - break; - default: - windowA.current = WindowState.first; - windowB.current = WindowState.first; - overlayA.current = OverlayState.first; - overlayB.current = OverlayState.first; - break; - } - windowA.update(dt); - windowB.update(dt); - overlayA.update(dt); - overlayB.update(dt); - if (background1Position.x + background1Size.x < 0) { - double newPosition = background2Position.x + background2Size.x; - background1Position = Vector2(newPosition - 1, 0); - } else if (background2Position.x + background2Size.x < 0) { - double newPosition = background1Position.x + background1Size.x; - background2Position = Vector2(newPosition - 1, 0); - } - - double velocity = gameRef.gameState.getVelocity() / 10.0; - background1Position = background1Position - Vector2(velocity * dt, 0); - windowA.position = background1Position; - overlayA.position = background1Position; - background2Position = background2Position - Vector2(velocity * dt, 0); - windowB.position = background2Position; - overlayB.position = background2Position; - } - - void render(Canvas canvas) { - background1.render(canvas, - size: background1Size, position: background1Position); - canvas.save(); - overlayA.render(canvas); - canvas.restore(); - canvas.save(); - windowA.render(canvas); - canvas.restore(); - background2.render(canvas, - size: background2Size, position: background2Position); - canvas.save(); - overlayB.render(canvas); - canvas.restore(); - canvas.save(); - windowB.render(canvas); - canvas.restore(); - } - - @override - void resize(Vector2 newSize, double xRatio, double yRatio) { - background1Size = - Vector2(newSize.y * (background.width / background.height), newSize.y); - windowA.position = background1Position; - windowA.size = background1Size; - overlayA.position = background1Position; - overlayA.size = background1Size; - - background2Position = - Vector2(background1Position.x + background1Size.x - 1, 0); - background2Size = - Vector2(newSize.y * (background.width / background.height), newSize.y); - windowB.position = background2Position; - windowB.size = background2Size; - overlayB.position = background2Position; - overlayB.size = background2Size; - } -} +import 'package:firo_runner/moving_object.dart'; +import 'package:firo_runner/main.dart'; +import 'package:flame/components.dart'; +import 'package:flame/flame.dart'; +import 'package:flame/extensions.dart'; + +enum WindowState { + first, + second, + third, + fourth, + fifth, + sixth, + seventh, +} + +enum OverlayState { + first, + second, + third, + fourth, + fifth, + sixth, + seventh, +} + +class CircuitBackground extends MovingObject { + late Image background; + + late Image overlay0; + late Image overlay1; + late Image overlay2; + late Image overlay3; + late Image overlay4; + late Image overlay5; + late Image overlay6; + + late Image windows0; + late Image windows1; + late Image windows2; + late Image windows3; + late Image windows4; + late Image windows5; + late Image windows6; + + late Sprite background1; + late Sprite background2; + late SpriteAnimationGroupComponent windowA; + late SpriteAnimationGroupComponent windowB; + late SpriteAnimationGroupComponent overlayA; + late SpriteAnimationGroupComponent overlayB; + Vector2 background1Size = Vector2(0, 0); + Vector2 background2Size = Vector2(0, 0); + Vector2 background1Position = Vector2(0, 0); + Vector2 background2Position = Vector2(0, 0); + + CircuitBackground(MyGame gameRef) : super(gameRef); + + Future load() async { + background = await Flame.images.load("bg.png"); + background1 = Sprite(background); + background2 = Sprite(background); + + overlay0 = await Flame.images.load("overlay100.png"); + overlay1 = await Flame.images.load("overlay90.png"); + overlay2 = await Flame.images.load("overlay80.png"); + overlay3 = await Flame.images.load("overlay70.png"); + overlay4 = await Flame.images.load("overlay60.png"); + overlay5 = await Flame.images.load("overlay50.png"); + overlay6 = await Flame.images.load("overlay40.png"); + + SpriteAnimation firstOverlay = SpriteAnimation.fromFrameData( + overlay0, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation secondOverlay = SpriteAnimation.fromFrameData( + overlay1, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation thirdOverlay = SpriteAnimation.fromFrameData( + overlay2, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation fourthOverlay = SpriteAnimation.fromFrameData( + overlay3, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation fifthOverlay = SpriteAnimation.fromFrameData( + overlay4, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation sixthOverlay = SpriteAnimation.fromFrameData( + overlay5, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation seventhOverlay = SpriteAnimation.fromFrameData( + overlay6, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + overlayA = SpriteAnimationGroupComponent( + animations: { + OverlayState.first: firstOverlay, + OverlayState.second: secondOverlay, + OverlayState.third: thirdOverlay, + OverlayState.fourth: fourthOverlay, + OverlayState.fifth: fifthOverlay, + OverlayState.sixth: sixthOverlay, + OverlayState.seventh: seventhOverlay, + }, + current: OverlayState.first, + ); + + overlayB = SpriteAnimationGroupComponent( + animations: { + OverlayState.first: firstOverlay, + OverlayState.second: secondOverlay, + OverlayState.third: thirdOverlay, + OverlayState.fourth: fourthOverlay, + OverlayState.fifth: fifthOverlay, + OverlayState.sixth: sixthOverlay, + OverlayState.seventh: seventhOverlay, + }, + current: OverlayState.first, + ); + + overlayA.changePriorityWithoutResorting(WINDOW_PRIORITY - 1); + + overlayA.changePriorityWithoutResorting(WINDOW_PRIORITY - 1); + + windows0 = await Flame.images.load("windows-0.png"); + windows1 = await Flame.images.load("windows-1.png"); + windows2 = await Flame.images.load("windows-2.png"); + windows3 = await Flame.images.load("windows-3.png"); + windows4 = await Flame.images.load("windows-4.png"); + windows5 = await Flame.images.load("windows-5.png"); + windows6 = await Flame.images.load("windows-6.png"); + + SpriteAnimation firstWindow = SpriteAnimation.fromFrameData( + windows0, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation secondWindow = SpriteAnimation.fromFrameData( + windows1, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation thirdWindow = SpriteAnimation.fromFrameData( + windows2, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation fourthWindow = SpriteAnimation.fromFrameData( + windows3, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation fifthWindow = SpriteAnimation.fromFrameData( + windows4, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation sixthWindow = SpriteAnimation.fromFrameData( + windows5, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + SpriteAnimation seventhWindow = SpriteAnimation.fromFrameData( + windows6, + SpriteAnimationData.sequenced( + amount: 1, + stepTime: 1, + textureSize: Vector2(2048, 683), + loop: false)); + + windowA = SpriteAnimationGroupComponent( + animations: { + WindowState.first: firstWindow, + WindowState.second: secondWindow, + WindowState.third: thirdWindow, + WindowState.fourth: fourthWindow, + WindowState.fifth: fifthWindow, + WindowState.sixth: sixthWindow, + WindowState.seventh: seventhWindow, + }, + current: WindowState.first, + ); + + windowB = SpriteAnimationGroupComponent( + animations: { + WindowState.first: firstWindow, + WindowState.second: secondWindow, + WindowState.third: thirdWindow, + WindowState.fourth: fourthWindow, + WindowState.fifth: fifthWindow, + WindowState.sixth: sixthWindow, + WindowState.seventh: seventhWindow, + }, + current: WindowState.first, + ); + + windowA.changePriorityWithoutResorting(WINDOW_PRIORITY); + + windowA.changePriorityWithoutResorting(WINDOW_PRIORITY); + + setUp(); + } + + void setUp() { + windowA.current = WindowState.first; + windowB.current = WindowState.first; + overlayA.current = OverlayState.first; + overlayB.current = OverlayState.first; + background1Position = Vector2(0, 0); + background1Size = Vector2( + gameRef.viewport.canvasSize.y * (background.width / background.height), + gameRef.viewport.canvasSize.y); + windowA.position = background1Position; + windowA.size = background1Size; + overlayA.position = background1Position; + overlayA.size = background1Size; + + background2Position = + Vector2(background1Position.x + background1Size.x - 1, 0); + background2Size = Vector2( + gameRef.viewport.canvasSize.y * (background.width / background.height), + gameRef.viewport.canvasSize.y); + windowB.position = background2Position; + windowB.size = background2Size; + overlayB.position = background2Position; + overlayB.size = background2Size; + } + + @override + void update(double dt) { + switch (gameRef.gameState.getScoreLevel()) { + case 12: + windowA.current = WindowState.seventh; + windowB.current = WindowState.seventh; + break; + case 11: + overlayA.current = OverlayState.seventh; + overlayB.current = OverlayState.seventh; + break; + case 10: + windowA.current = WindowState.sixth; + windowB.current = WindowState.sixth; + break; + case 9: + overlayA.current = OverlayState.sixth; + overlayB.current = OverlayState.sixth; + break; + case 8: + windowA.current = WindowState.fifth; + windowB.current = WindowState.fifth; + break; + case 7: + overlayA.current = OverlayState.fifth; + overlayB.current = OverlayState.fifth; + break; + case 6: + windowA.current = WindowState.fourth; + windowB.current = WindowState.fourth; + break; + case 5: + overlayA.current = OverlayState.fourth; + overlayB.current = OverlayState.fourth; + break; + case 4: + windowA.current = WindowState.third; + windowB.current = WindowState.third; + break; + case 3: + overlayA.current = OverlayState.third; + overlayB.current = OverlayState.third; + break; + case 2: + windowA.current = WindowState.second; + windowB.current = WindowState.second; + break; + case 1: + overlayA.current = OverlayState.second; + overlayB.current = OverlayState.second; + break; + default: + windowA.current = WindowState.first; + windowB.current = WindowState.first; + overlayA.current = OverlayState.first; + overlayB.current = OverlayState.first; + break; + } + windowA.update(dt); + windowB.update(dt); + overlayA.update(dt); + overlayB.update(dt); + if (background1Position.x + background1Size.x < 0) { + double newPosition = background2Position.x + background2Size.x; + background1Position = Vector2(newPosition - 1, 0); + } else if (background2Position.x + background2Size.x < 0) { + double newPosition = background1Position.x + background1Size.x; + background2Position = Vector2(newPosition - 1, 0); + } + + double velocity = gameRef.gameState.getVelocity() / 10.0; + background1Position = background1Position - Vector2(velocity * dt, 0); + windowA.position = background1Position; + overlayA.position = background1Position; + background2Position = background2Position - Vector2(velocity * dt, 0); + windowB.position = background2Position; + overlayB.position = background2Position; + } + + void render(Canvas canvas) { + background1.render(canvas, + size: background1Size, position: background1Position); + canvas.save(); + overlayA.render(canvas); + canvas.restore(); + canvas.save(); + windowA.render(canvas); + canvas.restore(); + background2.render(canvas, + size: background2Size, position: background2Position); + canvas.save(); + overlayB.render(canvas); + canvas.restore(); + canvas.save(); + windowB.render(canvas); + canvas.restore(); + } + + @override + void resize(Vector2 newSize, double xRatio, double yRatio) { + background1Size = + Vector2(newSize.y * (background.width / background.height), newSize.y); + windowA.position = background1Position; + windowA.size = background1Size; + overlayA.position = background1Position; + overlayA.size = background1Size; + + background2Position = + Vector2(background1Position.x + background1Size.x - 1, 0); + background2Size = + Vector2(newSize.y * (background.width / background.height), newSize.y); + windowB.position = background2Position; + windowB.size = background2Size; + overlayB.position = background2Position; + overlayB.size = background2Size; + } +} diff --git a/lib/firework.dart b/lib/firework.dart index c9df46b..d71a7f2 100644 --- a/lib/firework.dart +++ b/lib/firework.dart @@ -1,131 +1,131 @@ -import 'dart:math'; - -import 'package:firo_runner/main.dart'; -import 'package:flame/components.dart'; -import 'package:flame/extensions.dart'; -import 'package:flame/flame.dart'; - -enum FireworkState { normal } - -class Firework extends Component { - MyGame gameRef; - late SpriteAnimationGroupComponent sprite1; - late SpriteAnimationGroupComponent sprite2; - Firework(this.gameRef); - double timeSinceFirework = 0; - late Random random; - String message = ""; - List messages = [ - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - "Speed Up!", - ]; - - Future load() async { - random = Random(); - Image firework = await Flame.images.load("fireworks-frames.png"); - - SpriteAnimation normal = SpriteAnimation.fromFrameData( - firework, - SpriteAnimationData.sequenced( - amount: 10, - stepTime: 0.25, - textureSize: Vector2(512, 512), - loop: false, - ), - ); - - sprite1 = SpriteAnimationGroupComponent( - animations: { - FireworkState.normal: normal, - }, - current: FireworkState.normal, - ); - - sprite1.changePriorityWithoutResorting(FIREWORK_PRIORITY); - sprite1.update(100); - - sprite1.size = - Vector2(gameRef.viewport.canvasSize.y, gameRef.viewport.canvasSize.y); - sprite1.position = Vector2(0, 0); - - sprite2 = SpriteAnimationGroupComponent( - animations: { - FireworkState.normal: normal, - }, - current: FireworkState.normal, - ); - - sprite2.changePriorityWithoutResorting(FIREWORK_PRIORITY); - - sprite2.size = - Vector2(gameRef.viewport.canvasSize.y, gameRef.viewport.canvasSize.y); - sprite2.position = - Vector2(gameRef.viewport.canvasSize.x - sprite2.size.x, 0); - sprite2.update(100); - } - - void setUp() { - message = ""; - timeSinceFirework = 0; - gameRef.add(sprite1); - gameRef.add(sprite2); - } - - @override - void update(double dt) { - if (!(sprite1.animation?.done() ?? false)) { - timeSinceFirework = 0; - } else { - timeSinceFirework += dt; - } - sprite1.update(dt); - sprite2.update(dt); - } - - void renderText(Canvas canvas) { - sprite1.render(canvas); - sprite1.render(canvas); - if ((sprite1.animation?.done() ?? false) && - timeSinceFirework < 1 && - message != "") { - gameRef.fireworksPaint.render( - canvas, - message, - Vector2( - gameRef.size.x / 2 - - gameRef.fireworksPaint.measureTextWidth(message) / 2, - gameRef.size.y / 9 - - gameRef.fireworksPaint.measureTextHeight(message) / 2), - ); - } - } - - void reset() { - message = messages.elementAt(random.nextInt(messages.length)); - sprite1.animation!.reset(); - sprite2.animation!.reset(); - } - - void resize(Vector2 newSize, double xRatio, double yRatio) { - sprite1.x *= xRatio; - sprite1.y *= yRatio; - sprite1.width *= xRatio; - sprite1.height *= yRatio; - - sprite2.x *= xRatio; - sprite2.y *= yRatio; - sprite2.width *= xRatio; - sprite2.height *= yRatio; - } -} +import 'dart:math'; + +import 'package:firo_runner/main.dart'; +import 'package:flame/components.dart'; +import 'package:flame/extensions.dart'; +import 'package:flame/flame.dart'; + +enum FireworkState { normal } + +class Firework extends Component { + MyGame gameRef; + late SpriteAnimationGroupComponent sprite1; + late SpriteAnimationGroupComponent sprite2; + Firework(this.gameRef); + double timeSinceFirework = 0; + late Random random; + String message = ""; + List messages = [ + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + "Speed Up!", + ]; + + Future load() async { + random = Random(); + Image firework = await Flame.images.load("fireworks-frames.png"); + + SpriteAnimation normal = SpriteAnimation.fromFrameData( + firework, + SpriteAnimationData.sequenced( + amount: 10, + stepTime: 0.25, + textureSize: Vector2(512, 512), + loop: false, + ), + ); + + sprite1 = SpriteAnimationGroupComponent( + animations: { + FireworkState.normal: normal, + }, + current: FireworkState.normal, + ); + + sprite1.changePriorityWithoutResorting(FIREWORK_PRIORITY); + sprite1.update(100); + + sprite1.size = + Vector2(gameRef.viewport.canvasSize.y, gameRef.viewport.canvasSize.y); + sprite1.position = Vector2(0, 0); + + sprite2 = SpriteAnimationGroupComponent( + animations: { + FireworkState.normal: normal, + }, + current: FireworkState.normal, + ); + + sprite2.changePriorityWithoutResorting(FIREWORK_PRIORITY); + + sprite2.size = + Vector2(gameRef.viewport.canvasSize.y, gameRef.viewport.canvasSize.y); + sprite2.position = + Vector2(gameRef.viewport.canvasSize.x - sprite2.size.x, 0); + sprite2.update(100); + } + + void setUp() { + message = ""; + timeSinceFirework = 0; + gameRef.add(sprite1); + gameRef.add(sprite2); + } + + @override + void update(double dt) { + if (!(sprite1.animation?.done() ?? false)) { + timeSinceFirework = 0; + } else { + timeSinceFirework += dt; + } + sprite1.update(dt); + sprite2.update(dt); + } + + void renderText(Canvas canvas) { + sprite1.render(canvas); + sprite1.render(canvas); + if ((sprite1.animation?.done() ?? false) && + timeSinceFirework < 1 && + message != "") { + gameRef.fireworksPaint.render( + canvas, + message, + Vector2( + gameRef.size.x / 2 - + gameRef.fireworksPaint.measureTextWidth(message) / 2, + gameRef.size.y / 9 - + gameRef.fireworksPaint.measureTextHeight(message) / 2), + ); + } + } + + void reset() { + message = messages.elementAt(random.nextInt(messages.length)); + sprite1.animation!.reset(); + sprite2.animation!.reset(); + } + + void resize(Vector2 newSize, double xRatio, double yRatio) { + sprite1.x *= xRatio; + sprite1.y *= yRatio; + sprite1.width *= xRatio; + sprite1.height *= yRatio; + + sprite2.x *= xRatio; + sprite2.y *= yRatio; + sprite2.width *= xRatio; + sprite2.height *= yRatio; + } +} diff --git a/lib/game_state.dart b/lib/game_state.dart index 46f77cd..26ff86f 100644 --- a/lib/game_state.dart +++ b/lib/game_state.dart @@ -1,124 +1,124 @@ -import 'package:firo_runner/main.dart'; -import 'package:flame/components.dart'; - -class GameState extends Component { - int start = 0; - bool isPaused = false; - int numCoins = 0; - int distance = 0; - late MyGame gameRef; - int previousLevel = 1; - - @override - void update(double dt) { - super.update(dt); - if (!isPaused) { - distance = DateTime.now().microsecondsSinceEpoch - start; - if (previousLevel != getLevel()) { - previousLevel = getLevel(); - gameRef.fireworks.reset(); - } - } - } - - void addCoin() { - numCoins++; - } - - void setUp(MyGame gameRef) { - this.gameRef = gameRef; - numCoins = 0; - distance = 0; - previousLevel = 1; - start = DateTime.now().microsecondsSinceEpoch; - isPaused = false; - } - - void setPaused() { - isPaused = true; - } - - int getLevel() { - if (distance > LEVEL7) { - return 7; - } else if (distance > LEVEL6) { - return 6; - } else if (distance > LEVEL5) { - return 5; - } else if (distance > LEVEL4) { - return 4; - } else if (distance > LEVEL3) { - return 3; - } else if (distance > LEVEL2) { - return 2; - } else { - return 1; - } - } - - int getScoreLevel() { - int score = getScore(); - if (score > LEVEL7) { - return 12; - } else if (score > LEVEL6 + LEVEL6 / 2) { - return 11; - } else if (score > LEVEL6) { - return 10; - } else if (score > LEVEL5 + LEVEL5 / 2) { - return 9; - } else if (score > LEVEL5) { - return 8; - } else if (score > LEVEL4 + LEVEL4 / 2) { - return 7; - } else if (score > LEVEL4) { - return 6; - } else if (score > LEVEL3 + LEVEL3 / 2) { - return 5; - } else if (score > LEVEL3) { - return 4; - } else if (score > LEVEL2 + LEVEL2 / 2) { - return 3; - } else if (score > LEVEL2) { - return 2; - } else if (score > LEVEL2 - LEVEL2 / 2) { - return 1; - } else { - return 0; - } - } - - int getScore() { - return distance ~/ 10 + numCoins * 1000000; - } - - int getPlayerScore() { - return getScore() ~/ 10000; - } - - int getPlayerDistance() { - return distance ~/ 1000000; - } - - double getVelocity() { - if (!isPaused) { - switch (getLevel()) { - case 7: - return gameRef.viewport.canvasSize.x * 0.25; - case 6: - return gameRef.viewport.canvasSize.x * 0.20; - case 5: - return gameRef.viewport.canvasSize.x * 0.18; - case 4: - return gameRef.viewport.canvasSize.x * 0.16; - case 3: - return gameRef.viewport.canvasSize.x * 0.14; - case 2: - return gameRef.viewport.canvasSize.x * 0.12; - default: - return gameRef.viewport.canvasSize.x * 0.1; - } - } else { - return 0; - } - } -} +import 'package:firo_runner/main.dart'; +import 'package:flame/components.dart'; + +class GameState extends Component { + int start = 0; + bool isPaused = false; + int numCoins = 0; + int distance = 0; + late MyGame gameRef; + int previousLevel = 1; + + @override + void update(double dt) { + super.update(dt); + if (!isPaused) { + distance = DateTime.now().microsecondsSinceEpoch - start; + if (previousLevel != getLevel()) { + previousLevel = getLevel(); + gameRef.fireworks.reset(); + } + } + } + + void addCoin() { + numCoins++; + } + + void setUp(MyGame gameRef) { + this.gameRef = gameRef; + numCoins = 0; + distance = 0; + previousLevel = 1; + start = DateTime.now().microsecondsSinceEpoch; + isPaused = false; + } + + void setPaused() { + isPaused = true; + } + + int getLevel() { + if (distance > LEVEL7) { + return 7; + } else if (distance > LEVEL6) { + return 6; + } else if (distance > LEVEL5) { + return 5; + } else if (distance > LEVEL4) { + return 4; + } else if (distance > LEVEL3) { + return 3; + } else if (distance > LEVEL2) { + return 2; + } else { + return 1; + } + } + + int getScoreLevel() { + int score = getScore(); + if (score > LEVEL7) { + return 12; + } else if (score > LEVEL6 + LEVEL6 / 2) { + return 11; + } else if (score > LEVEL6) { + return 10; + } else if (score > LEVEL5 + LEVEL5 / 2) { + return 9; + } else if (score > LEVEL5) { + return 8; + } else if (score > LEVEL4 + LEVEL4 / 2) { + return 7; + } else if (score > LEVEL4) { + return 6; + } else if (score > LEVEL3 + LEVEL3 / 2) { + return 5; + } else if (score > LEVEL3) { + return 4; + } else if (score > LEVEL2 + LEVEL2 / 2) { + return 3; + } else if (score > LEVEL2) { + return 2; + } else if (score > LEVEL2 - LEVEL2 / 2) { + return 1; + } else { + return 0; + } + } + + int getScore() { + return distance ~/ 10 + numCoins * 1000000; + } + + int getPlayerScore() { + return getScore() ~/ 10000; + } + + int getPlayerDistance() { + return distance ~/ 1000000; + } + + double getVelocity() { + if (!isPaused) { + switch (getLevel()) { + case 7: + return gameRef.viewport.canvasSize.x * 0.25; + case 6: + return gameRef.viewport.canvasSize.x * 0.20; + case 5: + return gameRef.viewport.canvasSize.x * 0.18; + case 4: + return gameRef.viewport.canvasSize.x * 0.16; + case 3: + return gameRef.viewport.canvasSize.x * 0.14; + case 2: + return gameRef.viewport.canvasSize.x * 0.12; + default: + return gameRef.viewport.canvasSize.x * 0.1; + } + } else { + return 0; + } + } +} diff --git a/lib/lose_menu_overlay.dart b/lib/lose_menu_overlay.dart index e8120ea..0f14c8c 100644 --- a/lib/lose_menu_overlay.dart +++ b/lib/lose_menu_overlay.dart @@ -1,88 +1,94 @@ -import 'package:flutter/material.dart'; - -import 'main.dart'; - -class LoseMenuOverlay extends StatelessWidget { - const LoseMenuOverlay({ - Key? key, - required this.game, - }) : super(key: key); - - final MyGame game; - - @override - Widget build(BuildContext context) { - return Center( - child: Container( - height: game.viewport.canvasSize.y, - width: game.viewport.canvasSize.x, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/overlay100.png'), - fit: BoxFit.fill, - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Score: ' + game.gameState.getPlayerScore().toString(), - style: overlayText, - ), - const SizedBox(height: 32.0), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - MaterialButton( - padding: const EdgeInsets.all(8.0), - textColor: Colors.white, - splashColor: Colors.greenAccent, - elevation: 8.0, - child: Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/button.png'), - fit: BoxFit.fill), - ), - child: const Padding( - padding: EdgeInsets.all(8.0), - child: Text("Main Menu"), - ), - ), - // ), - onPressed: () { - // Go to the Main Menu - }, - ), - const SizedBox( - width: 32.0, - ), - MaterialButton( - padding: const EdgeInsets.all(8.0), - textColor: Colors.white, - splashColor: Colors.greenAccent, - elevation: 8.0, - child: Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/button.png'), - fit: BoxFit.fill), - ), - child: const Padding( - padding: EdgeInsets.all(8.0), - child: Text("Replay"), - ), - ), - // ), - onPressed: () { - game.reset(); - }, - ), - ], - ), - ], - ), - ), - ); - } -} +import 'package:flutter/material.dart'; + +import 'main.dart'; + +class LoseMenuOverlay extends StatelessWidget { + const LoseMenuOverlay({ + Key? key, + required this.game, + }) : super(key: key); + + final MyGame game; + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + height: game.viewport.canvasSize.y, + width: game.viewport.canvasSize.x, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/overlay100.png'), + fit: BoxFit.fill, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Score: ' + game.gameState.getPlayerScore().toString(), + style: overlayText, + ), + const SizedBox(height: 32.0), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + MaterialButton( + padding: const EdgeInsets.all(8.0), + textColor: Colors.white, + splashColor: Colors.greenAccent, + elevation: 8.0, + child: Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/button.png'), + fit: BoxFit.fill), + ), + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Text( + " Main Menu ", + style: overlayText, + ), + ), + ), + // ), + onPressed: () { + // Go to the Main Menu + }, + ), + const SizedBox( + width: 32.0, + ), + MaterialButton( + padding: const EdgeInsets.all(8.0), + textColor: Colors.white, + splashColor: Colors.greenAccent, + elevation: 8.0, + child: Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/button.png'), + fit: BoxFit.fill), + ), + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Text( + " Replay ", + style: overlayText, + ), + ), + ), + // ), + onPressed: () { + game.reset(); + }, + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index bd24b56..85b3217 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,441 +1,441 @@ -import 'dart:math'; - -import 'package:firo_runner/bug_holder.dart'; -import 'package:firo_runner/circuit_background.dart'; -import 'package:firo_runner/coin_holder.dart'; -import 'package:firo_runner/debris_holder.dart'; -import 'package:firo_runner/firework.dart'; -import 'package:firo_runner/game_state.dart'; -import 'package:firo_runner/moving_object.dart'; -import 'package:firo_runner/platform.dart'; -import 'package:firo_runner/platform_holder.dart'; -import 'package:firo_runner/wall_holder.dart'; -import 'package:firo_runner/wire.dart'; -import 'package:firo_runner/wire_holder.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_audio/flame_audio.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:firo_runner/runner.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; - -import 'package:firo_runner/lose_menu_overlay.dart'; - -const COLOR = Color(0xFFDDC0A3); - -const LEVEL2 = 10000000; -const LEVEL3 = 20000000; -const LEVEL4 = 30000000; -const LEVEL5 = 40000000; -const LEVEL6 = 50000000; -const LEVEL7 = 60000000; - -const OVERLAY_PRIORITY = 110; -const RUNNER_PRIORITY = 100; -const BUG_PRIORITY = 75; -const COIN_PRIORITY = 70; -const PLATFORM_PRIORITY = 50; -const WALL_PRIORITY = 40; -const DEBRIS_PRIORITY = 30; -const WIRE_PRIORITY = 25; -const FIREWORK_PRIORITY = 15; -const WINDOW_PRIORITY = 10; - -const overlayText = TextStyle( - fontSize: 30, - color: Colors.white, -); - -void main() async { - WidgetsFlutterBinding.ensureInitialized(); - await Flame.device.fullScreen(); - await Flame.device.setLandscape(); - final myGame = MyGame(); - runApp(GameWidget( - game: myGame, - overlayBuilderMap: { - 'gameOver': (_, myGame) { - return LoseMenuOverlay(game: myGame); - }, - }, - )); -} - -int getNearestPlatform(int level) { - return level <= 0 - ? 0 - : level <= 3 - ? 2 - : level <= 6 - ? 5 - : 8; -} - -class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { - TextPaint fireworksPaint = TextPaint( - config: const TextPaintConfig( - fontSize: 48.0, fontFamily: 'Codystar', color: COLOR), - ); - - TextPaint scoresPaint = TextPaint( - config: const TextPaintConfig(fontSize: 16.0, color: COLOR), - ); - - late CircuitBackground circuitBackground; - late PlatformHolder platformHolder; - late CoinHolder coinHolder; - late WireHolder wireHolder; - late BugHolder bugHolder; - late Firework fireworks; - late DebrisHolder debrisHolder; - late WallHolder wallHolder; - Random random = Random(); - bool playingMusic = false; - - late Runner runner; - late GameState gameState; - late double blockSize; - - bool loaded = false; - bool firstDeath = true; - late Wire wire; - late TextComponent _distance; - late TextComponent _coins; - - MyGame() : super() { - viewport.resize(Vector2(1920, 1080)); - } - - @override - Future onLoad() async { - // debugMode = true; - FlameAudio.bgm.initialize(); - - circuitBackground = CircuitBackground(this); - await circuitBackground.load(); - platformHolder = PlatformHolder(); - await platformHolder.load(); - coinHolder = CoinHolder(); - await coinHolder.load(); - wireHolder = WireHolder(); - await wireHolder.load(); - bugHolder = BugHolder(); - await bugHolder.load(); - debrisHolder = DebrisHolder(); - await debrisHolder.load(); - wallHolder = WallHolder(); - await wallHolder.load(); - fireworks = Firework(this); - await fireworks.load(); - - gameState = GameState(); - - runner = Runner(); - await runner.load(loadSpriteAnimation); - - if (!kIsWeb) { - playMusic(); - } - loaded = true; - _distance = TextComponent("Distance: 0", - position: Vector2(size.x - 100, 10), textRenderer: scoresPaint) - ..anchor = Anchor.topRight; - _distance.changePriorityWithoutResorting(OVERLAY_PRIORITY); - _coins = TextComponent("Coins: 0", - position: Vector2(size.x - 10, 10), textRenderer: scoresPaint) - ..anchor = Anchor.topRight; - _coins.changePriorityWithoutResorting(OVERLAY_PRIORITY); - setUp(); - } - - void playMusic() { - FlameAudio.bgm.play('Infinite_Spankage_M.mp3'); - playingMusic = true; - } - - void fillScreen() { - if (shouldReset) { - return; - } - - platformHolder.generatePlatforms(this); - - int wireChosenRegion = random.nextInt(9); - if (wireChosenRegion % 3 != 2 && - wireChosenRegion != 6 && - wireChosenRegion != 7) { - wireHolder.generateWire(this, wireChosenRegion); - } - - int bugChosenRegion = random.nextInt(9); - if (bugChosenRegion % 3 != 2 && bugChosenRegion % 3 != 0) { - bugHolder.generateBug(this, bugChosenRegion); - } - - int debrisChosenRegion = random.nextInt(9); - if (debrisChosenRegion % 3 == 0 && debrisChosenRegion != 6) { - debrisHolder.generateDebris(this, debrisChosenRegion); - } - - int choseCoinLevel = random.nextInt(9); - if (choseCoinLevel % 3 != 2 && choseCoinLevel != 6) { - coinHolder.generateCoin(this, choseCoinLevel); - } - - int wallChosenRegion = random.nextInt(9); - if (wallChosenRegion % 3 == 1 && wallChosenRegion != 7) { - wallHolder.generateWall(this, wallChosenRegion); - } - } - - bool isTooNearOtherObstacles(Rect rect) { - Rect obstacleBounds = Rect.fromLTRB( - 3 * rect.left - 2 * (rect.left + blockSize) - 1, - 3 * rect.top - 2 * (rect.top + blockSize) - 1, - 3 * (rect.left + blockSize) - 2 * rect.left + 1, - 3 * (rect.top + blockSize) - 2 * rect.top + 1); - for (List wireLevel in wireHolder.objects) { - for (MovingObject wire in wireLevel) { - if (wire.intersect(obstacleBounds) != "none") { - return true; - } - } - } - - for (List coinLevel in coinHolder.objects) { - for (MovingObject coin in coinLevel) { - if (coin.intersect(obstacleBounds) != "none") { - return true; - } - } - } - - for (List bugLevel in bugHolder.objects) { - for (MovingObject bug in bugLevel) { - if (bug.intersect(obstacleBounds) != "none") { - return true; - } - } - } - - for (List debrisLevel in debrisHolder.objects) { - for (MovingObject debris in debrisLevel) { - if (debris.intersect(obstacleBounds) != "none") { - return true; - } - } - } - - for (List wallLevel in wallHolder.objects) { - for (MovingObject wall in wallLevel) { - if (wall.intersect(obstacleBounds) != "none") { - return true; - } - } - } - - return false; - } - - bool shouldReset = false; - - void displayLoss() { - if (!(runner.sprite.animation?.done() ?? false) && - runner.sprite.animation!.loop == false && - firstDeath) { - return; - } - firstDeath = false; - overlays.add('gameOver'); - } - - void reset() { - runner.sprite.animation!.reset(); - overlays.remove('gameOver'); - shouldReset = false; - components.clear(); - setUp(); - } - - void die() { - gameState.setPaused(); - shouldReset = true; - } - - void setUp() { - add(runner); - fireworks.setUp(); - runner.sprite.clearEffects(); - runner.sprite.current = RunnerState.run; - circuitBackground.setUp(); - platformHolder.setUp(); - coinHolder.setUp(); - wireHolder.setUp(); - bugHolder.setUp(); - debrisHolder.setUp(); - wallHolder.setUp(); - - gameState.setUp(this); - - runner.setUp(); - add(_coins); - add(_distance); - - fillScreen(); - platformHolder.objects[2][0].sprite.current = PlatformState.left; - platformHolder.objects[5][0].sprite.current = PlatformState.left; - } - - @override - void render(Canvas canvas) { - circuitBackground.render(canvas); - fireworks.renderText(canvas); - super.render(canvas); - final fpsCount = fps(10000); - fireworksPaint.render( - canvas, - fpsCount.toString(), - Vector2(0, 0), - ); - } - - @override - void update(double dt) { - fireworks.update(dt); - platformHolder.removePast(this); - coinHolder.removePast(this); - wireHolder.removePast(this); - bugHolder.removePast(this); - debrisHolder.removePast(this); - wallHolder.removePast(this); - fillScreen(); - super.update(dt); - circuitBackground.update(dt); - gameState.update(dt); - platformHolder.update(dt); - coinHolder.update(dt); - wireHolder.update(dt); - bugHolder.update(dt); - debrisHolder.update(dt); - wallHolder.update(dt); - - _distance.text = "Distance: ${gameState.getPlayerDistance()}"; - _coins.text = "Coins: ${gameState.numCoins}"; - if (shouldReset && !overlays.isActive('gameOver')) { - displayLoss(); - } - } - - @override - void onResize(Vector2 canvasSize) { - Vector2 oldSize = viewport.canvasSize; - super.onResize(canvasSize); - blockSize = canvasSize.y / 9; - if (loaded) { - double xRatio = canvasSize.x / oldSize.x; - double yRatio = canvasSize.y / oldSize.y; - circuitBackground.resize(canvasSize, xRatio, yRatio); - runner.resize(canvasSize, xRatio, yRatio); - platformHolder.resize(canvasSize, xRatio, yRatio); - coinHolder.resize(canvasSize, xRatio, yRatio); - wireHolder.resize(canvasSize, xRatio, yRatio); - bugHolder.resize(canvasSize, xRatio, yRatio); - debrisHolder.resize(canvasSize, xRatio, yRatio); - wallHolder.resize(canvasSize, xRatio, yRatio); - fireworks.resize(canvasSize, xRatio, yRatio); - } - } - - // Mobile controls - late List xDeltas; - late List yDeltas; - @override - void onPanStart(DragStartInfo info) { - 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); - } - - @override - void onPanEnd(DragEndInfo info) { - if (!playingMusic && kIsWeb) { - playMusic(); - } - double xDelta = xDeltas.isEmpty - ? 0 - : 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) { - runner.control("right"); - } else { - runner.control("left"); - } - } else if (xDelta.abs() < yDelta.abs()) { - if (yDelta > 0) { - runner.control("down"); - } else { - runner.control("up"); - } - } - } - - @override - void onTap() { - if (!playingMusic && kIsWeb) { - playMusic(); - } - runner.control("center"); - } - - // Keyboard controls. - var keyboardKey; - @override - void onKeyEvent(RawKeyEvent event) { - if (!playingMusic && kIsWeb) { - playMusic(); - } - print(event.data.logicalKey.keyId); - print(event.data.keyLabel); - if (event is RawKeyUpEvent) { - keyboardKey = null; - switch (event.data.keyLabel) { - case "w": - runner.control("up"); - break; - case "a": - runner.control("left"); - break; - case "s": - runner.control("down"); - break; - case "d": - runner.control("right"); - break; - default: - if (event.data.logicalKey.keyId == 32) { - runner.control("down"); - } - break; - } - } - if (event is RawKeyDownEvent && event.data.logicalKey.keyId == 32) { - if (keyboardKey == null) { - runner.control("center"); - } - keyboardKey = "spacebar"; - } - } -} +import 'dart:math'; + +import 'package:firo_runner/bug_holder.dart'; +import 'package:firo_runner/circuit_background.dart'; +import 'package:firo_runner/coin_holder.dart'; +import 'package:firo_runner/debris_holder.dart'; +import 'package:firo_runner/firework.dart'; +import 'package:firo_runner/game_state.dart'; +import 'package:firo_runner/moving_object.dart'; +import 'package:firo_runner/platform.dart'; +import 'package:firo_runner/platform_holder.dart'; +import 'package:firo_runner/wall_holder.dart'; +import 'package:firo_runner/wire.dart'; +import 'package:firo_runner/wire_holder.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_audio/flame_audio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:firo_runner/runner.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; + +import 'package:firo_runner/lose_menu_overlay.dart'; + +const COLOR = Color(0xFFDDC0A3); + +const LEVEL2 = 10000000; +const LEVEL3 = 20000000; +const LEVEL4 = 30000000; +const LEVEL5 = 40000000; +const LEVEL6 = 50000000; +const LEVEL7 = 60000000; + +const OVERLAY_PRIORITY = 110; +const RUNNER_PRIORITY = 100; +const BUG_PRIORITY = 75; +const COIN_PRIORITY = 70; +const PLATFORM_PRIORITY = 50; +const WALL_PRIORITY = 40; +const DEBRIS_PRIORITY = 30; +const WIRE_PRIORITY = 25; +const FIREWORK_PRIORITY = 15; +const WINDOW_PRIORITY = 10; + +const overlayText = TextStyle( + fontSize: 30, + color: Colors.white, +); + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Flame.device.fullScreen(); + await Flame.device.setLandscape(); + final myGame = MyGame(); + runApp(GameWidget( + game: myGame, + overlayBuilderMap: { + 'gameOver': (_, myGame) { + return LoseMenuOverlay(game: myGame); + }, + }, + )); +} + +int getNearestPlatform(int level) { + return level <= 0 + ? 0 + : level <= 3 + ? 2 + : level <= 6 + ? 5 + : 8; +} + +class MyGame extends BaseGame with PanDetector, TapDetector, KeyboardEvents { + TextPaint fireworksPaint = TextPaint( + config: const TextPaintConfig( + fontSize: 48.0, fontFamily: 'Codystar', color: COLOR), + ); + + TextPaint scoresPaint = TextPaint( + config: const TextPaintConfig(fontSize: 16.0, color: COLOR), + ); + + late CircuitBackground circuitBackground; + late PlatformHolder platformHolder; + late CoinHolder coinHolder; + late WireHolder wireHolder; + late BugHolder bugHolder; + late Firework fireworks; + late DebrisHolder debrisHolder; + late WallHolder wallHolder; + Random random = Random(); + bool playingMusic = false; + + late Runner runner; + late GameState gameState; + late double blockSize; + + bool loaded = false; + bool firstDeath = true; + late Wire wire; + late TextComponent _distance; + late TextComponent _coins; + + MyGame() : super() { + viewport.resize(Vector2(1920, 1080)); + } + + @override + Future onLoad() async { + // debugMode = true; + FlameAudio.bgm.initialize(); + + circuitBackground = CircuitBackground(this); + await circuitBackground.load(); + platformHolder = PlatformHolder(); + await platformHolder.load(); + coinHolder = CoinHolder(); + await coinHolder.load(); + wireHolder = WireHolder(); + await wireHolder.load(); + bugHolder = BugHolder(); + await bugHolder.load(); + debrisHolder = DebrisHolder(); + await debrisHolder.load(); + wallHolder = WallHolder(); + await wallHolder.load(); + fireworks = Firework(this); + await fireworks.load(); + + gameState = GameState(); + + runner = Runner(); + await runner.load(loadSpriteAnimation); + + if (!kIsWeb) { + playMusic(); + } + loaded = true; + _distance = TextComponent("Distance: 0", + position: Vector2(size.x - 100, 10), textRenderer: scoresPaint) + ..anchor = Anchor.topRight; + _distance.changePriorityWithoutResorting(OVERLAY_PRIORITY); + _coins = TextComponent("Coins: 0", + position: Vector2(size.x - 10, 10), textRenderer: scoresPaint) + ..anchor = Anchor.topRight; + _coins.changePriorityWithoutResorting(OVERLAY_PRIORITY); + setUp(); + } + + void playMusic() { + FlameAudio.bgm.play('Infinite_Spankage_M.mp3'); + playingMusic = true; + } + + void fillScreen() { + if (shouldReset) { + return; + } + + platformHolder.generatePlatforms(this); + + int wireChosenRegion = random.nextInt(9); + if (wireChosenRegion % 3 != 2 && + wireChosenRegion != 6 && + wireChosenRegion != 7) { + wireHolder.generateWire(this, wireChosenRegion); + } + + int bugChosenRegion = random.nextInt(9); + if (bugChosenRegion % 3 != 2 && bugChosenRegion % 3 != 0) { + bugHolder.generateBug(this, bugChosenRegion); + } + + int debrisChosenRegion = random.nextInt(9); + if (debrisChosenRegion % 3 == 0 && debrisChosenRegion != 6) { + debrisHolder.generateDebris(this, debrisChosenRegion); + } + + int choseCoinLevel = random.nextInt(9); + if (choseCoinLevel % 3 != 2 && choseCoinLevel != 6) { + coinHolder.generateCoin(this, choseCoinLevel); + } + + int wallChosenRegion = random.nextInt(9); + if (wallChosenRegion % 3 == 1 && wallChosenRegion != 7) { + wallHolder.generateWall(this, wallChosenRegion); + } + } + + bool isTooNearOtherObstacles(Rect rect) { + Rect obstacleBounds = Rect.fromLTRB( + 3 * rect.left - 2 * (rect.left + blockSize) - 1, + 3 * rect.top - 2 * (rect.top + blockSize) - 1, + 3 * (rect.left + blockSize) - 2 * rect.left + 1, + 3 * (rect.top + blockSize) - 2 * rect.top + 1); + for (List wireLevel in wireHolder.objects) { + for (MovingObject wire in wireLevel) { + if (wire.intersect(obstacleBounds) != "none") { + return true; + } + } + } + + for (List coinLevel in coinHolder.objects) { + for (MovingObject coin in coinLevel) { + if (coin.intersect(obstacleBounds) != "none") { + return true; + } + } + } + + for (List bugLevel in bugHolder.objects) { + for (MovingObject bug in bugLevel) { + if (bug.intersect(obstacleBounds) != "none") { + return true; + } + } + } + + for (List debrisLevel in debrisHolder.objects) { + for (MovingObject debris in debrisLevel) { + if (debris.intersect(obstacleBounds) != "none") { + return true; + } + } + } + + for (List wallLevel in wallHolder.objects) { + for (MovingObject wall in wallLevel) { + if (wall.intersect(obstacleBounds) != "none") { + return true; + } + } + } + + return false; + } + + bool shouldReset = false; + + void displayLoss() { + if (!(runner.sprite.animation?.done() ?? false) && + runner.sprite.animation!.loop == false && + firstDeath) { + return; + } + firstDeath = false; + overlays.add('gameOver'); + } + + void reset() { + runner.sprite.animation!.reset(); + overlays.remove('gameOver'); + shouldReset = false; + components.clear(); + setUp(); + } + + void die() { + gameState.setPaused(); + shouldReset = true; + } + + void setUp() { + add(runner); + fireworks.setUp(); + runner.sprite.clearEffects(); + runner.sprite.current = RunnerState.run; + circuitBackground.setUp(); + platformHolder.setUp(); + coinHolder.setUp(); + wireHolder.setUp(); + bugHolder.setUp(); + debrisHolder.setUp(); + wallHolder.setUp(); + + gameState.setUp(this); + + runner.setUp(); + add(_coins); + add(_distance); + + fillScreen(); + platformHolder.objects[2][0].sprite.current = PlatformState.left; + platformHolder.objects[5][0].sprite.current = PlatformState.left; + } + + @override + void render(Canvas canvas) { + circuitBackground.render(canvas); + fireworks.renderText(canvas); + super.render(canvas); + final fpsCount = fps(10000); + fireworksPaint.render( + canvas, + fpsCount.toString(), + Vector2(0, 0), + ); + } + + @override + void update(double dt) { + fireworks.update(dt); + platformHolder.removePast(this); + coinHolder.removePast(this); + wireHolder.removePast(this); + bugHolder.removePast(this); + debrisHolder.removePast(this); + wallHolder.removePast(this); + fillScreen(); + super.update(dt); + circuitBackground.update(dt); + gameState.update(dt); + platformHolder.update(dt); + coinHolder.update(dt); + wireHolder.update(dt); + bugHolder.update(dt); + debrisHolder.update(dt); + wallHolder.update(dt); + + _distance.text = "Distance: ${gameState.getPlayerDistance()}"; + _coins.text = "Coins: ${gameState.numCoins}"; + if (shouldReset && !overlays.isActive('gameOver')) { + displayLoss(); + } + } + + @override + void onResize(Vector2 canvasSize) { + Vector2 oldSize = viewport.canvasSize; + super.onResize(canvasSize); + blockSize = canvasSize.y / 9; + if (loaded) { + double xRatio = canvasSize.x / oldSize.x; + double yRatio = canvasSize.y / oldSize.y; + circuitBackground.resize(canvasSize, xRatio, yRatio); + runner.resize(canvasSize, xRatio, yRatio); + platformHolder.resize(canvasSize, xRatio, yRatio); + coinHolder.resize(canvasSize, xRatio, yRatio); + wireHolder.resize(canvasSize, xRatio, yRatio); + bugHolder.resize(canvasSize, xRatio, yRatio); + debrisHolder.resize(canvasSize, xRatio, yRatio); + wallHolder.resize(canvasSize, xRatio, yRatio); + fireworks.resize(canvasSize, xRatio, yRatio); + } + } + + // Mobile controls + late List xDeltas; + late List yDeltas; + @override + void onPanStart(DragStartInfo info) { + 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); + } + + @override + void onPanEnd(DragEndInfo info) { + if (!playingMusic && kIsWeb) { + playMusic(); + } + double xDelta = xDeltas.isEmpty + ? 0 + : 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) { + runner.control("right"); + } else { + runner.control("left"); + } + } else if (xDelta.abs() < yDelta.abs()) { + if (yDelta > 0) { + runner.control("down"); + } else { + runner.control("up"); + } + } + } + + @override + void onTap() { + if (!playingMusic && kIsWeb) { + playMusic(); + } + runner.control("center"); + } + + // Keyboard controls. + var keyboardKey; + @override + void onKeyEvent(RawKeyEvent event) { + if (!playingMusic && kIsWeb) { + playMusic(); + } + print(event.data.logicalKey.keyId); + print(event.data.keyLabel); + if (event is RawKeyUpEvent) { + keyboardKey = null; + switch (event.data.keyLabel) { + case "w": + runner.control("up"); + break; + case "a": + runner.control("left"); + break; + case "s": + runner.control("down"); + break; + case "d": + runner.control("right"); + break; + default: + if (event.data.logicalKey.keyId == 32) { + runner.control("down"); + } + break; + } + } + if (event is RawKeyDownEvent && event.data.logicalKey.keyId == 32) { + if (keyboardKey == null) { + runner.control("center"); + } + keyboardKey = "spacebar"; + } + } +} diff --git a/lib/platform.dart b/lib/platform.dart index 85d06f7..23d38b1 100644 --- a/lib/platform.dart +++ b/lib/platform.dart @@ -64,7 +64,7 @@ class Platform extends MovingObject { PlatformState.right: right, PlatformState.single: single, }, - current: PlatformState.single, + current: PlatformState.mid, ); sprite.changePriorityWithoutResorting(PLATFORM_PRIORITY); @@ -112,14 +112,19 @@ class Platform extends MovingObject { bool hasLeft = (left.x - sprite.position.x).abs() < 1.9 * sprite.size.x; bool hasRight = (sprite.position.x - right.x).abs() < 1.9 * sprite.size.x; - if (hasLeft && hasRight) { - sprite.current = PlatformState.mid; - } else if (hasLeft && !hasRight) { - sprite.current = PlatformState.right; - } else if (!hasLeft && hasRight) { - sprite.current = PlatformState.left; - } else { - sprite.current = PlatformState.single; + // If the platform cannot be seen by the player. + if (!((sprite.x >= 0 && sprite.x <= gameRef.size.x) || + (sprite.x + sprite.width >= 0 && + sprite.x + sprite.width <= gameRef.size.x))) { + if (hasLeft && hasRight) { + sprite.current = PlatformState.mid; + } else if (hasLeft && !hasRight) { + sprite.current = PlatformState.right; + } else if (!hasLeft && hasRight) { + sprite.current = PlatformState.left; + } else { + sprite.current = PlatformState.single; + } } } } diff --git a/lib/platform_holder.dart b/lib/platform_holder.dart index 65ee336..fab5fd2 100644 --- a/lib/platform_holder.dart +++ b/lib/platform_holder.dart @@ -14,6 +14,8 @@ class PlatformHolder extends Holder { late Image r2; late Image o1; late Image o2; + bool noTopObstaclesForNext = false; + bool noMiddleObstaclesForNext = false; int timeSinceLastTopHole = 0; int timeSinceLastBottomHole = 0; @@ -91,6 +93,7 @@ class PlatformHolder extends Holder { remove(objects[2], objects[2].length - 2); timeSinceLastTopHole = 0; + noTopObstaclesForNext = true; } if (bottomChance > 30) { Platform start = objects[5].elementAt(objects[5].length - 10) as Platform; @@ -112,6 +115,7 @@ class PlatformHolder extends Holder { remove(objects[5], firstToRemove); timeSinceLastBottomHole = 0; + noMiddleObstaclesForNext = true; } } @@ -129,6 +133,13 @@ class PlatformHolder extends Holder { platform.row = level; gameRef.add(platform.sprite); objects[level].add(platform); + if (level == 2 && noTopObstaclesForNext) { + platform.prohibitObstacles = true; + noTopObstaclesForNext = false; + } else if (level == 5 && noMiddleObstaclesForNext) { + platform.prohibitObstacles = true; + noMiddleObstaclesForNext = false; + } return false; } } diff --git a/lib/runner.dart b/lib/runner.dart index d07fc6b..12b3f45 100644 --- a/lib/runner.dart +++ b/lib/runner.dart @@ -1,578 +1,599 @@ -import 'package:firo_runner/bug.dart'; -import 'package:firo_runner/moving_object.dart'; -import 'package:firo_runner/main.dart'; -import 'package:flame/effects.dart'; -import 'package:flame/extensions.dart'; -import 'package:flutter/material.dart'; -import 'dart:math'; - -import 'package:flame/components.dart'; - -enum RunnerState { - run, - jump, - duck, - kick, - float, - fall, - die, - electrocute, - glitch, -} - -class Runner extends Component with HasGameRef { - late SpriteAnimationGroupComponent sprite; - String runnerState = "run"; - int level = 4; - String previousState = "run"; - var runnerPosition = Vector2(0, 0); - late Vector2 runnerSize; - // late Rect runnerRect; - bool dead = false; - - void setUp() { - dead = false; - runnerState = "run"; - previousState = "run"; - level = 4; - - runnerSize = Vector2( - gameRef.size.y / 9, - gameRef.size.y / 9, - ); - - setSize(runnerSize, gameRef.blockSize); - runnerPosition = Vector2(gameRef.blockSize * 2, gameRef.blockSize * 4); - setPosition(runnerPosition); - } - - void setPosition(Vector2 position) { - sprite.position = position; - } - - void setSize(Vector2 size, double ySize) { - sprite.size = size; - } - - Sprite getSprite() { - return sprite.animation!.getSprite(); - } - - @override - void render(Canvas c) { - super.render(c); - getSprite().render(c, position: sprite.position, size: sprite.size); - } - - void updateLevel() { - level = (sprite.position.y / gameRef.blockSize).round(); - } - - void event(String event) { - if (gameRef.gameState.isPaused) { - return; - } - previousState = runnerState; - switch (event) { - case "jump": - runnerState = event; - sprite.current = RunnerState.jump; - sprite.addEffect(MoveEffect( - path: [ - // sprite.position, - Vector2(sprite.x, (level - 1) * gameRef.blockSize), - ], - duration: 0.25, - curve: Curves.bounceIn, - onComplete: () { - updateLevel(); - this.event("float"); - }, - )); - break; - case "double_jump": - if (belowPlatform()) { - break; - } - sprite.clearEffects(); - if (level - 1 < 0) { - break; - } - runnerState = event; - sprite.current = RunnerState.float; - sprite.addEffect(MoveEffect( - path: [ - Vector2(sprite.x, (level - 2) * gameRef.blockSize), - ], - duration: 0.5, - curve: Curves.ease, - onComplete: () { - updateLevel(); - if (onTopOfPlatform()) { - this.event("run"); - } else { - this.event("float"); - } - }, - )); - break; - case "fall": - sprite.clearEffects(); - runnerState = event; - sprite.current = RunnerState.fall; - sprite.addEffect(getFallingEffect()); - break; - case "kick": - runnerState = event; - sprite.current = RunnerState.kick; - break; - case "run": - runnerState = event; - sprite.current = RunnerState.run; - break; - case "float": - runnerState = event; - sprite.current = RunnerState.float; - sprite.addEffect(MoveEffect( - path: [sprite.position], - duration: 1.5, - curve: Curves.ease, - onComplete: () { - updateLevel(); - if (onTopOfPlatform()) { - this.event("run"); - } else { - this.event("fall"); - } - }, - )); - break; - case "duck": - runnerState = event; - sprite.current = RunnerState.duck; - sprite.addEffect(MoveEffect( - path: [sprite.position], - duration: 1.5, - curve: Curves.linear, - onComplete: () { - this.event("run"); - }, - )); - break; - case "die": - if (dead) { - return; - } - sprite.clearEffects(); - level = 11; - sprite.addEffect(MoveEffect( - path: [Vector2(sprite.position.x, gameRef.blockSize * 11)], - duration: 2, - curve: Curves.bounceOut, - onComplete: () {}, - )); - runnerState = event; - sprite.current = RunnerState.die; - gameRef.die(); - break; - case "electrocute": - if (dead) { - return; - } - sprite.clearEffects(); - level = 11; - sprite.addEffect(MoveEffect( - path: [Vector2(sprite.position.x, gameRef.blockSize * 11)], - duration: 1, - curve: Curves.bounceOut, - onComplete: () {}, - )); - runnerState = event; - sprite.current = RunnerState.electrocute; - gameRef.die(); - break; - case "glitch": - if (dead) { - return; - } - sprite.clearEffects(); - level = 11; - sprite.addEffect(MoveEffect( - path: [Vector2(sprite.position.x, gameRef.blockSize * 11)], - duration: 1, - curve: Curves.bounceOut, - onComplete: () {}, - )); - runnerState = event; - sprite.current = RunnerState.glitch; - gameRef.die(); - break; - default: - break; - } - } - - MoveEffect getFallingEffect() { - for (int i = level; i < 9; i++) { - if (i % 3 != 2) { - continue; - } - int distance = (i - 1 - level); - double time = 0.2; - for (int x = 2; x < distance; x++) { - time += time * pow(0.5, x - 1); - } - double estimatedXCoordinate = - time * gameRef.gameState.getVelocity() + sprite.x; - for (MovingObject p in gameRef.platformHolder.objects[i]) { - if (estimatedXCoordinate >= p.sprite.x - p.sprite.width / 2 && - estimatedXCoordinate <= p.sprite.x + p.sprite.width) { - return MoveEffect( - path: [ - Vector2(sprite.x, (i - 1) * gameRef.blockSize), - ], - duration: time, - curve: Curves.ease, - onComplete: () { - updateLevel(); - if (onTopOfPlatform()) { - event("run"); - } else { - event("fall"); - } - }, - ); - } - } - } - return MoveEffect( - path: [ - Vector2(sprite.x, 8 * gameRef.blockSize), - ], - duration: 0.2 * (8 - level), - curve: Curves.ease, - onComplete: () { - updateLevel(); - if (onTopOfPlatform()) { - event("run"); - } else { - event("fall"); - } - }, - ); - } - - void control(String input) { - if (gameRef.gameState.isPaused) { - return; - } - switch (input) { - case "up": - if (runnerState == "run") { - event("jump"); - } else if (runnerState == "float" && previousState == "jump") { - event("double_jump"); - } else if (runnerState == "duck") { - sprite.clearEffects(); - event("run"); - } - break; - case "down": - if (runnerState == "run") { - event("duck"); - } else if (runnerState == "float" && onTopOfPlatform()) { - sprite.clearEffects(); - event("run"); - } else if (runnerState == "float") { - sprite.clearEffects(); - event("fall"); - } - break; - case "right": - if (runnerState == "run") { - event("kick"); - } - break; - case "left": - if (runnerState == "kick") { - sprite.animation!.reset(); - sprite.clearEffects(); - event("run"); - } - break; - case "center": - // if (runnerState == "fall") { - // updateLevel(); - // event("float"); - // } - break; - } - } - - @override - void update(double dt) { - super.update(dt); - if (sprite.position.y + sprite.size.y >= gameRef.size.y) { - event("die"); - } - // If the animation is finished - if (sprite.animation?.done() ?? false) { - sprite.animation!.reset(); - if (runnerState == "kick") { - event("run"); - } - sprite.current = RunnerState.run; - } - - intersecting(); - sprite.update(dt); - } - - bool onTopOfPlatform() { - Rect runnerRect = sprite.toRect(); - bool onTopOfPlatform = false; - for (List platformLevel in gameRef.platformHolder.objects) { - for (MovingObject p in platformLevel) { - String side = p.intersect(runnerRect); - if (side == "none") { - Rect belowRunner = Rect.fromLTRB(runnerRect.left, runnerRect.top, - runnerRect.right, runnerRect.bottom + 1); - if (p.intersect(belowRunner) != "none") { - onTopOfPlatform = true; - } - } - } - } - return onTopOfPlatform; - } - - bool belowPlatform() { - Rect runnerRect = sprite.toRect(); - bool belowPlatform = false; - for (List platformLevel in gameRef.platformHolder.objects) { - for (MovingObject p in platformLevel) { - String side = p.intersect(runnerRect); - if (side == "none") { - Rect belowRunner = Rect.fromLTRB(runnerRect.left, runnerRect.top - 1, - runnerRect.right, runnerRect.bottom); - if (p.intersect(belowRunner) == "bottom") { - belowPlatform = true; - } - } - } - } - return belowPlatform; - } - - void intersecting() { - if (gameRef.gameState.isPaused) { - return; - } - Rect runnerRect = sprite.toRect(); - bool onTopOfPlatform = this.onTopOfPlatform(); - - for (List coinLevel in gameRef.coinHolder.objects) { - for (int i = 0; i < coinLevel.length;) { - if (coinLevel[i].intersect(runnerRect) != "none") { - gameRef.gameState.numCoins++; - gameRef.coinHolder.remove(coinLevel, i); - continue; - } - i++; - } - } - - for (List wireLevel in gameRef.wireHolder.objects) { - for (int i = 0; i < wireLevel.length; i++) { - if (wireLevel[i].intersect(runnerRect) != "none") { - event("electrocute"); - return; - } - } - } - - for (List bugLevel in gameRef.bugHolder.objects) { - for (int i = 0; i < bugLevel.length; i++) { - String intersectState = bugLevel[i].intersect(runnerRect); - if (bugLevel[i].sprite.current == BugState.breaking) { - continue; - } - if (intersectState == "none") { - Rect above = Rect.fromLTRB(runnerRect.left, runnerRect.top - 1, - runnerRect.right, runnerRect.bottom); - String aboveIntersect = bugLevel[i].intersect(above); - if (aboveIntersect != "none" && - (runnerState == "duck" || runnerState == "float")) { - continue; - } else if (aboveIntersect != "none") { - event("glitch"); - return; - } - } else if (intersectState == "left" && runnerState == "kick") { - bugLevel[i].sprite.current = BugState.breaking; - gameRef.coinHolder.generateCoin(gameRef, level, - force: true, xPosition: bugLevel[i].sprite.x + gameRef.blockSize); - } else { - event("glitch"); - return; - } - } - } - - for (List debrisLevel in gameRef.debrisHolder.objects) { - for (int i = 0; i < debrisLevel.length; i++) { - Rect slim = Rect.fromLTRB( - runnerRect.left + sprite.width / 3, - runnerRect.top, - runnerRect.right - sprite.width / 3, - runnerRect.bottom); - String intersectState = debrisLevel[i].intersect(slim); - if (intersectState == "none") { - continue; - } else if (runnerState == "duck" && intersectState != "above") { - continue; - } else { - event("die"); - } - } - } - - for (List debrisLevel in gameRef.wallHolder.objects) { - for (int i = 0; i < debrisLevel.length; i++) { - Rect slim = Rect.fromLTRB( - runnerRect.left + sprite.width / 3, - runnerRect.top + sprite.height / (runnerState == "duck" ? 3 : 6), - runnerRect.right - sprite.width / 3, - runnerRect.bottom - sprite.height / 3); - String intersectState = debrisLevel[i].intersect(slim); - if (intersectState == "none") { - continue; - } else { - event("die"); - } - } - } - - if (!onTopOfPlatform && - (runnerState == "run" || - runnerState == "kick" || - runnerState == "duck")) { - event("fall"); - } - } - - Future load(loadSpriteAnimation) async { - SpriteAnimation running = await loadSpriteAnimation( - 'run-frames.png', - SpriteAnimationData.sequenced( - amount: 7, - stepTime: 0.1, - textureSize: Vector2(512, 512), - ), - ); - - SpriteAnimation jumping = await loadSpriteAnimation( - 'jump-frames.png', - SpriteAnimationData.sequenced( - amount: 5, - stepTime: 0.1, - textureSize: Vector2(512, 512), - loop: false, - ), - ); - - SpriteAnimation ducking = await loadSpriteAnimation( - 'crawl-frames.png', - SpriteAnimationData.sequenced( - amount: 3, - stepTime: 0.1, - textureSize: Vector2(512, 512), - ), - ); - - SpriteAnimation kicking = await loadSpriteAnimation( - 'kick-frames.png', - SpriteAnimationData.sequenced( - amount: 19, - stepTime: 0.03, - textureSize: Vector2(512, 512), - loop: false, - ), - ); - - SpriteAnimation floating = await loadSpriteAnimation( - 'hover-frames.png', - SpriteAnimationData.sequenced( - amount: 3, - stepTime: 0.1, - textureSize: Vector2(512, 512), - ), - ); - - SpriteAnimation falling = await loadSpriteAnimation( - 'fall-frames.png', - SpriteAnimationData.sequenced( - amount: 7, - stepTime: 0.1, - textureSize: Vector2(512, 512), - ), - ); - - SpriteAnimation dying = await loadSpriteAnimation( - 'death-normal-frames.png', - SpriteAnimationData.sequenced( - amount: 20, - stepTime: 0.05, - textureSize: Vector2(512, 512), - loop: false, - ), - ); - - SpriteAnimation dyingElectrocuted = await loadSpriteAnimation( - 'electrocuted-frames.png', - SpriteAnimationData.sequenced( - amount: 2, - stepTime: 0.25, - textureSize: Vector2(512, 512), - loop: false, - ), - ); - - SpriteAnimation dyingGlitch = await loadSpriteAnimation( - 'death-glitched-frames.png', - SpriteAnimationData.sequenced( - amount: 8, - stepTime: 0.1, - textureSize: Vector2(512, 512), - loop: false, - ), - ); - - sprite = SpriteAnimationGroupComponent( - animations: { - RunnerState.run: running, - RunnerState.jump: jumping, - RunnerState.duck: ducking, - RunnerState.kick: kicking, - RunnerState.float: floating, - RunnerState.fall: falling, - RunnerState.die: dying, - RunnerState.electrocute: dyingElectrocuted, - RunnerState.glitch: dyingGlitch, - }, - current: RunnerState.run, - ); - - changePriorityWithoutResorting(RUNNER_PRIORITY); - } - - void resize(Vector2 newSize, double xRatio, double yRatio) { - sprite.x = gameRef.blockSize * 2; - sprite.y = gameRef.blockSize * level; - sprite.size.x = gameRef.blockSize; - sprite.size.y = gameRef.blockSize; - if (sprite.effects.isNotEmpty) { - sprite.effects.first.onComplete!(); - } - } -} +import 'package:firo_runner/bug.dart'; +import 'package:firo_runner/moving_object.dart'; +import 'package:firo_runner/main.dart'; +import 'package:flame/effects.dart'; +import 'package:flame/extensions.dart'; +import 'package:flutter/material.dart'; +import 'dart:math'; + +import 'package:flame/components.dart'; + +enum RunnerState { + run, + jump, + duck, + kick, + float, + fall, + die, + electrocute, + glitch, +} + +class Runner extends Component with HasGameRef { + late SpriteAnimationGroupComponent sprite; + String runnerState = "run"; + int level = 4; + String previousState = "run"; + var runnerPosition = Vector2(0, 0); + late Vector2 runnerSize; + // late Rect runnerRect; + bool dead = false; + + void setUp() { + dead = false; + runnerState = "run"; + previousState = "run"; + level = 4; + + runnerSize = Vector2( + gameRef.size.y / 9, + gameRef.size.y / 9, + ); + + setSize(runnerSize, gameRef.blockSize); + runnerPosition = Vector2(gameRef.blockSize * 2, gameRef.blockSize * 4); + setPosition(runnerPosition); + } + + void setPosition(Vector2 position) { + sprite.position = position; + } + + void setSize(Vector2 size, double ySize) { + sprite.size = size; + } + + Sprite getSprite() { + return sprite.animation!.getSprite(); + } + + @override + void render(Canvas c) { + super.render(c); + getSprite().render(c, position: sprite.position, size: sprite.size); + } + + void updateLevel() { + level = (sprite.position.y / gameRef.blockSize).round(); + } + + void event(String event) { + if (gameRef.gameState.isPaused) { + return; + } + switch (event) { + case "jump": + previousState = runnerState; + runnerState = event; + sprite.current = RunnerState.jump; + sprite.addEffect(MoveEffect( + path: [ + // sprite.position, + Vector2(sprite.x, (level - 1) * gameRef.blockSize), + ], + duration: 0.25, + curve: Curves.bounceIn, + onComplete: () { + updateLevel(); + this.event("float"); + }, + )); + break; + case "double_jump": + if (belowPlatform()) { + break; + } + previousState = runnerState; + sprite.clearEffects(); + if (level - 1 < 0) { + break; + } + runnerState = event; + sprite.current = RunnerState.float; + sprite.addEffect(MoveEffect( + path: [ + Vector2(sprite.x, (level - 2) * gameRef.blockSize), + ], + duration: 0.5, + curve: Curves.ease, + onComplete: () { + updateLevel(); + if (onTopOfPlatform()) { + this.event("run"); + } else { + this.event("float"); + } + }, + )); + break; + case "fall": + previousState = runnerState; + sprite.clearEffects(); + runnerState = event; + sprite.current = RunnerState.fall; + sprite.addEffect(getFallingEffect()); + break; + case "kick": + previousState = runnerState; + runnerState = event; + sprite.current = RunnerState.kick; + break; + case "run": + previousState = runnerState; + runnerState = event; + sprite.current = RunnerState.run; + break; + case "float": + previousState = runnerState; + runnerState = event; + sprite.current = RunnerState.float; + sprite.addEffect(MoveEffect( + path: [sprite.position], + duration: 1.5, + curve: Curves.ease, + onComplete: () { + updateLevel(); + if (onTopOfPlatform()) { + this.event("run"); + } else { + this.event("fall"); + } + }, + )); + break; + case "duck": + previousState = runnerState; + runnerState = event; + sprite.current = RunnerState.duck; + sprite.addEffect(MoveEffect( + path: [sprite.position], + duration: 1.5, + curve: Curves.linear, + onComplete: () { + this.event("run"); + }, + )); + break; + case "die": + if (dead) { + return; + } + previousState = runnerState; + sprite.clearEffects(); + level = 11; + sprite.addEffect(MoveEffect( + path: [Vector2(sprite.position.x, gameRef.blockSize * 11)], + duration: 2, + curve: Curves.bounceOut, + onComplete: () {}, + )); + runnerState = event; + sprite.current = RunnerState.die; + gameRef.die(); + break; + case "electrocute": + if (dead) { + return; + } + previousState = runnerState; + sprite.clearEffects(); + level = 11; + sprite.addEffect(MoveEffect( + path: [Vector2(sprite.position.x, gameRef.blockSize * 11)], + duration: 1, + curve: Curves.bounceOut, + onComplete: () {}, + )); + runnerState = event; + sprite.current = RunnerState.electrocute; + gameRef.die(); + break; + case "glitch": + if (dead) { + return; + } + previousState = runnerState; + sprite.clearEffects(); + level = 11; + sprite.addEffect(MoveEffect( + path: [Vector2(sprite.position.x, gameRef.blockSize * 11)], + duration: 1, + curve: Curves.bounceOut, + onComplete: () {}, + )); + runnerState = event; + sprite.current = RunnerState.glitch; + gameRef.die(); + break; + default: + break; + } + } + + MoveEffect getFallingEffect() { + for (int i = level; i < 9; i++) { + if (i % 3 != 2) { + continue; + } + int distance = (i - 1 - level); + double time = 0.2; + for (int x = 2; x < distance; x++) { + time += time * pow(0.5, x - 1); + } + double estimatedXCoordinate = + time * gameRef.gameState.getVelocity() + sprite.x; + for (MovingObject p in gameRef.platformHolder.objects[i]) { + if (estimatedXCoordinate >= p.sprite.x - p.sprite.width / 2 && + estimatedXCoordinate <= p.sprite.x + p.sprite.width) { + return MoveEffect( + path: [ + Vector2(sprite.x, (i - 1) * gameRef.blockSize), + ], + duration: time, + curve: Curves.ease, + onComplete: () { + updateLevel(); + if (onTopOfPlatform()) { + event("run"); + } else { + event("fall"); + } + }, + ); + } + } + } + return MoveEffect( + path: [ + Vector2(sprite.x, 8 * gameRef.blockSize), + ], + duration: 0.2 * (8 - level), + curve: Curves.ease, + onComplete: () { + updateLevel(); + if (onTopOfPlatform()) { + event("run"); + } else { + event("fall"); + } + }, + ); + } + + void control(String input) { + if (gameRef.gameState.isPaused) { + return; + } + switch (input) { + case "up": + if (runnerState == "run") { + event("jump"); + } else if (runnerState == "float" && previousState == "jump") { + event("double_jump"); + } else if (runnerState == "duck") { + sprite.clearEffects(); + event("run"); + } + break; + case "down": + if (runnerState == "run") { + event("duck"); + } else if (runnerState == "float" && onTopOfPlatform()) { + sprite.clearEffects(); + event("run"); + } else if (runnerState == "float") { + sprite.clearEffects(); + event("fall"); + } + break; + case "right": + if (runnerState == "run") { + event("kick"); + } + break; + case "left": + if (runnerState == "kick") { + sprite.animation!.reset(); + sprite.clearEffects(); + event("run"); + } + break; + case "center": + // if (runnerState == "fall") { + // updateLevel(); + // event("float"); + // } + break; + } + } + + @override + void update(double dt) { + super.update(dt); + if (sprite.position.y + sprite.size.y >= gameRef.size.y) { + event("die"); + } + // If the animation is finished + if (sprite.animation?.done() ?? false) { + sprite.animation!.reset(); + if (runnerState == "kick") { + event("run"); + } + sprite.current = RunnerState.run; + } + + if (runnerState == "float" || runnerState == "double_jump") { + if (onTopOfPlatform()) { + updateLevel(); + sprite.clearEffects(); + event("run"); + } + } + + intersecting(); + sprite.update(dt); + } + + bool onTopOfPlatform() { + Rect runnerRect = sprite.toRect(); + bool onTopOfPlatform = false; + for (List platformLevel in gameRef.platformHolder.objects) { + for (MovingObject p in platformLevel) { + String side = p.intersect(runnerRect); + if (side == "none") { + Rect belowRunner = Rect.fromLTRB(runnerRect.left, runnerRect.top, + runnerRect.right, runnerRect.bottom + 1); + if (p.intersect(belowRunner) != "none") { + onTopOfPlatform = true; + } + } + } + } + return onTopOfPlatform; + } + + bool belowPlatform() { + Rect runnerRect = Rect.fromLTRB( + sprite.toRect().left, + sprite.toRect().top, + sprite.toRect().right - sprite.toRect().width / 2, + sprite.toRect().bottom); + bool belowPlatform = false; + for (List platformLevel in gameRef.platformHolder.objects) { + for (MovingObject p in platformLevel) { + String side = p.intersect(runnerRect); + if (side == "none") { + Rect belowRunner = Rect.fromLTRB(runnerRect.left, runnerRect.top - 1, + runnerRect.right, runnerRect.bottom); + if (p.intersect(belowRunner) == "bottom") { + belowPlatform = true; + } + } + } + } + return belowPlatform; + } + + void intersecting() { + if (gameRef.gameState.isPaused) { + return; + } + Rect runnerRect = sprite.toRect(); + bool onTopOfPlatform = this.onTopOfPlatform(); + + for (List coinLevel in gameRef.coinHolder.objects) { + for (int i = 0; i < coinLevel.length;) { + if (coinLevel[i].intersect(runnerRect) != "none") { + gameRef.gameState.numCoins++; + gameRef.coinHolder.remove(coinLevel, i); + continue; + } + i++; + } + } + + for (List wireLevel in gameRef.wireHolder.objects) { + for (int i = 0; i < wireLevel.length; i++) { + if (wireLevel[i].intersect(runnerRect) != "none") { + event("electrocute"); + return; + } + } + } + + for (List bugLevel in gameRef.bugHolder.objects) { + for (int i = 0; i < bugLevel.length; i++) { + String intersectState = bugLevel[i].intersect(runnerRect); + if (bugLevel[i].sprite.current == BugState.breaking) { + continue; + } + if (intersectState == "none") { + Rect above = Rect.fromLTRB(runnerRect.left, runnerRect.top - 1, + runnerRect.right, runnerRect.bottom); + String aboveIntersect = bugLevel[i].intersect(above); + if (aboveIntersect != "none" && + (runnerState == "duck" || runnerState == "float")) { + continue; + } else if (aboveIntersect != "none") { + event("glitch"); + return; + } + } else if (intersectState == "left" && runnerState == "kick") { + bugLevel[i].sprite.current = BugState.breaking; + gameRef.coinHolder.generateCoin(gameRef, level, + force: true, xPosition: bugLevel[i].sprite.x + gameRef.blockSize); + } else { + event("glitch"); + return; + } + } + } + + for (List debrisLevel in gameRef.debrisHolder.objects) { + for (int i = 0; i < debrisLevel.length; i++) { + Rect slim = Rect.fromLTRB( + runnerRect.left + sprite.width / 3, + runnerRect.top, + runnerRect.right - sprite.width / 3, + runnerRect.bottom); + String intersectState = debrisLevel[i].intersect(slim); + if (intersectState == "none") { + continue; + } else if (runnerState == "duck" && intersectState != "above") { + continue; + } else { + event("die"); + } + } + } + + for (List debrisLevel in gameRef.wallHolder.objects) { + for (int i = 0; i < debrisLevel.length; i++) { + Rect slim = Rect.fromLTRB( + runnerRect.left + sprite.width / 3, + runnerRect.top + sprite.height / (runnerState == "duck" ? 3 : 6), + runnerRect.right - sprite.width / 3, + runnerRect.bottom - sprite.height / 3); + String intersectState = debrisLevel[i].intersect(slim); + if (intersectState == "none") { + continue; + } else { + event("die"); + } + } + } + + if (!onTopOfPlatform && + (runnerState == "run" || + runnerState == "kick" || + runnerState == "duck")) { + event("fall"); + } + } + + Future load(loadSpriteAnimation) async { + SpriteAnimation running = await loadSpriteAnimation( + 'run-frames.png', + SpriteAnimationData.sequenced( + amount: 7, + stepTime: 0.1, + textureSize: Vector2(512, 512), + ), + ); + + SpriteAnimation jumping = await loadSpriteAnimation( + 'jump-frames.png', + SpriteAnimationData.sequenced( + amount: 5, + stepTime: 0.1, + textureSize: Vector2(512, 512), + loop: false, + ), + ); + + SpriteAnimation ducking = await loadSpriteAnimation( + 'crawl-frames.png', + SpriteAnimationData.sequenced( + amount: 3, + stepTime: 0.1, + textureSize: Vector2(512, 512), + ), + ); + + SpriteAnimation kicking = await loadSpriteAnimation( + 'kick-frames.png', + SpriteAnimationData.sequenced( + amount: 19, + stepTime: 0.03, + textureSize: Vector2(512, 512), + loop: false, + ), + ); + + SpriteAnimation floating = await loadSpriteAnimation( + 'hover-frames.png', + SpriteAnimationData.sequenced( + amount: 3, + stepTime: 0.1, + textureSize: Vector2(512, 512), + ), + ); + + SpriteAnimation falling = await loadSpriteAnimation( + 'fall-frames.png', + SpriteAnimationData.sequenced( + amount: 7, + stepTime: 0.1, + textureSize: Vector2(512, 512), + ), + ); + + SpriteAnimation dying = await loadSpriteAnimation( + 'death-normal-frames.png', + SpriteAnimationData.sequenced( + amount: 20, + stepTime: 0.05, + textureSize: Vector2(512, 512), + loop: false, + ), + ); + + SpriteAnimation dyingElectrocuted = await loadSpriteAnimation( + 'electrocuted-frames.png', + SpriteAnimationData.sequenced( + amount: 2, + stepTime: 0.25, + textureSize: Vector2(512, 512), + loop: false, + ), + ); + + SpriteAnimation dyingGlitch = await loadSpriteAnimation( + 'death-glitched-frames.png', + SpriteAnimationData.sequenced( + amount: 8, + stepTime: 0.1, + textureSize: Vector2(512, 512), + loop: false, + ), + ); + + sprite = SpriteAnimationGroupComponent( + animations: { + RunnerState.run: running, + RunnerState.jump: jumping, + RunnerState.duck: ducking, + RunnerState.kick: kicking, + RunnerState.float: floating, + RunnerState.fall: falling, + RunnerState.die: dying, + RunnerState.electrocute: dyingElectrocuted, + RunnerState.glitch: dyingGlitch, + }, + current: RunnerState.run, + ); + + changePriorityWithoutResorting(RUNNER_PRIORITY); + } + + void resize(Vector2 newSize, double xRatio, double yRatio) { + sprite.x = gameRef.blockSize * 2; + sprite.y = gameRef.blockSize * level; + sprite.size.x = gameRef.blockSize; + sprite.size.y = gameRef.blockSize; + if (sprite.effects.isNotEmpty) { + sprite.effects.first.onComplete!(); + } + } +} diff --git a/lib/wall.dart b/lib/wall.dart index 6b7e9e8..327d3fa 100644 --- a/lib/wall.dart +++ b/lib/wall.dart @@ -31,7 +31,7 @@ class Wall extends MovingObject { gameRef.blockSize * (gameRef.wallHolder.wall.width / gameRef.wallHolder.wall.height / 5) * 2.0, - gameRef.blockSize * 0.5, + gameRef.blockSize * 0.35, ); }