From 2ac18d91635b023db7ff3918f5041cb51ed1c968 Mon Sep 17 00:00:00 2001 From: romangraef Date: Wed, 30 May 2018 12:06:31 +0200 Subject: Initial commit --- .../kotlin/de/romjaki/pluggabledino/api/Button.kt | 65 ++++++++++++ .../de/romjaki/pluggabledino/api/Dependency.kt | 3 + .../romjaki/pluggabledino/api/DependencyMissing.kt | 4 + .../kotlin/de/romjaki/pluggabledino/api/Event.kt | 3 + .../de/romjaki/pluggabledino/api/EventHandler.kt | 5 + .../kotlin/de/romjaki/pluggabledino/api/Events.kt | 15 +++ .../kotlin/de/romjaki/pluggabledino/api/IPlugin.kt | 5 + .../kotlin/de/romjaki/pluggabledino/api/Inject.kt | 5 + .../romjaki/pluggabledino/api/InjectException.kt | 3 + .../pluggabledino/api/PluginFolderNotFound.kt | 3 + .../de/romjaki/pluggabledino/api/PluginLoader.kt | 76 ++++++++++++++ .../de/romjaki/pluggabledino/api/PluginMeta.kt | 5 + src/main/kotlin/de/romjaki/pluggabledino/assets.kt | 28 ++++++ .../de/romjaki/pluggabledino/events/InitEvent.kt | 5 + .../romjaki/pluggabledino/events/PostInitEvent.kt | 5 + .../romjaki/pluggabledino/events/PreInitEvent.kt | 6 ++ .../de/romjaki/pluggabledino/game/GameWorld.kt | 109 +++++++++++++++++++++ src/main/kotlin/de/romjaki/pluggabledino/main.kt | 49 +++++++++ .../de/romjaki/pluggabledino/states/GameState.kt | 45 +++++++++ .../de/romjaki/pluggabledino/states/MainMenu.kt | 52 ++++++++++ .../romjaki/pluggabledino/states/SettingsState.kt | 42 ++++++++ .../romjaki/pluggabledino/states/SplashScreen.kt | 41 ++++++++ src/main/kotlin/de/romjaki/pluggabledino/util.kt | 23 +++++ 23 files changed, 597 insertions(+) create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/Button.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/Dependency.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/DependencyMissing.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/Event.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/EventHandler.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/Events.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/IPlugin.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/Inject.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/InjectException.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/PluginFolderNotFound.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/PluginLoader.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/api/PluginMeta.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/assets.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/events/InitEvent.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/events/PostInitEvent.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/events/PreInitEvent.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/game/GameWorld.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/main.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/states/GameState.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/states/MainMenu.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/states/SettingsState.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/states/SplashScreen.kt create mode 100644 src/main/kotlin/de/romjaki/pluggabledino/util.kt (limited to 'src/main/kotlin/de/romjaki/pluggabledino') diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/Button.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/Button.kt new file mode 100644 index 0000000..9b39e4b --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/Button.kt @@ -0,0 +1,65 @@ +package de.romjaki.pluggabledino.api + +import de.romjaki.pluggabledino.buttonImage +import de.romjaki.pluggabledino.drawImageCentered +import de.romjaki.pluggabledino.drawStringCentered +import de.romjaki.pluggabledino.font +import org.newdawn.slick.Graphics +import org.newdawn.slick.Input +import java.awt.Rectangle +import kotlin.math.min + +class Button(private val text: String, val x: Float, val y: Float) { + + val width = min(buttonImage.width, font.getWidth(text) + 10) + val image = buttonImage.getScaledCopy(width, buttonImage.height) + + private var lastClicked = false + + val leftX + get() = x - width / 2 + val rightX + get() = x + width / 2 + val topY + get() = y - image.height / 2 + val bottomY + get() = y + image.height / 2 + + val rectangle + get() = Rectangle(leftX.toInt(), topY.toInt(), (rightX - leftX).toInt(), (bottomY - topY).toInt()) + + + private val clickHandlers = mutableListOf<() -> Unit>() + + fun addClickHandler(handler: () -> Unit) { + clickHandlers.add(handler) + } + + fun draw(g: Graphics) { + g.drawImageCentered(image, x, y) + g.drawStringCentered(text, x, y) + } + + override fun toString(): String = + "X: $leftX - $rightX, $topY - $bottomY, width=$width" + + fun enter() { + lastClicked = true + } + + fun isClicked(input: Input): Boolean = + input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) && isMouseOver(input) + + fun update(input: Input) { + val ret = isClicked(input) + if (!lastClicked && ret) { + clickHandlers.forEach({ it() }) + } + lastClicked = ret + } + + fun isMouseOver(input: Input): Boolean = + rectangle.contains(input.mouseX, input.mouseY) + +} + diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/Dependency.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/Dependency.kt new file mode 100644 index 0000000..65c8b06 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/Dependency.kt @@ -0,0 +1,3 @@ +package de.romjaki.pluggabledino.api + +data class Dependency(var dependencyName: String, var dependencyVersion: String) \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/DependencyMissing.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/DependencyMissing.kt new file mode 100644 index 0000000..85769f7 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/DependencyMissing.kt @@ -0,0 +1,4 @@ +package de.romjaki.pluggabledino.api + +class DependencyMissing(plugin: String, dependencyName: String, dependencyVersion: String) : + Exception("$plugin is missing dependency ${dependencyName}with version $dependencyVersion") diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/Event.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/Event.kt new file mode 100644 index 0000000..4aa702d --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/Event.kt @@ -0,0 +1,3 @@ +package de.romjaki.pluggabledino.api + +interface Event \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/EventHandler.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/EventHandler.kt new file mode 100644 index 0000000..989fb81 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/EventHandler.kt @@ -0,0 +1,5 @@ +package de.romjaki.pluggabledino.api + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class EventHandler \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/Events.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/Events.kt new file mode 100644 index 0000000..6f43844 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/Events.kt @@ -0,0 +1,15 @@ +package de.romjaki.pluggabledino.api + +import java.util.* + +object Events { + fun broadcastEvent(event: Event) { + for (plugin in PluginLoader.plugins.values) { + Arrays.stream(plugin.javaClass.methods!!) + .filter { it.getAnnotation(EventHandler::class.java) != null } + .filter { it.parameterCount == 1 } + .filter { it.parameterTypes[0].isInstance(event) } + .forEach { it.invoke(plugin, event) } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/IPlugin.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/IPlugin.kt new file mode 100644 index 0000000..e2e25fc --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/IPlugin.kt @@ -0,0 +1,5 @@ +package de.romjaki.pluggabledino.api; + +open class IPlugin { + var meta: PluginMeta? = null +} diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/Inject.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/Inject.kt new file mode 100644 index 0000000..c3089c9 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/Inject.kt @@ -0,0 +1,5 @@ +package de.romjaki.pluggabledino.api + +@Target(AnnotationTarget.FIELD) +@Retention(AnnotationRetention.RUNTIME) +annotation class Inject(val what: String) diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/InjectException.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/InjectException.kt new file mode 100644 index 0000000..2dc14dd --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/InjectException.kt @@ -0,0 +1,3 @@ +package de.romjaki.pluggabledino.api + +class InjectException(plugin: String, dependency: String) : Exception("$plugin failed to load $dependency") \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/PluginFolderNotFound.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/PluginFolderNotFound.kt new file mode 100644 index 0000000..5ca946f --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/PluginFolderNotFound.kt @@ -0,0 +1,3 @@ +package de.romjaki.pluggabledino.api + +class PluginFolderNotFound(folder: String) : Exception("Plugin folder not found at $folder") diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/PluginLoader.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/PluginLoader.kt new file mode 100644 index 0000000..7ce8649 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/PluginLoader.kt @@ -0,0 +1,76 @@ +package de.romjaki.pluggabledino.api + +import com.beust.klaxon.Klaxon +import java.io.File +import java.net.URL +import java.net.URLClassLoader +import java.util.* + + +object PluginLoader { + private val _plugins: MutableMap = mutableMapOf() + private val klaxon = Klaxon() + private const val pluginFolder = "plugins" + + val plugins + get() = _plugins.toMap() + + + fun loadPlugin(url: URL): IPlugin? { + val cl = URLClassLoader(arrayOf(url)) + val pluginInfo = klaxon.parse( + Scanner( + cl.getResourceAsStream("plugin.json")) + .useDelimiter("\\A") + .next())!! + val pluginClass = cl.loadClass(pluginInfo.clazz) + if (!IPlugin::class.java.isAssignableFrom(pluginClass)) { + return null + } + val plugin = pluginClass.newInstance() as IPlugin + plugin.meta = pluginInfo + _plugins[pluginInfo.name] = plugin + return plugin + } + + private fun checkDependencies() { + for ((name, instance) in _plugins) { + for (dep in instance.meta!!.dependencies) { + if (!_plugins.containsKey(dep.dependencyName)) { + throw DependencyMissing(name, dep.dependencyName, dep.dependencyVersion) + } + val dependency = _plugins[dep.dependencyName]!! + if (dep.dependencyVersion.matches(dependency.meta!!.name.toRegex())) { + throw DependencyMissing(name, dep.dependencyName, dep.dependencyVersion) + } + } + } + } + + fun loadPlugins() = loadPlugins(File(pluginFolder)) + fun loadPlugins(folder: File) { + if (!folder.isDirectory) { + throw PluginFolderNotFound(folder.absolutePath) + } + folder.listFiles { _, filename -> filename.endsWith(".jar") } + .map { + it.toURI().toURL() + }.forEach { loadPlugin(it) } + checkDependencies() + injectDependencies() + } + + + private fun injectDependencies() { + for ((name, instance) in _plugins) { + for (field in instance.javaClass.fields) { + val inject = field.getAnnotation(Inject::class.java) as Inject + if (_plugins.containsKey(inject.what)) { + field.set(instance, _plugins[inject.what]) + } else { + throw InjectException(name, inject.what) + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/api/PluginMeta.kt b/src/main/kotlin/de/romjaki/pluggabledino/api/PluginMeta.kt new file mode 100644 index 0000000..aec7e35 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/api/PluginMeta.kt @@ -0,0 +1,5 @@ +package de.romjaki.pluggabledino.api + +import com.beust.klaxon.Json + +data class PluginMeta(var name: String, var version: String, @Json(name = "class") var clazz: String, var dependencies: MutableList = mutableListOf()) \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/assets.kt b/src/main/kotlin/de/romjaki/pluggabledino/assets.kt new file mode 100644 index 0000000..6a0e600 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/assets.kt @@ -0,0 +1,28 @@ +package de.romjaki.pluggabledino + +import org.newdawn.slick.Animation +import org.newdawn.slick.Image +import org.newdawn.slick.SpriteSheet +import org.newdawn.slick.UnicodeFont +import org.newdawn.slick.opengl.TextureLoader +import java.awt.Font +import java.io.FileInputStream + +val splash = Image(TextureLoader.getTexture("PNG", FileInputStream("assets/images/splash.png"))) +val dinoSprites = SpriteSheet("assets/images/characters.png", 32, 32) +val dinoAnimated = Animation(dinoSprites, intArrayOf( + 0, 0, + 1, 0, + 2, 0, + 3, 0, + 4, 0, + 5, 0, + 6, 0, + 7, 0 +), IntArray(8) { 100 }) +val font = UnicodeFont(Font("Arial", Font.PLAIN, 14)) +val buttonImage = Image(TextureLoader.getTexture("PNG", FileInputStream("assets/images/button.png"))) + +val groundline = Image(TextureLoader.getTexture("PNG", FileInputStream("assets/images/groundline.png"))) + +val cactusImg = Image(TextureLoader.getTexture("PNG", FileInputStream("assets/images/cactus.png"))) diff --git a/src/main/kotlin/de/romjaki/pluggabledino/events/InitEvent.kt b/src/main/kotlin/de/romjaki/pluggabledino/events/InitEvent.kt new file mode 100644 index 0000000..e82529c --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/events/InitEvent.kt @@ -0,0 +1,5 @@ +package de.romjaki.pluggabledino.events + +import de.romjaki.pluggabledino.api.Event + +class InitEvent : Event diff --git a/src/main/kotlin/de/romjaki/pluggabledino/events/PostInitEvent.kt b/src/main/kotlin/de/romjaki/pluggabledino/events/PostInitEvent.kt new file mode 100644 index 0000000..757888e --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/events/PostInitEvent.kt @@ -0,0 +1,5 @@ +package de.romjaki.pluggabledino.events + +import de.romjaki.pluggabledino.api.Event + +class PostInitEvent : Event diff --git a/src/main/kotlin/de/romjaki/pluggabledino/events/PreInitEvent.kt b/src/main/kotlin/de/romjaki/pluggabledino/events/PreInitEvent.kt new file mode 100644 index 0000000..75d7acc --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/events/PreInitEvent.kt @@ -0,0 +1,6 @@ +package de.romjaki.pluggabledino.events + +import de.romjaki.pluggabledino.api.Event + + +class PreInitEvent : Event \ No newline at end of file diff --git a/src/main/kotlin/de/romjaki/pluggabledino/game/GameWorld.kt b/src/main/kotlin/de/romjaki/pluggabledino/game/GameWorld.kt new file mode 100644 index 0000000..cc940cf --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/game/GameWorld.kt @@ -0,0 +1,109 @@ +package de.romjaki.pluggabledino.game + +import org.jbox2d.callbacks.ContactImpulse +import org.jbox2d.callbacks.ContactListener +import org.jbox2d.collision.Manifold +import org.jbox2d.collision.shapes.PolygonShape +import org.jbox2d.common.Vec2 +import org.jbox2d.dynamics.* +import org.jbox2d.dynamics.contacts.Contact +import org.newdawn.slick.Input + +class GameWorld : ContactListener { + override fun endContact(contact: Contact?) { + + } + + override fun beginContact(contact: Contact?) { + contact!! + val bodies = listOf(contact.fixtureA.body, contact.fixtureB.body) + if (bodies.contains(dino) && cacti.any { bodies.contains(it) }) { + hurt = true + } + } + + override fun preSolve(contact: Contact?, oldManifold: Manifold?) { + } + + override fun postSolve(contact: Contact?, impulse: ContactImpulse?) { + } + + var hurt = false + + val world: World + + val cacti = mutableListOf() + + val cactiBodyDef: BodyDef + + val groundBody: Body + + val dino: Body + + val groundBodyDef: BodyDef + + val groundBox: PolygonShape + + val dinoDef: BodyDef + + val dinoBox: PolygonShape + + val dinoFixtureDef: FixtureDef + + init { + val gravity = Vec2(0f, 10f) + world = World(gravity) + + //#region GROUND + groundBodyDef = BodyDef() + groundBodyDef.position.set(0f, 50f) + groundBody = world.createBody(groundBodyDef) + groundBox = PolygonShape() + groundBox.setAsBox(50f, 10f) + groundBody.createFixture(groundBox, 0f) + //#endregion + + //#region DINO + dinoDef = BodyDef() + dinoDef.type = BodyType.DYNAMIC + dinoDef.position.set(4f, 39f) + dino = world.createBody(dinoDef) + dinoBox = PolygonShape() + dinoBox.setAsBox(1f, 1f) + dinoFixtureDef = FixtureDef() + dinoFixtureDef.shape = dinoBox + dinoFixtureDef.density = 0.9f + dinoFixtureDef.friction = 0.3f + dino.createFixture(dinoFixtureDef) + //#endregion + + cactiBodyDef = BodyDef() + + createCactus() + } + + fun createCactus() { + val body = world.createBody(cactiBodyDef) + val shape = PolygonShape() + shape.setAsBox(1f, 1f) + body.createFixture(shape, 0f) + cacti.add(body) + } + + + fun update(delta: Float, input: Input) { + if (input.isKeyDown(Input.KEY_UP)) { + if (isDinoOnGround()) { + print("Jump") + dino.applyForceToCenter(Vec2(0f, -2000f)) + } + } + world.step(delta, 4, 3) + world.setContactListener(this) + } + + private fun isDinoOnGround(): Boolean = + dino.linearVelocity.y == 0.0f + +} + diff --git a/src/main/kotlin/de/romjaki/pluggabledino/main.kt b/src/main/kotlin/de/romjaki/pluggabledino/main.kt new file mode 100644 index 0000000..a829089 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/main.kt @@ -0,0 +1,49 @@ +package de.romjaki.pluggabledino + +import de.romjaki.pluggabledino.api.Events +import de.romjaki.pluggabledino.api.PluginLoader +import de.romjaki.pluggabledino.events.InitEvent +import de.romjaki.pluggabledino.events.PostInitEvent +import de.romjaki.pluggabledino.events.PreInitEvent +import de.romjaki.pluggabledino.states.GameState +import de.romjaki.pluggabledino.states.MainMenu +import de.romjaki.pluggabledino.states.SettingsState +import de.romjaki.pluggabledino.states.SplashScreen +import org.newdawn.slick.AppGameContainer +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Input +import org.newdawn.slick.state.StateBasedGame + + +const val WIDTH = 640 +const val HEIGHT = 480 +const val FPS = 60 +const val VERSION = 1.0 + +const val SPLASHSCREEN = 0 +const val MAINMENU = 1 +const val SETTINGS = 3 +const val GAME = 2 + +fun main(args: Array) { + PluginLoader.loadPlugins() + Input.disableControllers() + val app = AppGameContainer(Application()) + app.setDisplayMode(WIDTH, HEIGHT, false) + app.setTargetFrameRate(FPS) + app.setShowFPS(true) + Events.broadcastEvent(PreInitEvent()) + Events.broadcastEvent(InitEvent()) + Events.broadcastEvent(PostInitEvent()) + app.start() + +} + +class Application : StateBasedGame("Dino Game v$VERSION") { + override fun initStatesList(container: GameContainer?) { + addState(SplashScreen()) + addState(MainMenu()) + addState(SettingsState()) + addState(GameState()) + } +} diff --git a/src/main/kotlin/de/romjaki/pluggabledino/states/GameState.kt b/src/main/kotlin/de/romjaki/pluggabledino/states/GameState.kt new file mode 100644 index 0000000..479f7f7 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/states/GameState.kt @@ -0,0 +1,45 @@ +package de.romjaki.pluggabledino.states + +import de.romjaki.pluggabledino.* +import de.romjaki.pluggabledino.game.GameWorld +import org.newdawn.slick.Color +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.Input +import org.newdawn.slick.state.BasicGameState +import org.newdawn.slick.state.StateBasedGame + +class GameState : BasicGameState() { + override fun init(container: GameContainer?, game: StateBasedGame?) { + } + + override fun enter(container: GameContainer?, game: StateBasedGame?) { + world = GameWorld() + } + + override fun update(container: GameContainer?, game: StateBasedGame?, delta: Int) { + if (container!!.input.isKeyDown(Input.KEY_R)) { + world = GameWorld() + } + world.update(delta / 1000f, container.input) + dinoAnimated.update(delta.toLong()) + } + + lateinit var world: GameWorld + + override fun getID(): Int = + GAME + + + override fun render(container: GameContainer?, game: StateBasedGame?, g: Graphics?) { + g!! + g.background = Color.lightGray + g.color = Color.red + g.drawImage(dinoAnimated.currentFrame, world.dino.position.x * WIDTH / 50, world.dino.position.y * HEIGHT / 50 - dinoAnimated.height) + g.drawImage(groundline, 0f, HEIGHT * 39 / 50f) + for (cactus in world.cacti) { + g.drawImage(cactusImg, cactus.position.x, cactus.position.y) + } + } + +} diff --git a/src/main/kotlin/de/romjaki/pluggabledino/states/MainMenu.kt b/src/main/kotlin/de/romjaki/pluggabledino/states/MainMenu.kt new file mode 100644 index 0000000..f10a470 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/states/MainMenu.kt @@ -0,0 +1,52 @@ +package de.romjaki.pluggabledino.states + +import de.romjaki.pluggabledino.* +import de.romjaki.pluggabledino.api.Button +import org.newdawn.slick.Color +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.Input +import org.newdawn.slick.state.BasicGameState +import org.newdawn.slick.state.StateBasedGame + +class MainMenu : BasicGameState() { + override fun init(container: GameContainer?, game: StateBasedGame?) { + game!! + settingsButton.addClickHandler { + game.enterState(SETTINGS) + } + playButton.addClickHandler { + game.enterState(GAME) + } + } + + override fun enter(container: GameContainer?, game: StateBasedGame?) { + settingsButton.enter() + playButton.enter() + } + + override fun update(container: GameContainer?, game: StateBasedGame?, delta: Int) { + container!! + game!! + dinoAnimated.update(delta.toLong()) + if (container.input.isKeyDown(Input.KEY_Q)) { + System.exit(0) + } + settingsButton.update(container.input) + playButton.update(container.input) + } + + override fun getID(): Int = + MAINMENU + + val playButton = Button("PLAY", WIDTH / 2f, HEIGHT / 2f + 50) + val settingsButton = Button("SETTINGS", WIDTH / 2f, HEIGHT / 2f + 100) + override fun render(container: GameContainer?, game: StateBasedGame?, g: Graphics?) { + g!! + g.background = Color.lightGray + g.drawImage(dinoAnimated.currentFrame, WIDTH / 2f - 16, HEIGHT / 2f - 16f) + playButton.draw(g) + settingsButton.draw(g) + } + +} diff --git a/src/main/kotlin/de/romjaki/pluggabledino/states/SettingsState.kt b/src/main/kotlin/de/romjaki/pluggabledino/states/SettingsState.kt new file mode 100644 index 0000000..5003232 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/states/SettingsState.kt @@ -0,0 +1,42 @@ +package de.romjaki.pluggabledino.states + +import de.romjaki.pluggabledino.HEIGHT +import de.romjaki.pluggabledino.MAINMENU +import de.romjaki.pluggabledino.SETTINGS +import de.romjaki.pluggabledino.WIDTH +import de.romjaki.pluggabledino.api.Button +import org.newdawn.slick.Color +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.state.BasicGameState +import org.newdawn.slick.state.StateBasedGame + +class SettingsState : BasicGameState() { + override fun init(container: GameContainer?, game: StateBasedGame?) { + game!! + backButton.addClickHandler { + game.enterState(MAINMENU) + } + } + + override fun enter(container: GameContainer?, game: StateBasedGame?) { + backButton.enter() + } + + override fun update(container: GameContainer?, game: StateBasedGame?, delta: Int) { + container!! + backButton.update(container.input) + } + + override fun getID(): Int = + SETTINGS + + val backButton = Button("BACK", WIDTH / 2f, HEIGHT / 8 * 7f) + + override fun render(container: GameContainer?, game: StateBasedGame?, g: Graphics?) { + g!! + g.background = Color.lightGray + backButton.draw(g) + } + +} diff --git a/src/main/kotlin/de/romjaki/pluggabledino/states/SplashScreen.kt b/src/main/kotlin/de/romjaki/pluggabledino/states/SplashScreen.kt new file mode 100644 index 0000000..d39b31a --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/states/SplashScreen.kt @@ -0,0 +1,41 @@ +package de.romjaki.pluggabledino.states + +import de.romjaki.pluggabledino.* +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.Image +import org.newdawn.slick.Input +import org.newdawn.slick.state.BasicGameState +import org.newdawn.slick.state.StateBasedGame + + +class SplashScreen : BasicGameState() { + override fun init(container: GameContainer?, game: StateBasedGame?) { + } + + override fun update(container: GameContainer?, game: StateBasedGame?, delta: Int) { + container!! + game!! + val input = container.input + if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)) { + input.clearMousePressedRecord() + game.enterState(MAINMENU) + } + if (input.isKeyDown(Input.KEY_Q)) { + System.exit(0) + } + } + + override fun getID(): Int = + SPLASHSCREEN + + + override fun render(container: GameContainer?, game: StateBasedGame?, g: Graphics?) { + g!! + g.drawImage(splash, 0f, 0f) + g.drawStringCentered("CLICK ANYWHERE TO CONTINUE", WIDTH / 2f, HEIGHT / 2f) + } + +} + + diff --git a/src/main/kotlin/de/romjaki/pluggabledino/util.kt b/src/main/kotlin/de/romjaki/pluggabledino/util.kt new file mode 100644 index 0000000..de434e0 --- /dev/null +++ b/src/main/kotlin/de/romjaki/pluggabledino/util.kt @@ -0,0 +1,23 @@ +package de.romjaki.pluggabledino + +import org.jbox2d.common.Vec2 +import org.newdawn.slick.Graphics +import org.newdawn.slick.Image +import org.newdawn.slick.Input + +fun Graphics.drawStringCentered(s: String, x: Float, y: Float) { + val h = font.getHeight(s) + val w = font.getWidth(s) + drawString(s, x - w / 2f, y - h / 2f) +} + +fun Graphics.drawImageCentered(image: Image, x: Float, y: Float) { + drawImage(image, x - image.width / 2f, y - image.height / 2) +} + +operator fun Vec2.plus(vec2: Vec2): Vec2? = add(vec2) + +fun Graphics.drawMousePointer(input: Input) { + fillOval(input.mouseX - 5f, input.mouseY - 5f, 10f, 10f) +} + -- cgit