You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gamejam-22/core/src/main/kotlin/com/last/commit/screen/FirstScreen.kt

359 lines
11 KiB
Kotlin

package com.last.commit.screen
2 years ago
import com.badlogic.gdx.*
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.math.Vector3
2 years ago
import com.badlogic.gdx.scenes.scene2d.ui.Skin
import com.badlogic.gdx.utils.Json
import com.badlogic.gdx.utils.viewport.FillViewport
import com.last.commit.Game
import com.last.commit.Player
import com.last.commit.config.GameConfig
import com.last.commit.map.Interactable
import com.last.commit.map.TimeMap
import com.last.commit.stages.DialogStage
import com.last.commit.stages.PromptStage
2 years ago
import com.last.commit.stages.UIStage
import kotlin.math.floor
/** First screen of the application. Displayed after the application is created. */
2 years ago
class FirstScreen(private val parent: Game) : Screen, InputProcessor {
val viewportSize = 1200f
private var isColliding = false
val batch = SpriteBatch()
val viewport = FillViewport(viewportSize, viewportSize)
val camera = OrthographicCamera(viewportSize, viewportSize)
2 years ago
lateinit var map: TimeMap
val playerTexture = Texture("sprites/characters.png")
val player = Player(TextureRegion(playerTexture, 300, 44, 35, 43))
var shapeRenderer = ShapeRenderer()
val highlightColor = Color(0f, 0f, 1f, 0.5f)
2 years ago
lateinit var uiStage: UIStage
lateinit var promptStage: PromptStage
lateinit var dialogStage: DialogStage
2 years ago
val inputProcessors = InputMultiplexer()
2 years ago
override fun show() {
val gameConfig = this.loadGameConfig()
val randomMap = gameConfig.getRandomMap()
dialogStage = DialogStage(Skin(Gdx.files.internal("ui/uiskin.json")))
map = TimeMap(randomMap, dialogStage)
this.spawnPlayer()
this.updateCamera()
uiStage = UIStage("sprites/genericItems_spritesheet_colored", player, map)
shapeRenderer.setAutoShapeType(true)
promptStage = PromptStage(Skin(Gdx.files.internal("ui/uiskin.json")))
2 years ago
promptStage.addText(
"""
You are stranded in time.
The time traveling device you carry with you cannot be controlled anymore.
2 years ago
""".trimIndent()
)
promptStage.addText(
"""
You need to find the tools required to fix your time traveling device.
Look around the map to find them.
2 years ago
""".trimIndent()
)
promptStage.addText(
"""
You can use <W>, <A>, <S> and <D> to walk around the map.
2 years ago
""".trimIndent()
)
promptStage.addText(
"""
2 years ago
Doors can be opened and items picked up with <E>.
Some doors require keys to be opened.
2 years ago
"""
)
promptStage.addText(
"""
At some locations you can press <T> to travel to a random spot in time.
The top left indicates where you traveled to.
2 years ago
""".trimIndent()
)
promptStage.addText(
"""
Some items can only be collected in certain time locations.
A collectible item will be highlighted when hovering over it using the mouse
2 years ago
""".trimIndent()
)
promptStage.visible = true
viewport.camera = camera
viewport.apply()
2 years ago
resume()
inputProcessors.addProcessor(dialogStage)
2 years ago
inputProcessors.addProcessor(promptStage)
inputProcessors.addProcessor(this)
Gdx.input.inputProcessor = inputProcessors
}
fun loadGameConfig(): GameConfig {
val jsonFileHandle = Gdx.files.local("config.json")
val json = Json()
return json.fromJson(GameConfig::class.java, jsonFileHandle)
}
override fun render(delta: Float) {
2 years ago
uiStage.act(delta)
dialogStage.act(delta)
2 years ago
promptStage.act(delta)
if (player.inventory.checkVictoryCondition()) {
promptStage.visible = true
promptStage.clearText()
promptStage.addText("You won!")
} else {
if (!promptStage.visible) {
handleInput(delta)
handleMapBorderCollision()
}
2 years ago
val mousePosition: Vector2 = getMousePosition()
player.lookAt(mousePosition)
2 years ago
2 years ago
batch.projectionMatrix = camera.combined
batch.begin()
this.map.render(batch, camera, delta)
this.player.render(batch)
batch.end()
2 years ago
val interactables = map.getInteractablesAt(player.getAbsoluteDirection())
renderInteractables(interactables)
viewport.apply()
updateCamera()
2 years ago
}
2 years ago
promptStage.draw()
uiStage.draw()
dialogStage.draw()
}
fun renderInteractables(interactables: List<Interactable>) {
Gdx.gl.glEnable(GL20.GL_BLEND)
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
shapeRenderer.setProjectionMatrix(this.camera.combined)
shapeRenderer.setColor(highlightColor)
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled)
for (interactable in interactables) {
shapeRenderer.rect(
interactable.getCollider().x,
interactable.getCollider().y,
interactable.getCollider().width,
interactable.getCollider().height
)
}
shapeRenderer.end()
Gdx.gl.glDisable(GL20.GL_BLEND)
}
private fun getMousePosition(): Vector2 {
val unprojectedMousePosition =
viewport.unproject(Vector3(Gdx.input.x.toFloat(), Gdx.input.y.toFloat(), 0f))
return Vector2(unprojectedMousePosition.x, unprojectedMousePosition.y)
}
private fun handleMapBorderCollision() {
val mapWidth: Int = map.width
val mapHeight: Int = map.height
val playerSize: Float = player.getSize()
val playerX: Float = MathUtils.clamp(this.player.getX(), 0f, mapWidth - playerSize)
val playerY: Float = MathUtils.clamp(this.player.getY(), 0f, mapHeight - playerSize)
this.player.setPosition(playerX, playerY)
}
private fun handleInput(delta: Float) {
val horizontalMovement = Vector2()
2 years ago
if (Gdx.input.isKeyPressed(Input.Keys.A) || Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
horizontalMovement.sub(Vector2.X)
}
2 years ago
if (Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
horizontalMovement.add(Vector2.X)
}
this.player.move(horizontalMovement, delta)
checkCollision()
if (this.isColliding) {
horizontalMovement.rotateDeg(180f)
this.player.move(horizontalMovement, delta)
}
val verticalMovement = Vector2()
2 years ago
if (Gdx.input.isKeyPressed(Input.Keys.W) || Gdx.input.isKeyPressed(Input.Keys.UP)) {
verticalMovement.add(Vector2.Y)
}
2 years ago
if (Gdx.input.isKeyPressed(Input.Keys.S) || Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
verticalMovement.sub(Vector2.Y)
}
this.player.move(verticalMovement, delta)
checkCollision()
if (this.isColliding) {
verticalMovement.rotateDeg(180f)
this.player.move(verticalMovement, delta)
}
val hasMoved = !horizontalMovement.isZero || !verticalMovement.isZero
if (hasMoved) {
updateCamera()
}
}
private fun isKeyPressed(keyCodes: List<Int>): Boolean {
for (key in keyCodes) {
if (Gdx.input.isKeyPressed(key)) {
return true
}
}
return false
}
private fun spawnPlayer() {
val playerSpawn: Vector2 = map.getPlayerSpawn()
this.player.position = playerSpawn
}
private fun checkCollision() {
this.isColliding = map.isCollidingWith(player)
}
2 years ago
private fun updateCamera() {
val mapSize = Vector2(map.width.toFloat(), map.height.toFloat())
val scale = viewport.worldHeight / viewport.screenHeight
camera.position.x = MathUtils.clamp(
player.position.x,
(viewport.worldWidth / 2f) + (viewport.leftGutterWidth * scale),
mapSize.x - (viewport.worldWidth / 2f) - (viewport.rightGutterWidth * scale)
)
camera.position.y = MathUtils.clamp(
player.position.y,
(viewport.worldHeight / 2f) + (viewport.topGutterHeight * scale),
mapSize.y - (viewport.worldHeight / 2f) - (viewport.bottomGutterHeight * scale)
)
camera.update()
}
2 years ago
override fun resize(width: Int, height: Int) {
// Resize your screen here. The parameters represent the new window size.
uiStage.resize(width, height)
promptStage.resize(width, height)
dialogStage.resize(width, height)
viewport.update(width, height)
viewport.apply()
camera.update()
}
override fun pause() {
2 years ago
}
override fun resume() {
this.viewport.apply()
this.updateCamera()
// Invoked when your application is resumed after pause.
}
override fun hide() {
//gameState.soundEngine.stop()
}
override fun dispose() {
// Destroy screen's assets here.
batch.dispose()
shapeRenderer.dispose()
}
fun openDoor() {
val playerDirection: Vector2 = player.getAbsoluteDirection()
map.interactWith(playerDirection.x, playerDirection.y, player)
}
fun toWorldCoordinates(x: Float, y: Float): Vector2 {
val mouseInWorldPosition = viewport.unproject(Vector3(x, y, 0f))
return Vector2(
floor(mouseInWorldPosition.x.toDouble() / this.map.getTileWidth()).toFloat(),
floor(mouseInWorldPosition.y.toDouble() / this.map.getTileHeight()).toFloat()
)
}
2 years ago
override fun keyDown(keycode: Int): Boolean {
return false
}
override fun keyUp(keycode: Int): Boolean {
when (keycode) {
Input.Keys.E -> {
openDoor()
}
Input.Keys.T -> {
map.teleport(player)
}
Input.Keys.ESCAPE -> {
parent.changeScreen(Screens.MAIN_MENU)
}
}
return false
}
override fun keyTyped(character: Char): Boolean {
return false
}
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
val mouseCoordinates: Vector2 = toWorldCoordinates(screenX.toFloat(), screenY.toFloat())
val playerDirection: Vector2 = player.getAbsoluteDirection()
map.interactWith(playerDirection.x, playerDirection.y, player)
2 years ago
return false
}
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
//TODO:("Not yet implemented")
return false
}
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
//TODO:("Not yet implemented")
return false
}
override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
//TODO:("Not yet implemented")
return false
}
override fun scrolled(amountX: Float, amountY: Float): Boolean {
//TODO:("Not yet implemented")
return false
}
}