diff --git a/Project.xml b/Project.xml index 3f930bc73..93845756c 100644 --- a/Project.xml +++ b/Project.xml @@ -129,7 +129,7 @@ - + diff --git a/hmm.json b/hmm.json index e92868545..84510a05a 100644 --- a/hmm.json +++ b/hmm.json @@ -68,7 +68,7 @@ "name": "hxcodec", "type": "git", "dir": null, - "ref": "91adeec", + "ref": "14ef69f", "url": "https://github.com/polybiusproxy/hxCodec" }, { @@ -118,4 +118,4 @@ "version": "0.2.2" } ] -} \ No newline at end of file +} diff --git a/source/funkin/CutsceneAnimTestState.hx b/source/funkin/CutsceneAnimTestState.hx deleted file mode 100644 index 7d6369c12..000000000 --- a/source/funkin/CutsceneAnimTestState.hx +++ /dev/null @@ -1,80 +0,0 @@ -package funkin; - -import flixel.FlxSprite; -import flixel.FlxState; -import flixel.addons.display.FlxGridOverlay; -import flixel.group.FlxGroup.FlxTypedGroup; -import flixel.math.FlxPoint; -import flixel.text.FlxText; -import flixel.util.FlxColor; -import openfl.Assets; -import openfl.display.BitmapData; -import openfl.display.MovieClip; -import openfl.display.Timeline; -import openfl.geom.Matrix; -import openfl.geom.Rectangle; - -class CutsceneAnimTestState extends FlxState -{ - var cutsceneGroup:CutsceneCharacter; - - var curSelected:Int = 0; - var debugTxt:FlxText; - - var funnySprite:FlxSprite = new FlxSprite(); - var clip:MovieClip; - - public function new() - { - super(); - - var gridBG:FlxSprite = FlxGridOverlay.create(10, 10); - gridBG.scrollFactor.set(0.5, 0.5); - add(gridBG); - - debugTxt = new FlxText(900, 20, 0, "", 20); - debugTxt.color = FlxColor.BLUE; - add(debugTxt); - - clip = Assets.getMovieClip("tanky:"); - // clip.x = FlxG.width/2; - // clip.y = FlxG.height/2; - FlxG.stage.addChild(clip); - - var swagShit:MovieClip = Assets.getMovieClip('tankBG:'); - // swagShit.scaleX = 5; - - FlxG.stage.addChild(swagShit); - swagShit.gotoAndStop(13); - - var swfMountain = new BitmapData(FlxG.width, FlxG.height, true, 0x00000000); - swfMountain.draw(swagShit, swagShit.transform.matrix); - - var mountains:FlxSprite = new FlxSprite().loadGraphic(swfMountain); - // add(mountains); - - FlxG.stage.removeChild(swagShit); - - funnySprite.x = FlxG.width / 2; - funnySprite.y = FlxG.height / 2; - add(funnySprite); - } - - override function update(elapsed:Float) - { - super.update(elapsed); - - // jam sprite into top left corner - var drawMatrix:Matrix = clip.transform.matrix; - var bounds:Rectangle = clip.getBounds(null); - drawMatrix.tx = -bounds.x; - drawMatrix.ty = -bounds.y; - // make bitmapdata only as big as it needs to be - var funnyBmp:BitmapData = new BitmapData(Math.ceil(bounds.width), Math.ceil(bounds.height), true, 0x00000000); - funnyBmp.draw(clip, drawMatrix, true); - funnySprite.loadGraphic(funnyBmp); - // jam sprite back into place lol - funnySprite.offset.x = -bounds.x; - funnySprite.offset.y = -bounds.y; - } -} diff --git a/source/funkin/CutsceneCharacter.hx b/source/funkin/CutsceneCharacter.hx deleted file mode 100644 index 67810bc30..000000000 --- a/source/funkin/CutsceneCharacter.hx +++ /dev/null @@ -1,75 +0,0 @@ -package funkin; - -import flixel.FlxSprite; -import flixel.group.FlxGroup.FlxTypedGroup; -import flixel.math.FlxPoint; - -class CutsceneCharacter extends FlxTypedGroup -{ - public var coolPos:FlxPoint = FlxPoint.get(); - public var animShit:Map = new Map(); - - var imageShit:String; - - public function new(x:Float, y:Float, imageShit:String) - { - super(); - - coolPos.set(x, y); - - this.imageShit = imageShit; - parseOffsets(); - createCutscene(0); - } - - // shitshow, oh well - var arrayLMFAOOOO:Array = []; - - function parseOffsets() - { - var splitShit:Array = CoolUtil.coolTextFile(Paths.file('images/cutsceneStuff/' + imageShit + "CutsceneOffsets.txt")); - - for (i in splitShit) - { - var xAndY:FlxPoint = FlxPoint.get(); - var dumbSplit:Array = i.split('---')[1].trim().split(' '); - trace('cool split: ' + i.split('---')[1]); - trace(dumbSplit); - xAndY.set(Std.parseFloat(dumbSplit[0]), Std.parseFloat(dumbSplit[1])); - - animShit.set(i.split('---')[0].trim(), xAndY); - arrayLMFAOOOO.push(i.split('---')[0].trim()); - } - - trace(animShit); - } - - public function createCutscene(daNum:Int = 0) - { - var cutScene:FlxSprite = new FlxSprite(coolPos.x + animShit.get(arrayLMFAOOOO[daNum]).x, coolPos.y + animShit.get(arrayLMFAOOOO[daNum]).y); - cutScene.frames = Paths.getSparrowAtlas('cutsceneStuff/' + imageShit + "-" + daNum); - cutScene.animation.addByPrefix('weed', arrayLMFAOOOO[daNum], 24, false); - cutScene.animation.play('weed'); - cutScene.antialiasing = true; - - cutScene.animation.finishCallback = function(anim:String) - { - cutScene.kill(); - cutScene.destroy(); - cutScene = null; - - if (daNum + 1 < arrayLMFAOOOO.length) createCutscene(daNum + 1); - else - ended(); - }; - - add(cutScene); - } - - public var onFinish:Void->Void; - - public function ended():Void - { - if (onFinish != null) onFinish(); - } -} diff --git a/source/funkin/play/cutscene/VanillaCutscenes.hx b/source/funkin/play/cutscene/VanillaCutscenes.hx index a0cbd965b..a332d0795 100644 --- a/source/funkin/play/cutscene/VanillaCutscenes.hx +++ b/source/funkin/play/cutscene/VanillaCutscenes.hx @@ -1,13 +1,10 @@ package funkin.play.cutscene; -// import hxcodec.flixel.FlxVideoSprite; -// import hxcodec.flixel.FlxCutsceneState; import flixel.FlxSprite; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.util.FlxColor; import flixel.util.FlxTimer; -import funkin.graphics.video.FlxVideo; /** * Static methods for playing cutscenes in the PlayState. @@ -15,112 +12,46 @@ import funkin.graphics.video.FlxVideo; */ class VanillaCutscenes { - /** - * Well, well, well, what have we got here? - */ - public static function playUghCutscene():Void - { - playVideoCutscene('music/ughCutscene.mp4'); - } - - /** - * Nice bars for an ugly, boring teenager! - */ - public static function playGunsCutscene():Void - { - playVideoCutscene('music/gunsCutscene.mp4'); - } - - /** - * Don't you have a school to shoot up? - */ - public static function playStressCutscene():Void - { - playVideoCutscene('music/stressCutscene.mp4'); - } - static var blackScreen:FlxSprite; - /** - * Plays a cutscene from a video file, then starts the countdown once the video is done. - * TODO: Cutscene is currently skipped on native platforms. - */ - static function playVideoCutscene(path:String):Void - { - // Tell PlayState to stop the song until the video is done. - PlayState.isInCutscene = true; - PlayState.instance.camHUD.visible = false; - - // Display a black screen to hide the game while the video is playing. - blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); - blackScreen.scrollFactor.set(0, 0); - blackScreen.cameras = [PlayState.instance.camCutscene]; - PlayState.instance.add(blackScreen); - - #if html5 - // Video displays OVER the FlxState. - vid = new FlxVideo(path); - vid.finishCallback = finishCutscene.bind(0.5); - #else - // Video displays OVER the FlxState. - // vid = new FlxVideoSprite(0, 0); - - vid.cameras = [PlayState.instance.camCutscene]; - - PlayState.instance.add(vid); - - vid.playVideo(Paths.file(path), false); - vid.onEndReached.add(finishCutscene.bind(0.5)); - #end - } - - static var vid:#if html5 FlxVideo #else Dynamic /**FlxVideoSprite **/ #end; + static final TWEEN_DURATION:Float = 2.0; /** - * Does the cleanup to start the countdown after the video is done. - * Gets called immediately if the video can't be played. - */ - public static function finishCutscene(?transitionTime:Float = 2.5):Void - { - trace('ALERT: Finish cutscene called!'); - - #if html5 - #else - vid.stop(); - PlayState.instance.remove(vid); - #end - - PlayState.instance.camHUD.visible = true; - - FlxTween.tween(blackScreen, {alpha: 0}, transitionTime, - { - ease: FlxEase.quadInOut, - onComplete: function(twn:FlxTween) { - PlayState.instance.remove(blackScreen); - blackScreen = null; - } - }); - FlxTween.tween(FlxG.camera, {zoom: PlayState.defaultCameraZoom}, transitionTime, - { - ease: FlxEase.quadInOut, - onComplete: function(twn:FlxTween) { - PlayState.instance.startCountdown(); - } - }); - } - - /** - * FNF corruption mod??? + * Plays the cutscene that appears at the start of Winter Horrorland. + * TODO: Move this to `winter-horrorland.hxc` */ public static function playHorrorStartCutscene():Void { - PlayState.isInCutscene = true; + PlayState.instance.isInCutscene = true; PlayState.instance.camHUD.visible = false; blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); blackScreen.scrollFactor.set(0, 0); + blackScreen.zIndex = 1000000; PlayState.instance.add(blackScreen); - new FlxTimer().start(0.1, _ -> finishCutscene(2.5)); + new FlxTimer().start(0.1, function(_) { + trace('Playing horrorland cutscene...'); + PlayState.instance.remove(blackScreen); + + // Force set the camera position and zoom. + PlayState.instance.cameraFollowPoint.setPosition(400, -2050); + PlayState.instance.resetCamera(); + FlxG.camera.zoom = 2.5; + + // Play the Sound effect. + FlxG.sound.play(Paths.sound('Lights_Turn_On'), function() { + // Fade in the HUD. + trace('SFX done...'); + PlayState.instance.camHUD.visible = true; + PlayState.instance.camHUD.alpha = 0.0; // Use alpha rather than visible to let us fade it in. + FlxTween.tween(PlayState.instance.camHUD, {alpha: 1.0}, TWEEN_DURATION, {ease: FlxEase.quadInOut}); + + // Start the countdown. + trace('Zoom out done...'); + trace('Begin countdown (ends cutscene)'); + PlayState.instance.startCountdown(); + }); + }); } } diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx new file mode 100644 index 000000000..fe0cf9bbb --- /dev/null +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -0,0 +1,155 @@ +package funkin.play.cutscene; + +import funkin.play.PlayState; +import flixel.FlxSprite; +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import flixel.util.FlxColor; +import flixel.util.FlxTimer; +#if html5 +import funkin.graphics.video.FlxVideo; +#else +import hxcodec.flixel.FlxVideoSprite; +#end + +/** + * Assumes you are in the PlayState. + */ +class VideoCutscene +{ + static var blackScreen:FlxSprite; + + /** + * Play a video cutscene. + * TODO: Currently this is hardcoded to start the countdown after the video is done. + * @param path The path to the video file. Use Paths.file(path) to get the correct path. + */ + public static function play(filePath:String):Void + { + if (PlayState.instance == null) return; + + if (!openfl.Assets.exists(filePath)) + { + trace('ERROR: Video file does not exist: ${filePath}'); + return; + } + + // Trigger the cutscene. Don't play the song in the background. + PlayState.instance.isInCutscene = true; + PlayState.instance.camHUD.visible = false; + PlayState.instance.camCutscene.visible = true; + + // Display a black screen to hide the game while the video is playing. + blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK); + blackScreen.scrollFactor.set(0, 0); + blackScreen.cameras = [PlayState.instance.camCutscene]; + PlayState.instance.add(blackScreen); + + #if html5 + playVideoHTML5(filePath); + #else + playVideoNative(filePath); + #end + } + + public static function isPlaying():Bool + { + return vid != null; + } + + #if html5 + static var vid:FlxVideo; + + static function playVideoHTML5(filePath:String):Void + { + // Video displays OVER the FlxState. + vid = new FlxVideo(filePath); + if (vid != null) + { + vid.zIndex = 0; + + vid.finishCallback = finishVideo.bind(0.5); + + vid.cameras = [PlayState.instance.camCutscene]; + + PlayState.instance.add(vid); + + PlayState.instance.refresh(); + } + else + { + trace('ALERT: Video is null! Could not play cutscene!'); + } + } + #else + static var vid:FlxVideoSprite; + + static function playVideoNative(filePath:String):Void + { + // Video displays OVER the FlxState. + vid = new FlxVideoSprite(0, 0); + + if (vid != null) + { + vid.zIndex = 0; + vid.onEndReached.add(finishVideo.bind(0.5)); + + vid.cameras = [PlayState.instance.camCutscene]; + + PlayState.instance.add(vid); + + PlayState.instance.refresh(); + vid.playVideo(filePath, false); + } + else + { + trace('ALERT: Video is null! Could not play cutscene!'); + } + } + #end + + public static function finishVideo(?transitionTime:Float = 0.5):Void + { + trace('ALERT: Finish video cutscene called!'); + + #if html5 + if (vid != null) + { + PlayState.instance.remove(vid); + } + #else + if (vid != null) + { + vid.stop(); + PlayState.instance.remove(vid); + } + #end + vid.destroy(); + vid = null; + + PlayState.instance.camCutscene.visible = true; + PlayState.instance.camHUD.visible = true; + + FlxTween.tween(blackScreen, {alpha: 0}, transitionTime, + { + ease: FlxEase.quadInOut, + onComplete: function(twn:FlxTween) { + PlayState.instance.remove(blackScreen); + blackScreen = null; + } + }); + FlxTween.tween(FlxG.camera, {zoom: PlayState.instance.defaultCameraZoom}, transitionTime, + { + ease: FlxEase.quadInOut, + onComplete: function(twn:FlxTween) { + PlayState.instance.startCountdown(); + } + }); + } +} + +/* + trace('Video playback failed (${e})'); + vid = null; + finishCutscene(0.5); + */