diff --git a/game/src/main/kotlin/org/catinthedark/alyoep/game/states/PlayerState.kt b/game/src/main/kotlin/org/catinthedark/alyoep/game/states/PlayerState.kt index ad4b4de..e8325d6 100644 --- a/game/src/main/kotlin/org/catinthedark/alyoep/game/states/PlayerState.kt +++ b/game/src/main/kotlin/org/catinthedark/alyoep/game/states/PlayerState.kt @@ -3,6 +3,8 @@ package org.catinthedark.alyoep.game.states import com.badlogic.gdx.Gdx import com.badlogic.gdx.Input import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.glutils.ShapeRenderer +import com.badlogic.gdx.math.MathUtils import com.badlogic.gdx.math.Vector2 import org.catinthedark.alyoep.audio.Bgm import org.catinthedark.alyoep.game.Const @@ -10,10 +12,7 @@ import org.catinthedark.alyoep.game.Const.Balance.PLAYER_SPAWN_POINT import org.catinthedark.alyoep.game.States import org.catinthedark.alyoep.game.control.PlayerController import org.catinthedark.alyoep.game.entities.* -import org.catinthedark.alyoep.lib.IOC -import org.catinthedark.alyoep.lib.at -import org.catinthedark.alyoep.lib.atOrFail -import org.catinthedark.alyoep.lib.atOrPut +import org.catinthedark.alyoep.lib.* import org.catinthedark.alyoep.lib.math.randomDir import org.catinthedark.alyoep.lib.states.IState import org.slf4j.LoggerFactory @@ -34,6 +33,10 @@ class PlayerState : IState { private val bgm: Bgm by lazy { IOC.atOrFail("bgm") } private lateinit var powerUpsGenerator: PowerUpsGenerator private lateinit var tower: Tower + private val render: ShapeRenderer = IOC.atOrFail("shapeRenderer") + + private val showHintBarrier = AfterBarrier(3f) + private var hintTime = 0f private var activePlayers = 0 @@ -41,6 +44,8 @@ class PlayerState : IState { get() = enemies.count { it.isBoss } override fun onActivate() { + showHintBarrier.reset() + hintTime = 0f powerUpsGenerator = PowerUpsGenerator() tower = Tower(Vector2(Const.Screen.WIDTH / 2f, Const.Screen.HEIGHT / 3f * 2f)) IOC.put("tower", tower) @@ -59,6 +64,8 @@ class PlayerState : IState { } override fun onUpdate() { + hintTime += Gdx.graphics.deltaTime + controllers.forEach { if (activePlayers < 4 && !it.value && it.key.getDirection().len() > 0.0001) { players.add(Player(PLAYER_SPAWN_POINT.cpy(), colors[activePlayers], it.key)) @@ -91,10 +98,53 @@ class PlayerState : IState { bgm.update() bgm.updateLayers(playersCount = players.size, bossesCount = bossesCount) + showHintBarrier.invoke { + if (activePlayers == 0) { + val space = TutorialState.Dimensions.BUTTON_SIZE + TutorialState.Dimensions.BUTTON_SPACING + drawHint( + Vector2( + Const.Screen.WIDTH - space * 3, + Const.Screen.HEIGHT - space * 2 + ), MathUtils.floor(hintTime * 2) % 2 == 0 + ) + } + } + checkGameOver() checkRestart() } + private fun drawHint(pos: Vector2, state: Boolean) { + render.managed(ShapeRenderer.ShapeType.Line) { + it.color = Color.WHITE + val upOffset = Vector2( + TutorialState.Dimensions.BUTTON_SIZE + TutorialState.Dimensions.BUTTON_SPACING, + 0f + ) + + TutorialState.DrawHelpers.drawButton(it, pos.cpy().add(upOffset), false) + + val leftOffset = Vector2( + 0f, + TutorialState.Dimensions.BUTTON_SIZE + TutorialState.Dimensions.BUTTON_SPACING + ) + TutorialState.DrawHelpers.drawButton(it, pos.cpy().add(leftOffset), state) + + val downOffset = Vector2( + TutorialState.Dimensions.BUTTON_SIZE + TutorialState.Dimensions.BUTTON_SPACING, + TutorialState.Dimensions.BUTTON_SIZE + TutorialState.Dimensions.BUTTON_SPACING, + ) + TutorialState.DrawHelpers.drawButton(it, pos.cpy().add(downOffset), false) + + val rightOffset = Vector2( + 2 * (TutorialState.Dimensions.BUTTON_SIZE + TutorialState.Dimensions.BUTTON_SPACING), + TutorialState.Dimensions.BUTTON_SIZE + TutorialState.Dimensions.BUTTON_SPACING, + ) + + TutorialState.DrawHelpers.drawButton(it, pos.cpy().add(rightOffset), false) + } + } + override fun onExit() { } diff --git a/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TitleScreenState.kt b/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TitleScreenState.kt index 4a4f1e7..d8bca27 100644 --- a/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TitleScreenState.kt +++ b/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TitleScreenState.kt @@ -3,12 +3,16 @@ package org.catinthedark.alyoep.game.states import com.badlogic.gdx.Gdx import com.badlogic.gdx.Input import com.badlogic.gdx.assets.AssetManager +import com.badlogic.gdx.graphics.glutils.ShapeRenderer +import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.scenes.scene2d.Stage import org.catinthedark.alyoep.audio.Bgm import org.catinthedark.alyoep.game.Assets +import org.catinthedark.alyoep.game.Const import org.catinthedark.alyoep.game.States import org.catinthedark.alyoep.game.control.PlayerController import org.catinthedark.alyoep.game.texture +import org.catinthedark.alyoep.lib.AfterBarrier import org.catinthedark.alyoep.lib.IOC import org.catinthedark.alyoep.lib.atOrFail import org.catinthedark.alyoep.lib.managed @@ -19,6 +23,9 @@ class TitleScreenState : IState { private val am: AssetManager by lazy { IOC.atOrFail("assetManager") } private val bgm: Bgm by lazy { IOC.atOrFail("bgm") } private val controllers: Map = IOC.atOrFail("input") + private val render: ShapeRenderer by lazy { IOC.atOrFail("shapeRenderer") } + + private val drawNextBarrier = AfterBarrier(2f) private var currentTime = 0f @@ -32,6 +39,28 @@ class TitleScreenState : IState { b.draw(am.texture(Assets.Names.TITLE), 0f, 0f) } + currentTime += Gdx.graphics.deltaTime + drawNextBarrier.invoke { + render.managed(ShapeRenderer.ShapeType.Line) { + val spacePos = Vector2( + Const.Screen.WIDTH / 2f - (TutorialState.Dimensions.SPACE_WIDTH + TutorialState.Dimensions.ARROW_WIDTH + 2 * TutorialState.Dimensions.BUTTON_SPACING) / 2, + Const.Screen.HEIGHT - 100f + ) + + TutorialState.DrawHelpers.drawSpaceBar(it, spacePos) + + val arrowPos = spacePos.cpy() + .add(TutorialState.Dimensions.SPACE_WIDTH + 2 * TutorialState.Dimensions.BUTTON_SPACING, 15f) + TutorialState.DrawHelpers.animateArrow( + currentTime, + it, + arrowPos, + TutorialState.Dimensions.ARROW_WIDTH, + 45f + ) + } + } + var startPressed = false for (controller in controllers) { if (controller.key.isStartJustPressed()) { diff --git a/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TutorialState.kt b/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TutorialState.kt index 8c38473..c040fec 100644 --- a/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TutorialState.kt +++ b/game/src/main/kotlin/org/catinthedark/alyoep/game/states/TutorialState.kt @@ -15,6 +15,7 @@ import org.catinthedark.alyoep.game.entities.* import org.catinthedark.alyoep.game.entities.powerups.FirePowerUp import org.catinthedark.alyoep.game.entities.powerups.HealPowerUp import org.catinthedark.alyoep.game.entities.powerups.NovaPowerUp +import org.catinthedark.alyoep.game.states.TutorialState.DrawHelpers.drawButton import org.catinthedark.alyoep.lib.* import org.catinthedark.alyoep.lib.interfaces.ITransform import org.catinthedark.alyoep.lib.math.randomDir @@ -35,6 +36,76 @@ class TutorialState : IState { const val ARROW_DX = 20f } + object DrawHelpers { + fun drawSpaceBar(renderer: ShapeRenderer, pos: Vector2) { + val spaceSymWidth = 200f + val spaceSymPos = + pos.cpy().add((Dimensions.SPACE_WIDTH - spaceSymWidth) / 2, -10f) + renderer.roundedRectLine( + pos.x, + pos.y, + Dimensions.SPACE_WIDTH, + Dimensions.BUTTON_SIZE, + Dimensions.BUTTON_RADIUS + ) + renderer.roundedRectLineShadow( + pos.x, + pos.y + 10, + Dimensions.SPACE_WIDTH, + Dimensions.BUTTON_SIZE, + Dimensions.BUTTON_RADIUS + ) + renderer.roundedRectLineShadow( + spaceSymPos.x, + spaceSymPos.y, + spaceSymWidth, + Dimensions.BUTTON_SIZE, + 10f + ) + } + + private fun drawArrow(renderer: ShapeRenderer, pos: Vector2, width: Float, height: Float) { + val rp1 = pos.cpy() + val rp2 = pos.cpy().add(width, 0f) + val rp3 = pos.cpy().add(width, height) + val rp4 = pos.cpy().add(0f, height) + val triangleCenter = Vector2(pos.x + width + height / 2, pos.y + height / 2) + val radius = Vector2(height, 0f) + val p1 = triangleCenter.cpy().add(radius.cpy()) + val p2 = triangleCenter.cpy().add(radius.cpy().rotateDeg(120f)) + val p3 = triangleCenter.cpy().add(radius.cpy().rotateDeg(240f)) + renderer.polygon2(rp1, rp2, p3, p1, p2, rp3, rp4) + } + + fun animateArrow(time: Float, renderer: ShapeRenderer, pos: Vector2, width: Float, height: Float) { + val dx = MathUtils.map(-1f, 1f, 0f, Dimensions.ARROW_DX, sin(time * 10)) + pos.add(dx, 0f) + drawArrow(renderer, pos, width, height) + } + + fun drawButton(renderer: ShapeRenderer, pos: Vector2, pressed: Boolean) { + val offset = if (pressed) { + Dimensions.BUTTON_HEIGHT_PRESSED + } else { + Dimensions.BUTTON_HEIGHT_RELEASED + } + renderer.roundedRectLine( + pos.x, + pos.y - offset, + Dimensions.BUTTON_SIZE, + Dimensions.BUTTON_SIZE, + Dimensions.BUTTON_RADIUS + ) + renderer.roundedRectLineShadow( + pos.x, + pos.y, + Dimensions.BUTTON_SIZE, + Dimensions.BUTTON_SIZE, + Dimensions.BUTTON_RADIUS + ) + } + } + private val logger = LoggerFactory.getLogger(javaClass) private val render: ShapeRenderer by lazy { IOC.atOrFail("shapeRenderer") } @@ -54,7 +125,7 @@ class TutorialState : IState { private val pickupBarrier = OnceBarrier(1.5f) private val moveBackBarrier = OnceBarrier(2.5f) private val showNextBarrier = AfterBarrier(5f) - private val forceNextBarrier = OnceBarrier(10f) + private val forceNextBarrier = OnceBarrier(8f) private val inputBarrier = RepeatBarrier(0f, 1f) @@ -160,41 +231,6 @@ class TutorialState : IState { drawTutorialUi() } - private fun drawButton(renderer: ShapeRenderer, pos: Vector2, pressed: Boolean) { - val offset = if (pressed) { - Dimensions.BUTTON_HEIGHT_PRESSED - } else { - Dimensions.BUTTON_HEIGHT_RELEASED - } - renderer.roundedRectLine( - pos.x, - pos.y - offset, - Dimensions.BUTTON_SIZE, - Dimensions.BUTTON_SIZE, - Dimensions.BUTTON_RADIUS - ) - renderer.roundedRectLineShadow( - pos.x, - pos.y, - Dimensions.BUTTON_SIZE, - Dimensions.BUTTON_SIZE, - Dimensions.BUTTON_RADIUS - ) - } - - private fun drawArrow(renderer: ShapeRenderer, pos: Vector2, width: Float, height: Float) { - val rp1 = pos.cpy() - val rp2 = pos.cpy().add(width, 0f) - val rp3 = pos.cpy().add(width, height) - val rp4 = pos.cpy().add(0f, height) - val triangleCenter = Vector2(pos.x + width + height / 2, pos.y + height / 2) - val radius = Vector2(height, 0f) - val p1 = triangleCenter.cpy().add(radius.cpy()) - val p2 = triangleCenter.cpy().add(radius.cpy().rotateDeg(120f)) - val p3 = triangleCenter.cpy().add(radius.cpy().rotateDeg(240f)) - render.polygon2(rp1, rp2, p3, p1, p2, rp3, rp4) - } - private fun drawTutorialUi() { // border render.managed(ShapeRenderer.ShapeType.Filled) { @@ -241,12 +277,11 @@ class TutorialState : IState { stagePos.x + Dimensions.stage.x / 2 - (Dimensions.SPACE_WIDTH + Dimensions.ARROW_WIDTH + 2 * Dimensions.BUTTON_SPACING) / 2, stagePos.y + Dimensions.stage.y + 3 * Dimensions.BUTTON_SPACING ) - drawSpaceBar(it, spacePos) + DrawHelpers.drawSpaceBar(it, spacePos) val arrowPos = spacePos.cpy().add(Dimensions.SPACE_WIDTH + 2 * Dimensions.BUTTON_SPACING, 15f) - val dx = MathUtils.map(-1f, 1f, 0f, Dimensions.ARROW_DX, sin(time * 10)) - arrowPos.add(dx, 0f) - drawArrow( + DrawHelpers.animateArrow( + time, it, arrowPos, Dimensions.ARROW_WIDTH, @@ -273,27 +308,6 @@ class TutorialState : IState { } } - private fun drawSpaceBar(renderer: ShapeRenderer, pos: Vector2) { - val spaceSymWidth = 200f - val spaceSymPos = - pos.cpy().add((Dimensions.SPACE_WIDTH - spaceSymWidth) / 2, -10f) - renderer.roundedRectLine(pos.x, pos.y, Dimensions.SPACE_WIDTH, Dimensions.BUTTON_SIZE, Dimensions.BUTTON_RADIUS) - renderer.roundedRectLineShadow( - pos.x, - pos.y + 10, - Dimensions.SPACE_WIDTH, - Dimensions.BUTTON_SIZE, - Dimensions.BUTTON_RADIUS - ) - renderer.roundedRectLineShadow( - spaceSymPos.x, - spaceSymPos.y, - spaceSymWidth, - Dimensions.BUTTON_SIZE, - 10f - ) - } - private fun drawButtons(renderer: ShapeRenderer, pos: Vector2) { val upOffset = Vector2( Dimensions.BUTTON_SIZE + Dimensions.BUTTON_SPACING,