diff --git a/js/Gisela.js b/js/Gisela.js new file mode 100644 index 0000000..7ea26ff --- /dev/null +++ b/js/Gisela.js @@ -0,0 +1,10 @@ +import RetroAnimation from "./retro/RetroAnimation.js"; +import Movable from "./Movable.js"; + +export default class Gisela extends Movable +{ + constructor() { + const SCALE = 2; + super(new RetroAnimation('graphics/gisela-right.png', 1, SCALE, 1)); + } +} \ No newline at end of file diff --git a/js/MrCroc.js b/js/MrCroc.js index 6b1b8ea..2bdf574 100644 --- a/js/MrCroc.js +++ b/js/MrCroc.js @@ -4,7 +4,7 @@ import RetroAnimation from "./retro/RetroAnimation.js"; export default class MrCroc extends Movable { constructor() { - let SCALE = 2; + const SCALE = 2; super(new RetroAnimation('graphics/mr-croc-walk-right.png', 2, SCALE), 7); this.isJumping = false; this.addAnimation('WALK_RIGHT', new RetroAnimation('graphics/mr-croc-walk-right.png', 2, SCALE, 10)); diff --git a/js/module.js b/js/module.js index 9d5683b..939ba30 100644 --- a/js/module.js +++ b/js/module.js @@ -1,8 +1,11 @@ +'use strict'; + import Key from "./Key.js"; import MrCroc from "./MrCroc.js"; import RetroArchitecture from "./retro/RetroArchitecture.js"; import FileLoader from "./FileLoader.js"; import Camera from "./Camera.js"; +import Gisela from "./Gisela.js"; class ImageLoader { @@ -78,7 +81,7 @@ function MainLoop(timestamp) } /* Movement left and right */ - if (KeyLeft.isPressed()) { + if (!hasPlayerLeftArchitecture && KeyLeft.isPressed()) { let lastWallLeft = Math.min( architecture.getWallLeft(mrCroc.getPositionHeadLeft()), architecture.getWallLeft(mrCroc.getPositionFootLeft()) @@ -89,7 +92,7 @@ function MainLoop(timestamp) if (mrCroc.position.x <= lastWallLeft + mrCroc.getWidth() * 0.5) { mrCroc.position.x = lastWallLeft + mrCroc.getWidth() * 0.5 + 1; } - } else if (KeyRight.isPressed()) { + } else if (!hasPlayerLeftArchitecture && KeyRight.isPressed()) { let lastWallRight = Math.max( architecture.getWallRight(mrCroc.getPositionHeadRight()), architecture.getWallRight(mrCroc.getPositionFootRight()) @@ -102,8 +105,27 @@ function MainLoop(timestamp) } } - if (!architecture.isInsideArchitecture(mrCroc.position)) { - architecture.resetMovableToStartPosition(mrCroc); + if (!hasPlayerLeftArchitecture && !architecture.isInsideArchitecture(mrCroc.position)) { + hasPlayerLeftArchitecture = true; + + setTimeout( + function () { + architecture.setMovableToStartPosition(mrCroc); + hasPlayerLeftArchitecture = false; + }, 2000 + ); + } + + if (!gameFinished && architecture.isMovableInsideTargetPosition(mrCroc)) { + gameFinished = true; + + setTimeout( + function () { + alert('Gisela: "Thanks for showing up, Mr. Croc, but I\'m not in danger."'); + lastTimestamp = timestamp; + lastRendered = timestamp; + }, 1000 + ) } /* Drawing */ @@ -113,19 +135,7 @@ function MainLoop(timestamp) camera.centerCamera(mrCroc.position.x - mrCroc.getWidth() * 0.5, mrCroc.position.y - mrCroc.getHeight() * 0.5); architecture.draw(context, camera); mrCroc.draw(context, camera); - - /* - context.fillRect(0, ceilingHeight, window.innerWidth, 1); - context.fillRect(0, groundHeight, window.innerWidth, 1); - context.fillStyle = 'black'; - context.fillRect(lastWallRight, 0, 1, window.innerHeight); - context.fillStyle = 'red'; - context.fillRect(lastWallLeft, 0, 1, window.innerHeight); - mrCroc.getPositionHeadRight().draw(context); - mrCroc.getPositionFootRight().draw(context); - mrCroc.getPositionHeadLeft().draw(context); - mrCroc.getPositionFootLeft().draw(context); - */ + gisela.draw(context, camera); lastRendered = timestamp; } @@ -147,8 +157,10 @@ const LEVEL = JSON.parse(levelJson.getContent()); let lastRendered = undefined; let lastTimestamp = undefined; let context; -let mrCroc, architecture; +let mrCroc, gisela, architecture; let camera = new Camera(); +let gameFinished = false; +let hasPlayerLeftArchitecture = false; let KeyLeft = new Key('ArrowLeft'); let KeyRight = new Key('ArrowRight'); @@ -168,6 +180,10 @@ let imgArch = new Image(); imgArch.src = 'graphics/tileset-landscape01.jpg'; loader.addImage(imgArch); +let imgGisela = new Image(); +imgGisela.src = 'graphics/gisela-right.png'; +loader.addImage(imgGisela); + window.addEventListener( 'imagesloaded', () => { @@ -190,11 +206,10 @@ window.addEventListener( camera.borderBottom = architecture.rows * architecture.tileHeight; mrCroc = new MrCroc(); - architecture.resetMovableToStartPosition(mrCroc); - /* - mrCroc.position.x = architecture.tileWidth * LEVEL.startX + architecture.tileWidth * 0.5; - mrCroc.position.y = architecture.tileHeight * LEVEL.startY; - */ + architecture.setMovableToStartPosition(mrCroc); + + gisela = new Gisela(); + architecture.setMovableToTargetPosition(gisela); window.requestAnimationFrame(MainLoop); } diff --git a/js/retro/RetroArchitecture.js b/js/retro/RetroArchitecture.js index 3064041..1159115 100644 --- a/js/retro/RetroArchitecture.js +++ b/js/retro/RetroArchitecture.js @@ -17,6 +17,8 @@ export default class RetroArchitecture this.tileHeight = this.tileset.getHeight(); this.startX = 0; this.startY = 0; + this.targetX = 0; + this.targetY = 0; this.init(); } @@ -158,12 +160,33 @@ export default class RetroArchitecture return architectureRect.isContainingPoint(geometryPoint); } - resetMovableToStartPosition(movable) + setMovableToStartPosition(movable) { movable.position.x = this.tileWidth * this.startX + this.tileWidth * 0.5; movable.position.y = this.tileHeight * this.startY + this.tileHeight * 0.5; } + setMovableToTargetPosition(movable) + { + movable.position.x = this.tileWidth * this.targetX + this.tileWidth * 0.5; + movable.position.y = this.tileHeight * this.targetY + this.tileHeight; + } + + isMovableInsideTargetPosition(movable) + { + let tileRect = new GeometryRect( + this.targetX * this.tileWidth, + this.targetY * this.tileHeight, + this.tileWidth, + this.tileHeight + ); + + return tileRect.isContainingPoint(movable.getPositionHeadLeft()) || + tileRect.isContainingPoint(movable.getPositionHeadRight()) || + tileRect.isContainingPoint(movable.getPositionFootLeft()) || + tileRect.isContainingPoint(movable.getPositionFootRight()); + } + draw(context, camera = null) { let viewX = parseInt(Math.floor(Math.max(0, camera.position.x) / this.tileWidth)); @@ -205,6 +228,8 @@ export default class RetroArchitecture architecture.startX = data.startX; architecture.startY = data.startY; + architecture.targetX = data.targetX; + architecture.targetY = data.targetY; for (let y = 0; y < data.rows; y++) { for (let x = 0; x < data.columns; x++) { diff --git a/tilorswift/js/Field.js b/tilorswift/js/Field.js index ea28d77..e9d1a55 100644 --- a/tilorswift/js/Field.js +++ b/tilorswift/js/Field.js @@ -8,6 +8,7 @@ export default class Field this.tileset = tileset; this.index = index; this.isEntrancePoint = false; + this.isTargetPoint = false; this.initHtml(); this.initEventListeners(); } @@ -75,6 +76,17 @@ export default class Field } } + setTargetPoint(bool) + { + this.isTargetPoint = bool; + + if (this.isTargetPoint) { + this.htmlElement.classList.add('target'); + } else { + this.htmlElement.classList.remove('target'); + } + } + getElement() { return this.htmlElement; diff --git a/tilorswift/js/Terrain.js b/tilorswift/js/Terrain.js index 3c646e6..50ac3e1 100644 --- a/tilorswift/js/Terrain.js +++ b/tilorswift/js/Terrain.js @@ -12,6 +12,8 @@ export default class Terrain this.tilesY = tilesY; this.entranceTileX = undefined; this.entranceTileY = undefined; + this.targetTileX = undefined; + this.targetTileY = undefined; this.backgroundColor = backgroundColor; this.htmlElement = document.createElement('table'); this.brushTileIndex = 0; @@ -134,6 +136,20 @@ export default class Terrain } } + setTargetPoint(tileX, tileY) + { + if (this.fields[tileY][tileX].index === -1) { + if (this.targetTileX !== undefined && this.targetTileY !== undefined) { + this.fields[this.targetTileY][this.targetTileX].setTargetPoint(false); + } + + this.targetTileX = tileX; + this.targetTileY = tileY; + + this.fields[tileY][tileX].setTargetPoint(true); + } + } + getFieldCoordinates(field) { for (let y = 0; y < this.fields.length; y++) { @@ -152,6 +168,11 @@ export default class Terrain return this.entranceTileX !== undefined && this.entranceTileY !== undefined; } + hasTargetPoint() + { + return this.targetTileX !== undefined && this.targetTileY !== undefined; + } + static createFromJson(terrainData) { let imageTileset = new Image(); @@ -166,6 +187,8 @@ export default class Terrain if (x === terrainData.startX && y === terrainData.startY) { terrain.setEntrancePoint(x, y); + } else if (x === terrainData.targetX && y === terrainData.targetY) { + terrain.setTargetPoint(x, y); } } } diff --git a/tilorswift/js/Tilorswift.js b/tilorswift/js/Tilorswift.js index dc404e6..d62a3a8 100644 --- a/tilorswift/js/Tilorswift.js +++ b/tilorswift/js/Tilorswift.js @@ -22,6 +22,8 @@ export default class Tilorswift columns: terrain.tilesX, startX: terrain.entranceTileX, startY: terrain.entranceTileY, + targetX: terrain.targetTileX, + targetY: terrain.targetTileY, backgroundColor: terrain.backgroundColor, matrix: matrix, }; @@ -36,6 +38,11 @@ export default class Tilorswift return false; } + if (!terrain.hasTargetPoint()) { + alert('Es muss ein Zielpunkt definiert sein!'); + return false; + } + let filename = prompt('Dateiname', 'terrain.json'); if (filename === null) { diff --git a/tilorswift/js/menu/TargetPointWidget.js b/tilorswift/js/menu/TargetPointWidget.js new file mode 100644 index 0000000..05c0c8a --- /dev/null +++ b/tilorswift/js/menu/TargetPointWidget.js @@ -0,0 +1,28 @@ +import Widget from "./Widget.js"; +import BrushMode from "../BrushMode.js"; + +export default class TargetPointWidget extends Widget +{ + constructor(widgetBar, brush) { + super('Zielpunkt'); + this.widgetBar = widgetBar; + this.brush = brush; + this.htmlElement = this.createElement(); + this.htmlElement.addEventListener( + 'click', + () => { + this.widgetBar.disableWidgets(); + this.enable(); + this.brush.mode = BrushMode.EXIT; + } + ); + } + + createElement() + { + let htmlElement = document.createElement('div'); + htmlElement.id = 'target-picker'; + + return htmlElement; + } +} \ No newline at end of file diff --git a/tilorswift/js/module.js b/tilorswift/js/module.js index 9bc4cf4..a8ffbc5 100644 --- a/tilorswift/js/module.js +++ b/tilorswift/js/module.js @@ -20,8 +20,9 @@ import TilorswiftAddRowsClickedEvent from "./events/TilorswiftAddRowsClickedEven import TilorswiftAddColumnsClickedEvent from "./events/TilorswiftAddColumnsClickedEvent.js"; import TilorswiftMenuNewTerrainClickedEvent from "./events/TilorswiftMenuNewTerrainClickedEvent.js"; import DialogNewTerrain from "./dialog/DialogNewTerrain.js"; +import TargetPointWidget from "./menu/TargetPointWidget.js"; -let loader = new FileLoader('../levels/level.json'); +let loader = new FileLoader('../levels/level01.json'); let terrainData = JSON.parse(loader.getContent()); let image = new Image(); image.src = terrainData.tileset; @@ -41,6 +42,9 @@ image.onload = function () { let entrancePicker = new EntrancePointWidget(widgetBar, brush); widgetBar.addWidget(entrancePicker); + let targetPicker = new TargetPointWidget(widgetBar, brush); + widgetBar.addWidget(targetPicker); + document.body.appendChild(widgetBar.getElement()); let mouse = new Mouse(); @@ -77,6 +81,13 @@ image.onload = function () { brush.mode = BrushMode.TERRAIN; widgetBar.enableWidgets(); } + } else if (brush.mode === BrushMode.EXIT) { + if (event.getField().index === -1) { + let coordinates = terrain.getFieldCoordinates(event.getField()); + terrain.setTargetPoint(coordinates.x, coordinates.y); + brush.mode = BrushMode.TERRAIN; + widgetBar.enableWidgets(); + } } } ); diff --git a/tilorswift/style.css b/tilorswift/style.css index fee7c25..64153cf 100644 --- a/tilorswift/style.css +++ b/tilorswift/style.css @@ -120,7 +120,7 @@ body { display: none; } -#entrance-picker { +#entrance-picker, #target-picker { width: 96px; height: 96px; border: 1px solid black; @@ -131,6 +131,10 @@ body { cursor: pointer; } +#target-picker { + background-image: url("graphics/target-point.svg"); +} + #widget-insert-rows { position: relative; width: 96px; @@ -159,11 +163,16 @@ body { cursor: pointer; display: inline-flex; } -.entrance { +.entrance, .target { background-image: url("graphics/entrance-point.svg") !important; background-size: contain !important; background-position: center bottom !important; } + +.target { + background-image: url("graphics/target-point.svg") !important; +} + .button-tile { margin: 2px; }