diff --git a/js/Game.js b/js/Game.js index b82befa..bb58bd2 100644 --- a/js/Game.js +++ b/js/Game.js @@ -71,7 +71,13 @@ export class Game this.architecture.draw(this.context, this.camera); this.mrCroc.draw(this.context, this.camera); this.gisela.draw(this.context, this.camera); - this.userInterface.draw(this.context); + + for (const effect of this.level.fullscreenEffects) { + effect.update(timestamp); + effect.render(this.context); + } + + this.userInterface.draw(this.context); this.lastRendered = timestamp; } diff --git a/js/Level.js b/js/Level.js index 80c4e81..23d4ecd 100644 --- a/js/Level.js +++ b/js/Level.js @@ -1,5 +1,6 @@ import FileLoader from "./FileLoader.js"; import Terrain from "../tilorswift/js/Terrain.js"; +import {FullscreenEffectFactory} from "./effects/FullscreenEffectFactory.js"; export default class Level { @@ -8,6 +9,7 @@ export default class Level constructor(terrain) { this.terrain = terrain; + this.fullscreenEffects = []; this.gravity = 2.0; } @@ -83,7 +85,6 @@ export default class Level const json = JSON.parse(data); const level = new Level(Terrain.createFromJson(json)); level.setGravity(json.gravity / Level.FACTOR_GRAVITY); - callback(level); } loader.loadContent(); @@ -97,6 +98,16 @@ export default class Level const level = new Level(terrain); level.setGravity(data.gravity / Level.FACTOR_GRAVITY); + if (data.hasOwnProperty('effects')) { + const effectFactory = new FullscreenEffectFactory(); + + for (const effect of data.effects) { + level.fullscreenEffects.push( + effectFactory.getEffect(effect) + ); + } + } + return level; } } diff --git a/js/effects/FullscreenEffect.js b/js/effects/FullscreenEffect.js new file mode 100644 index 0000000..66ab38a --- /dev/null +++ b/js/effects/FullscreenEffect.js @@ -0,0 +1,22 @@ +export class FullscreenEffect +{ + static NAME = ''; + + constructor(canvas) + { + this.canvas = canvas; + } + + update(timestamp) + { + } + + render(context) + { + } + + getName() + { + return this.constructor.NAME; + } +} diff --git a/js/effects/FullscreenEffectFactory.js b/js/effects/FullscreenEffectFactory.js new file mode 100644 index 0000000..a4f8fc9 --- /dev/null +++ b/js/effects/FullscreenEffectFactory.js @@ -0,0 +1,27 @@ +import {SnowEffect} from "./SnowEffect.js"; + +export class FullscreenEffectFactory +{ + static EFFECTS = { + [SnowEffect.NAME]: SnowEffect, + } + + getEffect(name) + { + return new FullscreenEffectFactory.EFFECTS[name](); + } + + static getNames() + { + const names = []; + + for (const name in FullscreenEffectFactory.EFFECTS) { + console.log(name); + names.push(name); + } + + console.log(names); + + return names; + } +} diff --git a/js/effects/SnowEffect.js b/js/effects/SnowEffect.js new file mode 100644 index 0000000..2011fa2 --- /dev/null +++ b/js/effects/SnowEffect.js @@ -0,0 +1,31 @@ +import {FullscreenEffect} from "./FullscreenEffect.js"; + +export class SnowEffect extends FullscreenEffect +{ + static NAME = 'snow'; + + constructor() + { + super(); + this.image = new Image(); + this.image.src = '/js/effects/snow.png'; + this.offset = 0; + } + + update(timestamp) + { + super.update(timestamp); + this.offset = timestamp % 512; + } + + render(context) + { + super.render(context); + + for (let y = -1; y < Math.ceil(context.canvas.height / 512); y++) { + for (let x = -1; x < Math.ceil(context.canvas.width / 512); x++) { + context.drawImage(this.image, this.offset + 512 * x, this.offset + 512 * y); + } + } + } +} diff --git a/js/effects/snow.png b/js/effects/snow.png new file mode 100644 index 0000000..ecf8d41 Binary files /dev/null and b/js/effects/snow.png differ diff --git a/tilorswift/js/Tilorswift.js b/tilorswift/js/Tilorswift.js index 7eea964..267134f 100644 --- a/tilorswift/js/Tilorswift.js +++ b/tilorswift/js/Tilorswift.js @@ -17,19 +17,27 @@ import TilorswiftMenuSaveClickedEvent from "./events/TilorswiftMenuSaveClickedEv import TilorswiftAddRowsClickedEvent from "./events/TilorswiftAddRowsClickedEvent.js"; import TilorswiftAddColumnsClickedEvent from "./events/TilorswiftAddColumnsClickedEvent.js"; import TilorswiftMenuGravityClickedEvent from "./events/TilorswiftMenuGravityClickedEvent.js"; +import TilorswiftMenuEffectsClickedEvent from "./events/TilorswiftMenuEffectsClickedEvent.js"; import TilorswiftEvent from "./events/TilorswiftEvent.js"; import BrushMode from "./BrushMode.js"; import DialogNewTerrain from "./dialog/DialogNewTerrain.js"; import DialogGravity from "./dialog/DialogGravity.js"; +import DialogEffects from "./dialog/DialogEffects.js"; import DialogAddRows from "./dialog/DialogAddRows.js"; import DialogAddColumns from "./dialog/DialogAddColumns.js"; import Terrain from "./Terrain.js"; import TilorswiftSavedEvent from "./events/TilorswiftSavedEvent.js"; import Level from "../../js/Level.js"; import {IntelligentBrushSwitch} from "./menu/IntelligentBrushSwitch.js"; +import {SnowEffect} from "../../js/effects/SnowEffect.js"; +import {FullscreenEffectFactory} from "../../js/effects/FullscreenEffectFactory.js"; export default class Tilorswift { + static EFFECT_NAMES = { + [SnowEffect.NAME]: 'Schnee', + } + constructor(level) { this.level = level; this.map = document.getElementById('map'); @@ -65,6 +73,7 @@ export default class Tilorswift const menuLevel = new MenuGroup('Level'); menuLevel.addMenuEntry(new MainMenuEntry('Gravitation...', TilorswiftMenuGravityClickedEvent)); + menuLevel.addMenuEntry(new MainMenuEntry('Effekte...', TilorswiftMenuEffectsClickedEvent)); this.mainbar.addMenuGroup(menuLevel); document.body.appendChild(this.mainbar.getElement()); @@ -96,6 +105,7 @@ export default class Tilorswift targetY: this.level.getTargetY(), gravity: this.level.gravity, matrix: matrix, + effects: this.level.fullscreenEffects.map((effect) => {return effect.getName()}), }; return JSON.stringify(data); @@ -105,6 +115,7 @@ export default class Tilorswift { const dialog = new LoadLevelDialog(); dialog.onLoad = (json) => { + console.log(json); this.tileset = new Tileset(JSON.parse(json).tileset); this.level = Level.createFromJson(json); this.loadLevel(); @@ -297,6 +308,25 @@ export default class Tilorswift } ); + window.addEventListener( + TilorswiftEvent.MENU_EFFECTS_CLICKED, + () => { + const effects = []; + + for (const effect of this.level.fullscreenEffects) { + effects.push(effect.getName()); + } + + new DialogEffects( + FullscreenEffectFactory.getNames(), + effects, + { + [SnowEffect.NAME]: 'Schnee', + } + ); + } + ); + window.addEventListener( TilorswiftEvent.ADD_ROWS_CLICKED, () => { @@ -318,6 +348,21 @@ export default class Tilorswift } ); + window.addEventListener( + TilorswiftEvent.EFFECTS_UPDATED, + (event) => { + this.level.fullscreenEffects = []; + + const effectFactory = new FullscreenEffectFactory(); + + for (const effectName of event.effectNames) { + this.level.fullscreenEffects.push( + effectFactory.getEffect(effectName) + ); + } + } + ); + window.addEventListener( TilorswiftEvent.ADD_ROWS, (event) => { diff --git a/tilorswift/js/dialog/Dialog.js b/tilorswift/js/dialog/Dialog.js index 14810d9..1f02aa5 100644 --- a/tilorswift/js/dialog/Dialog.js +++ b/tilorswift/js/dialog/Dialog.js @@ -1,6 +1,7 @@ import GraphicSet from "../../../js/GraphicSet.js"; import Setting from "../../../js/Setting.js"; import TilorswiftTilesetSelectedEvent from "../events/TilorswiftTilesetSelectedEvent.js"; +import {Checkbox} from "./elements/Checkbox.js"; export default class Dialog { @@ -66,6 +67,16 @@ export default class Dialog return htmlElementInput; } + createCheckbox(label, value, isChecked = false, onClick = () => {}) + { + const checkbox = new Checkbox(label, value, isChecked); + checkbox.onClick = onClick; + + this.inputAreaElement.appendChild(checkbox.htmlElement); + + return checkbox; + } + createTilesetSelector() { let htmlElement = document.createElement('div'); @@ -133,6 +144,8 @@ export default class Dialog return htmlElement; } + + createFileInput(types = []) { let input = document.createElement('input'); diff --git a/tilorswift/js/dialog/DialogEffects.js b/tilorswift/js/dialog/DialogEffects.js new file mode 100644 index 0000000..960d1af --- /dev/null +++ b/tilorswift/js/dialog/DialogEffects.js @@ -0,0 +1,45 @@ +import Dialog from "./Dialog.js"; +import TilorswiftEffectsUpdatedEvent from "../events/TilorswiftEffectsUpdatedEvent.js"; + +export default class DialogEffects extends Dialog +{ + constructor(effects, checked, translations) + { + super(); + this.setMessage('Effekte'); + this.effects = []; + + for (const effect of effects) { + const checkbox = this.createCheckbox( + translations[effect], + effect, + checked.indexOf(effect) !== -1, + () => { + console.log(checkbox.name, 'is', checkbox.isChecked()); + } + ); + + this.effects.push(checkbox); + this.inputAreaElement.appendChild(checkbox.htmlElement); + } + + this.createButton('Abbrechen'); + this.buttonOk = this.createButton('OK'); + this.buttonOk.addEventListener( + 'click', + () => { + const effectNames = []; + + for (const effect of this.effects) { + if (effect.isChecked()) { + effectNames.push(effect.name); + } + } + + window.dispatchEvent( + new TilorswiftEffectsUpdatedEvent(effectNames) + ); + } + ) + } +} diff --git a/tilorswift/js/dialog/elements/Checkbox.js b/tilorswift/js/dialog/elements/Checkbox.js new file mode 100644 index 0000000..e7a4d63 --- /dev/null +++ b/tilorswift/js/dialog/elements/Checkbox.js @@ -0,0 +1,29 @@ +export class Checkbox +{ + constructor(label, name, isChecked = false) + { + this.name = name; + + this.htmlElement = document.createElement('div'); + + this.onClick = () => {}; + + this.checkbox = document.createElement('input'); + this.checkbox.type = 'checkbox'; + this.checkbox.checked = isChecked; + this.checkbox.onclick = () => { + this.onClick(); + } + + this.htmlLabel = document.createElement('label'); + this.htmlLabel.innerText = label; + + this.htmlElement.appendChild(this.checkbox); + this.htmlElement.appendChild(this.htmlLabel); + } + + isChecked() + { + return this.checkbox.checked; + } +} diff --git a/tilorswift/js/events/TilorswiftEffectsUpdatedEvent.js b/tilorswift/js/events/TilorswiftEffectsUpdatedEvent.js new file mode 100644 index 0000000..e71db56 --- /dev/null +++ b/tilorswift/js/events/TilorswiftEffectsUpdatedEvent.js @@ -0,0 +1,9 @@ +import TilorswiftEvent from "./TilorswiftEvent.js"; + +export default class TilorswiftEffectsUpdatedEvent extends Event +{ + constructor(effectNames) { + super(TilorswiftEvent.EFFECTS_UPDATED); + this.effectNames = effectNames; + } +} diff --git a/tilorswift/js/events/TilorswiftEvent.js b/tilorswift/js/events/TilorswiftEvent.js index 791d092..523d4f6 100644 --- a/tilorswift/js/events/TilorswiftEvent.js +++ b/tilorswift/js/events/TilorswiftEvent.js @@ -17,6 +17,7 @@ const TilorswiftEvent = { TILESET_SELECTED: 'tilesetSelected', MENU_GRAVITY_CLICKED: 'menuGravityClicked', GRAVITY_UPDATED: 'gravityUpdated', + MENU_EFFECTS_CLICKED: 'menuEffectsClicked', }; export default TilorswiftEvent; diff --git a/tilorswift/js/events/TilorswiftMenuEffectsClickedEvent.js b/tilorswift/js/events/TilorswiftMenuEffectsClickedEvent.js new file mode 100644 index 0000000..220a2e0 --- /dev/null +++ b/tilorswift/js/events/TilorswiftMenuEffectsClickedEvent.js @@ -0,0 +1,9 @@ +import TilorswiftEvent from "./TilorswiftEvent.js"; + +export default class TilorswiftMenuEffectsClickedEvent extends Event +{ + constructor() + { + super(TilorswiftEvent.MENU_EFFECTS_CLICKED); + } +}