|
| 1 | +class_name SlideShow extends Node2D |
| 2 | + |
| 3 | + |
| 4 | +## The initial slideshow in a videogame |
| 5 | +## |
| 6 | +## This is made easy |
| 7 | + |
| 8 | + |
| 9 | +enum { |
| 10 | + SKIP_PREV = -1, |
| 11 | + SKIP_NEXT = +1, |
| 12 | +} |
| 13 | + |
| 14 | +## Emitted when the slideshow is finished |
| 15 | +signal finished() |
| 16 | +## Emitted when a slide is skipped |
| 17 | +signal slide_skipped(skip_direction: int) |
| 18 | + |
| 19 | +@export_category("Presentation settings") |
| 20 | +## Starts the presentation automatically when ready |
| 21 | +@export var autoplay: bool = true |
| 22 | +## How much long the slide is shown. It does not take in the [member SlideShow.slide_fade_duration] fadein/fadeout time. |
| 23 | +@export_range(1.0, 10.0, 0.1) var slide_duration: float = 6.0 |
| 24 | +@export_range(0.0, 3.0) var slide_fade_duration: float = 1.0 |
| 25 | + |
| 26 | +## Current slide index. |
| 27 | +var current_slide: int = 0 |
| 28 | +## Is [code]true[/code] if there is a previous slide, [code]false[/code] otherwise. |
| 29 | +var has_prev: bool: |
| 30 | + get: |
| 31 | + return current_slide > 0 and slides.size() > 0 |
| 32 | +## Is [code]true[/code] if there is a next slide, [code]false[/code] otherwise. |
| 33 | +var has_next: bool: |
| 34 | + get: |
| 35 | + return current_slide < slides.size() |
| 36 | +## If [code]true[/code] the slide is playing, [code]false[/code] otherwise. |
| 37 | +var playing: bool = true: |
| 38 | + get: |
| 39 | + return playing |
| 40 | + set(value): |
| 41 | + playing = value |
| 42 | + |
| 43 | + if value and autoplay: |
| 44 | + _handle_next_slide() |
| 45 | +var slides: Array[Node2D]: |
| 46 | + get: |
| 47 | + var _s = [] as Array[Node2D] |
| 48 | + |
| 49 | + for child in get_children(): |
| 50 | + if child is Node2D: |
| 51 | + _s.append(child) |
| 52 | + |
| 53 | + return _s |
| 54 | + |
| 55 | + |
| 56 | +func _handle_slide_in(slide: Node2D) -> void: |
| 57 | + if slide.has_method("_slide_in"): |
| 58 | + slide.call("_slide_in") |
| 59 | + |
| 60 | + |
| 61 | +func _handle_slide_out(slide: Node2D) -> void: |
| 62 | + if slide.has_method("_slide_out"): |
| 63 | + slide.call("_slide_out") |
| 64 | + |
| 65 | + |
| 66 | +## Forcefully |
| 67 | +func _forcefully_fade_current() -> Tween: |
| 68 | + var tween = create_tween() |
| 69 | + var slide = slides[current_slide] as Node2D |
| 70 | + |
| 71 | + tween.tween_property(slide, "modulate:a", 0.0, slide_fade_duration) |
| 72 | + |
| 73 | + return tween |
| 74 | + |
| 75 | + |
| 76 | +## Handles next slide. Called internally, use [method SlideShow.skip_to_prev], [method SlideShow.skip_to_next], [method SlideShow.skip_to_nth] or [method SlideShow.skip_all] |
| 77 | +func _handle_next_slide(direction: int = SKIP_NEXT) -> void: |
| 78 | + if current_slide >= slides.size(): |
| 79 | + finished.emit() |
| 80 | + else: |
| 81 | + var tween = create_tween() |
| 82 | + var slide = slides[current_slide] as Node2D |
| 83 | + |
| 84 | + if slide == null: |
| 85 | + printerr("This should NEVER happen, what have you done?") |
| 86 | + _handle_next_slide() |
| 87 | + |
| 88 | + _handle_slide_in(slide) |
| 89 | + |
| 90 | + tween.tween_property(slide, "modulate:a", 1.0, slide_fade_duration) |
| 91 | + tween.tween_interval(slide_duration - (slide_fade_duration * 2)) |
| 92 | + tween.tween_property(slide, "modulate:a", 0.0, slide_fade_duration) |
| 93 | + |
| 94 | + tween.finished.connect(func (): |
| 95 | + _handle_slide_out(slide) |
| 96 | + current_slide += direction |
| 97 | + _handle_next_slide() |
| 98 | + ) |
| 99 | + |
| 100 | +## Ready fn |
| 101 | +func _ready() -> void: |
| 102 | + playing = autoplay |
| 103 | + |
| 104 | + for slide in slides: |
| 105 | + slide.modulate.a = 0.0 |
| 106 | + |
| 107 | + |
| 108 | +## Sets [member SlideShow.playing] to [code]true[/code] |
| 109 | +func play() -> void: |
| 110 | + current_slide = 0 |
| 111 | + playing = true |
| 112 | + |
| 113 | + |
| 114 | +## Skips all slides and the [signal SlideShow.finished] is emitted. |
| 115 | +## [br] |
| 116 | +## GG mate, we worked hard for this. |
| 117 | +func skip_all() -> void: |
| 118 | + skip_slide_to_nth(get_child_count() + 1) |
| 119 | + |
| 120 | + |
| 121 | +## Skips to the next slide if any, otherwise the slideshow ends and the [signal SlideShow.finished] is emitted. |
| 122 | +func skip_slide_to_next() -> void: |
| 123 | + skip_slide_to_nth(current_slide + 1) |
| 124 | + |
| 125 | + |
| 126 | +## Skips to a nth slide. If out of bound, the slideshow ends and the [signal SlideShow.finished] is emitted. |
| 127 | +func skip_slide_to_nth(slide_index: int) -> void: |
| 128 | + var direction = SKIP_NEXT if slide_index > current_slide else SKIP_PREV |
| 129 | + var inbound = slide_index >= 0 and slide_index <= slides.size() |
| 130 | + |
| 131 | + if not inbound: |
| 132 | + playing = false |
| 133 | + finished.emit() |
| 134 | + return |
| 135 | + |
| 136 | + if current_slide >= slides.size(): |
| 137 | + finished.emit() |
| 138 | + else: |
| 139 | + var tween = create_tween() |
| 140 | + var slide = slides[current_slide] as Node2D |
| 141 | + |
| 142 | + slide_skipped.emit(direction) |
| 143 | + |
| 144 | + ## Forcefully fades out current slide. You asked for it, do not complain plis. |
| 145 | + tween.tween_property(slide, "modulate:a", 0.0, slide_fade_duration) |
| 146 | + |
| 147 | + tween.finished.connect(func (): |
| 148 | + current_slide += direction |
| 149 | + _handle_slide_out(slide) |
| 150 | + _handle_next_slide(direction) |
| 151 | + ) |
| 152 | + |
| 153 | + |
| 154 | +## Skips to the previous slide if any, otherwise the slideshow ends and the [signal SlideShow.finished] is emitted. |
| 155 | +func skip_slide_to_prev() -> void: |
| 156 | + skip_slide_to_nth(current_slide - 1) |
| 157 | + |
| 158 | + |
0 commit comments