Compare commits
12 Commits
cbace1e07e
...
main
| Author | SHA256 | Date | |
|---|---|---|---|
| 1b07a4e414 | |||
| 212119adac | |||
| 64af2ed168 | |||
| f0ec933944 | |||
| 4d361a3f85 | |||
| 14849c9b07 | |||
| 4343234f3a | |||
| 8032ca4eb5 | |||
| 485047df31 | |||
| 822357b14e | |||
| 5c89bd0d94 | |||
| cfebae281d |
@@ -1,16 +1,16 @@
|
||||
package com.badlogic.drop.android
|
||||
|
||||
import android.os.Bundle
|
||||
import com.badlogic.drop.Drop
|
||||
|
||||
import com.badlogic.gdx.backends.android.AndroidApplication
|
||||
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration
|
||||
import com.badlogic.drop.Main
|
||||
|
||||
/** Launches the Android application. */
|
||||
class AndroidLauncher : AndroidApplication() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
initialize(Main(), AndroidApplicationConfiguration().apply {
|
||||
initialize(Drop(), AndroidApplicationConfiguration().apply {
|
||||
// Configure your application here.
|
||||
useImmersiveMode = true // Recommended, but not required.
|
||||
})
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.badlogic.drop
|
||||
|
||||
import com.badlogic.gdx.Game
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.utils.viewport.FitViewport
|
||||
|
||||
class Drop : Game() {
|
||||
lateinit var batch: SpriteBatch
|
||||
lateinit var font: BitmapFont
|
||||
//lateinit var viewport: FitViewport // Use camera instead of viewport
|
||||
|
||||
override fun create(): Unit {
|
||||
batch = SpriteBatch()
|
||||
//viewport = FitViewport(8f, 5f)
|
||||
/*font = BitmapFont().apply {
|
||||
setUseIntegerPositions(false)
|
||||
data.scale(viewport.worldHeight / Gdx.graphics.height)
|
||||
}*/
|
||||
font = BitmapFont()
|
||||
|
||||
this.screen = MainMenuScreen(this)
|
||||
}
|
||||
|
||||
override fun render() {
|
||||
super.render()
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
batch.dispose()
|
||||
font.dispose()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.badlogic.drop
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.Gdx.audio
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite
|
||||
import com.badlogic.gdx.math.MathUtils
|
||||
import com.badlogic.gdx.math.Rectangle
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.math.Vector3
|
||||
import com.badlogic.gdx.utils.ScreenUtils
|
||||
import ktx.assets.toInternalFile
|
||||
|
||||
class GameScreen(val game: Drop) : Screen {
|
||||
val camera = OrthographicCamera().apply { setToOrtho(false, 800f, 480f) }
|
||||
|
||||
val backgroundTexture = Texture("background.png")
|
||||
val bucketTexture = Texture("bucket.png")
|
||||
val dropTexture = Texture("drop.png")
|
||||
val dropSound = audio.newSound("drop.mp3".toInternalFile())
|
||||
val music = audio.newMusic("music.mp3".toInternalFile()).apply {
|
||||
isLooping = true
|
||||
volume = 0.5f
|
||||
}
|
||||
val bucketSprite = Sprite(bucketTexture).apply { setSize(64f, 64f) }
|
||||
val touchPos = Vector3()
|
||||
val dropSprites = mutableListOf<Sprite>()
|
||||
val dropSpeed = -128f
|
||||
var dropTimer = 0f
|
||||
val bucketRectangle = Rectangle()
|
||||
val dropRectangle = Rectangle()
|
||||
var dropsGathered = 0
|
||||
|
||||
override fun show() {
|
||||
music.play()
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
input()
|
||||
logic()
|
||||
draw()
|
||||
}
|
||||
|
||||
private fun input() {
|
||||
val speed = 4f
|
||||
val delta: Float = Gdx.graphics.deltaTime
|
||||
|
||||
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
|
||||
bucketSprite.translateX(speed * delta)
|
||||
}
|
||||
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
|
||||
bucketSprite.translateX(-speed * delta)
|
||||
}
|
||||
|
||||
if (Gdx.input.isTouched) {
|
||||
touchPos.set(Gdx.input.x.toFloat(), Gdx.input.y.toFloat(), 0f)
|
||||
camera.unproject(touchPos)
|
||||
bucketSprite.setCenterX(touchPos.x)
|
||||
}
|
||||
}
|
||||
|
||||
private fun logic() {
|
||||
val worldWidth: Float = camera.viewportWidth
|
||||
val worldHeight: Float = camera.viewportHeight
|
||||
val bucketWidth: Float = bucketSprite.width
|
||||
val bucketHeight: Float = bucketSprite.height
|
||||
val delta: Float = Gdx.graphics.deltaTime
|
||||
|
||||
bucketSprite.x = MathUtils.clamp(bucketSprite.x, 0f, worldWidth - bucketWidth)
|
||||
bucketRectangle.set(bucketSprite.x, bucketSprite.y, bucketWidth, bucketHeight)
|
||||
|
||||
for (dropSprite in dropSprites.reversed()) {
|
||||
val dropWidth: Float = dropSprite.width
|
||||
val dropHeight: Float = dropSprite.height
|
||||
|
||||
dropSprite.translateY(dropSpeed * delta * (MathUtils.clamp((dropsGathered.toFloat() + 1f) / 5f, 1f, Float.MAX_VALUE)))
|
||||
dropRectangle.set(dropSprite.x, dropSprite.y, dropWidth, dropHeight)
|
||||
|
||||
if (dropSprite.y < -dropHeight) dropSprites.remove(dropSprite)
|
||||
else if (bucketRectangle.overlaps(dropRectangle)) {
|
||||
dropsGathered++
|
||||
dropSprites.remove(dropSprite)
|
||||
dropSound.play()
|
||||
}
|
||||
}
|
||||
|
||||
dropTimer += delta
|
||||
if (dropTimer > 1f) {
|
||||
dropTimer = 0f
|
||||
createDroplet()
|
||||
}
|
||||
}
|
||||
|
||||
private fun draw() {
|
||||
ScreenUtils.clear(Color.BLACK)
|
||||
|
||||
camera.update()
|
||||
game.batch.projectionMatrix = camera.combined
|
||||
|
||||
game.batch.begin()
|
||||
val worldWidth: Float = camera.viewportWidth
|
||||
val worldHeight: Float = camera.viewportHeight
|
||||
game.batch.draw(backgroundTexture, 0f, 0f, worldWidth, worldHeight)
|
||||
bucketSprite.draw(game.batch)
|
||||
|
||||
game.font.draw(game.batch, "Drops collected: $dropsGathered", 0f, worldHeight)
|
||||
|
||||
for (dropSprite in dropSprites) dropSprite.draw(game.batch)
|
||||
|
||||
game.batch.end()
|
||||
}
|
||||
|
||||
private fun createDroplet() {
|
||||
val dropWidth = 64f
|
||||
val dropHeight = 64f
|
||||
val worldWidth: Float = camera.viewportWidth
|
||||
val worldHeight: Float = camera.viewportHeight
|
||||
|
||||
val dropSprite = Sprite(dropTexture).apply {
|
||||
setSize(dropWidth, dropHeight)
|
||||
x = MathUtils.random(0f, worldWidth - dropWidth)
|
||||
y = worldHeight
|
||||
}
|
||||
dropSprites.add(dropSprite)
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) = Unit
|
||||
|
||||
override fun pause() = Unit
|
||||
|
||||
override fun resume() = Unit
|
||||
|
||||
override fun hide() = Unit
|
||||
|
||||
override fun dispose() {
|
||||
backgroundTexture.dispose()
|
||||
dropSound.dispose()
|
||||
music.dispose()
|
||||
dropTexture.dispose()
|
||||
bucketTexture.dispose()
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package com.badlogic.drop
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Gdx.audio
|
||||
import com.badlogic.gdx.audio.Music
|
||||
import com.badlogic.gdx.audio.Sound
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.Texture.TextureFilter.Linear
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.math.MathUtils
|
||||
import com.badlogic.gdx.math.Rectangle
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.utils.ScreenUtils
|
||||
import com.badlogic.gdx.utils.viewport.FitViewport
|
||||
import ktx.app.KtxGame
|
||||
import ktx.app.KtxScreen
|
||||
import ktx.assets.disposeSafely
|
||||
import ktx.assets.toInternalFile
|
||||
import ktx.async.KtxAsync
|
||||
import ktx.graphics.use
|
||||
|
||||
class Main : KtxGame<KtxScreen>() {
|
||||
override fun create() {
|
||||
KtxAsync.initiate()
|
||||
|
||||
addScreen(FirstScreen())
|
||||
setScreen<FirstScreen>()
|
||||
}
|
||||
class FirstScreen : KtxScreen {
|
||||
private val backgroundTexture: Texture = Texture("background.png".toInternalFile(), true).apply { setFilter(Linear, Linear) }
|
||||
private val bucketTexture: Texture = Texture("bucket.png".toInternalFile(), true).apply { setFilter(Linear, Linear) }
|
||||
private val dropTexture: Texture = Texture("drop.png".toInternalFile(), true).apply { setFilter(Linear, Linear) }
|
||||
|
||||
private val dropSound: Sound = audio.newSound("drop.mp3".toInternalFile())
|
||||
private val music: Music = audio.newMusic("music.mp3".toInternalFile()).apply {
|
||||
isLooping = true
|
||||
volume = 0.5f
|
||||
play()
|
||||
}
|
||||
|
||||
private val bucketSprite: Sprite = Sprite(bucketTexture).apply { setSize(1f, 1f) }
|
||||
|
||||
private val image = Texture("logo.png".toInternalFile(), true).apply { setFilter(Linear, Linear) }
|
||||
private val batch = SpriteBatch()
|
||||
private val viewport = FitViewport(8f, 5f)
|
||||
|
||||
private var touchPos: Vector2 = Vector2()
|
||||
|
||||
private var dropletSpriteList: MutableList<Sprite> = mutableListOf()
|
||||
|
||||
private var dropTimer: Float = 0f
|
||||
|
||||
private val bucketRectangle: Rectangle = Rectangle()
|
||||
private val dropletRectangle: Rectangle = Rectangle()
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
viewport.update(width, height, true)
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
input()
|
||||
logic()
|
||||
draw()
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
image.disposeSafely()
|
||||
batch.disposeSafely()
|
||||
}
|
||||
|
||||
private fun input() {
|
||||
if (Gdx.input.isTouched) {
|
||||
touchPos.set(Gdx.input.x.toFloat(), Gdx.input.y.toFloat())
|
||||
viewport.unproject(touchPos)
|
||||
bucketSprite.setCenterX(touchPos.x)
|
||||
}
|
||||
}
|
||||
|
||||
private fun logic() {
|
||||
val worldWidth: Float = viewport.worldWidth
|
||||
|
||||
bucketSprite.x = MathUtils.clamp(bucketSprite.x, 0f, worldWidth - bucketSprite.width)
|
||||
|
||||
val delta: Float = Gdx.graphics.deltaTime
|
||||
bucketRectangle.set(bucketSprite.x, bucketSprite.y, bucketSprite.width, bucketSprite.height)
|
||||
|
||||
for (sprite in dropletSpriteList.reversed()) {
|
||||
sprite.translateY(-2f * delta)
|
||||
|
||||
dropletRectangle.set(sprite.x, sprite.y, sprite.width, sprite.height)
|
||||
|
||||
if (sprite.y < -sprite.height) dropletSpriteList.remove(sprite)
|
||||
else if (bucketRectangle.overlaps(dropletRectangle)) {
|
||||
dropletSpriteList.remove(sprite)
|
||||
dropSound.play()
|
||||
}
|
||||
}
|
||||
|
||||
dropTimer += delta
|
||||
if (dropTimer >= 1f)
|
||||
{
|
||||
dropTimer = 0f
|
||||
dropletSpriteList.add(createDroplet())
|
||||
}
|
||||
//Gdx.app.log("Droplets", dropletSpriteList.size.toString() + " in List")
|
||||
}
|
||||
|
||||
private fun draw() {
|
||||
ScreenUtils.clear(Color.BLACK)
|
||||
viewport.apply()
|
||||
batch.setProjectionMatrix(viewport.camera.combined)
|
||||
batch.use {
|
||||
it.draw(backgroundTexture, 0f, 0f, viewport.worldWidth, viewport.worldHeight)
|
||||
for (s in dropletSpriteList) {
|
||||
s.draw(it)
|
||||
}
|
||||
bucketSprite.draw(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDroplet(): Sprite {
|
||||
val dropWidth: Float = 1f
|
||||
val dropHeight: Float = 1f
|
||||
val worldWidth: Float = viewport.worldWidth
|
||||
val worldHeight: Float = viewport.worldHeight
|
||||
|
||||
val dropSprite: Sprite = Sprite(dropTexture).apply {
|
||||
setSize(dropWidth, dropHeight)
|
||||
x = MathUtils.random(0f, worldWidth - dropWidth)
|
||||
y = worldHeight //- dropHeight // Spawn droplet above world for cleaner transition in?
|
||||
} // We don't add the object to the set here because apply is really meant for doing stuff with members
|
||||
|
||||
return dropSprite
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.badlogic.drop
|
||||
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.utils.ScreenUtils
|
||||
|
||||
class MainMenuScreen(val game: Drop) : Screen {
|
||||
private val camera = OrthographicCamera()
|
||||
|
||||
init {
|
||||
camera.setToOrtho(false, 800f, 480f)
|
||||
}
|
||||
|
||||
override fun show() = Unit
|
||||
|
||||
override fun render(delta: Float) {
|
||||
ScreenUtils.clear(Color.BLACK)
|
||||
|
||||
//game.viewport.apply()
|
||||
//game.batch.projectionMatrix = game.viewport.camera.combined
|
||||
camera.update()
|
||||
game.batch.projectionMatrix = camera.combined
|
||||
|
||||
game.batch.begin()
|
||||
|
||||
game.font.draw(game.batch, "Welcome to Drop!!!", 100f, 150f)
|
||||
game.font.draw(game.batch, "Tap anywhere to begin!", 100f, 100f)
|
||||
|
||||
game.batch.end()
|
||||
|
||||
if (Gdx.input.isTouched) {
|
||||
game.screen = GameScreen(game)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) = Unit
|
||||
|
||||
override fun pause() = Unit
|
||||
|
||||
override fun resume() = Unit
|
||||
|
||||
override fun hide() = Unit
|
||||
|
||||
override fun dispose() = Unit
|
||||
}
|
||||
18
Exercises/NetworkedTicTacToe/.editorconfig
Normal file
@@ -0,0 +1,18 @@
|
||||
# https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{java,scala,groovy,kt,kts}]
|
||||
indent_size = 4
|
||||
|
||||
[*.gradle]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
Exercises/NetworkedTicTacToe/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
* text=auto eol=lf
|
||||
*.bat text=auto eol=crlf
|
||||
203
Exercises/NetworkedTicTacToe/.gitignore
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
## Gradle:
|
||||
.gradle/
|
||||
gradle-app.setting
|
||||
/build/
|
||||
/android/build/
|
||||
/core/build/
|
||||
/lwjgl2/build/
|
||||
/lwjgl3/build/
|
||||
/html/build/
|
||||
/teavm/build/
|
||||
/ios/build/
|
||||
/ios-moe/build/
|
||||
/headless/build/
|
||||
/server/build/
|
||||
/shared/build/
|
||||
|
||||
## Java:
|
||||
*.class
|
||||
*.war
|
||||
*.ear
|
||||
hs_err_pid*
|
||||
.attach_pid*
|
||||
|
||||
## Android:
|
||||
/android/libs/armeabi-v7a/
|
||||
/android/libs/arm64-v8a/
|
||||
/android/libs/x86/
|
||||
/android/libs/x86_64/
|
||||
/android/gen/
|
||||
/android/out/
|
||||
local.properties
|
||||
com_crashlytics_export_strings.xml
|
||||
|
||||
## Robovm:
|
||||
/ios/robovm-build/
|
||||
|
||||
## iOS:
|
||||
/ios/xcode/*.xcodeproj/*
|
||||
!/ios/xcode/*.xcodeproj/xcshareddata
|
||||
!/ios/xcode/*.xcodeproj/project.pbxproj
|
||||
/ios/xcode/native/
|
||||
/ios/IOSLauncher.app
|
||||
/ios/IOSLauncher.app.dSYM
|
||||
|
||||
## GWT:
|
||||
/html/war/
|
||||
/html/gwt-unitCache/
|
||||
.apt_generated/
|
||||
/html/war/WEB-INF/deploy/
|
||||
/html/war/WEB-INF/classes/
|
||||
.gwt/
|
||||
gwt-unitCache/
|
||||
www-test/
|
||||
.gwt-tmp/
|
||||
|
||||
## TeaVM:
|
||||
# Not sure yet...
|
||||
|
||||
## IntelliJ, Android Studio:
|
||||
.idea/
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
|
||||
## Eclipse:
|
||||
.classpath
|
||||
.project
|
||||
.metadata/
|
||||
/android/bin/
|
||||
/core/bin/
|
||||
/lwjgl2/bin/
|
||||
/lwjgl3/bin/
|
||||
/html/bin/
|
||||
/teavm/bin/
|
||||
/ios/bin/
|
||||
/ios-moe/bin/
|
||||
/headless/bin/
|
||||
/server/bin/
|
||||
/shared/bin/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
.settings/
|
||||
.loadpath
|
||||
.externalToolBuilders/
|
||||
*.launch
|
||||
|
||||
|
||||
## NetBeans:
|
||||
|
||||
/nbproject/private/
|
||||
/android/nbproject/private/
|
||||
/core/nbproject/private/
|
||||
/lwjgl2/nbproject/private/
|
||||
/lwjgl3/nbproject/private/
|
||||
/html/nbproject/private/
|
||||
/teavm/nbproject/private/
|
||||
/ios/nbproject/private/
|
||||
/ios-moe/nbproject/private/
|
||||
/headless/nbproject/private/
|
||||
/server/nbproject/private/
|
||||
/shared/nbproject/private/
|
||||
|
||||
/nbbuild/
|
||||
/android/nbbuild/
|
||||
/core/nbbuild/
|
||||
/lwjgl2/nbbuild/
|
||||
/lwjgl3/nbbuild/
|
||||
/html/nbbuild/
|
||||
/teavm/nbbuild/
|
||||
/ios/nbbuild/
|
||||
/ios-moe/nbbuild/
|
||||
/headless/nbbuild/
|
||||
/server/nbbuild/
|
||||
/shared/nbbuild/
|
||||
|
||||
/dist/
|
||||
/android/dist/
|
||||
/core/dist/
|
||||
/lwjgl2/dist/
|
||||
/lwjgl3/dist/
|
||||
/html/dist/
|
||||
/teavm/dist/
|
||||
/ios/dist/
|
||||
/ios-moe/dist/
|
||||
/headless/dist/
|
||||
/server/dist/
|
||||
/shared/dist/
|
||||
|
||||
/nbdist/
|
||||
/android/nbdist/
|
||||
/core/nbdist/
|
||||
/lwjgl2/nbdist/
|
||||
/lwjgl3/nbdist/
|
||||
/html/nbdist/
|
||||
/teavm/nbdist/
|
||||
/ios/nbdist/
|
||||
/ios-moe/nbdist/
|
||||
/headless/nbdist/
|
||||
/server/nbdist/
|
||||
/shared/nbdist/
|
||||
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
|
||||
## OS-Specific:
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
## Miscellaneous:
|
||||
*~
|
||||
*.*#
|
||||
*#*#
|
||||
/.kotlin/
|
||||
/assets/assets.txt
|
||||
|
||||
## Special cases:
|
||||
|
||||
## There is a resource-config.json file generated by nativeimage.gradle if you use Graal Native Image.
|
||||
## Some usage may need extra resource configuration in a different file with the same name.
|
||||
## You could also add that configuration to the text in nativeimage.gradle .
|
||||
## You should delete or comment out the next line if you have configuration in a different resource-config.json .
|
||||
**/resource-config.json
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/c++
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=c++
|
||||
|
||||
### C++ ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
GameServer/server
|
||||
# End of https://www.toptal.com/developers/gitignore/api/c++
|
||||
256
Exercises/NetworkedTicTacToe/GameServer/GameServer.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
#include <SFML/Network.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
// TODO: move `GameServer` into its own files (h/cpp).
|
||||
// Note: This is compiled with SFML 2.6.2 in mind.
|
||||
// It would work similarly with slightly older versions of SFML.
|
||||
// A thourough rework is necessary for SFML 3.0.
|
||||
|
||||
enum GameMessageType : unsigned char {
|
||||
JOIN_GAME = 0x01, PLACE_TOKEN = 0x02, START_GAME = 0x03, GAME_OVER = 0x04
|
||||
};
|
||||
|
||||
enum Token : unsigned char {
|
||||
NOUGHTS = 0x01, CROSSES = 0x02
|
||||
};
|
||||
|
||||
class GameServer {
|
||||
public:
|
||||
GameServer(unsigned short tcp_port) :
|
||||
m_tcp_port(tcp_port) {}
|
||||
|
||||
|
||||
bool send_start_game_to_clients() {
|
||||
char buf[1] = { START_GAME };
|
||||
std::cout << "Starting the game..." << std::endl;
|
||||
return broadcast_message(buf, nullptr);
|
||||
}
|
||||
|
||||
bool send_game_over_to_clients() {
|
||||
char buf[1] = { GAME_OVER };
|
||||
std::cout << "Game Over!" << std::endl;
|
||||
return broadcast_message(buf, nullptr);
|
||||
}
|
||||
|
||||
// Binds to a port and then loops around. For every client that connects,
|
||||
// we start a new thread receiving their messages.
|
||||
void tcp_start()
|
||||
{
|
||||
// BINDING
|
||||
sf::TcpListener listener;
|
||||
sf::Socket::Status status = listener.listen(m_tcp_port, sf::IpAddress("152.105.66.120")); // Make sure to change this!
|
||||
if (status != sf::Socket::Status::Done)
|
||||
{
|
||||
std::cerr << "Error binding listener to port" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "TCP Server is listening to port "
|
||||
<< m_tcp_port
|
||||
<< ", waiting for connections..."
|
||||
<< std::endl;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// ACCEPTING
|
||||
if(m_player_count < 2)
|
||||
{
|
||||
sf::TcpSocket* client = new sf::TcpSocket;
|
||||
status = listener.accept(*client);
|
||||
if (status != sf::Socket::Status::Done)
|
||||
{
|
||||
delete client;
|
||||
} else {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_clients_mutex);
|
||||
m_clients.push_back(client);
|
||||
}
|
||||
std::cout << "New client connected: "
|
||||
<< client->getRemoteAddress()
|
||||
<< std::endl;
|
||||
|
||||
m_player_count++;
|
||||
|
||||
std::thread(&GameServer::handle_client, this, client, m_player_count).detach();
|
||||
|
||||
if(m_player_count == 2)
|
||||
{
|
||||
// --------------------------------------------------------------
|
||||
// Slight pause to ensure the all threads have started
|
||||
// --------------------------------------------------------------
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
|
||||
if(!send_start_game_to_clients()) {
|
||||
std::cerr << "Could not start game. One or both players did not recieve START_GAME" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// No need to call close of the listener.
|
||||
// The connection is closed automatically when the listener object is out of scope.
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned short m_tcp_port;
|
||||
unsigned short m_player_count { 0 };
|
||||
unsigned short m_turns_played { 0 };
|
||||
int board[3][3];
|
||||
|
||||
std::vector<sf::TcpSocket*> m_clients;
|
||||
std::mutex m_clients_mutex;
|
||||
|
||||
// Loop around, receive messages from client and send them to all
|
||||
// the other connected clients.
|
||||
void handle_client(sf::TcpSocket* client, unsigned short player_num)
|
||||
{
|
||||
sf::Socket::Status status;
|
||||
|
||||
if(player_num == 1) {
|
||||
std::cout << "Player " << player_num << " is NOUGHTS" << std::endl;
|
||||
char buffer[2] = {
|
||||
GameMessageType::JOIN_GAME,
|
||||
Token::NOUGHTS
|
||||
};
|
||||
|
||||
status = client->send(buffer, message_size(GameMessageType::JOIN_GAME));
|
||||
|
||||
if (status != sf::Socket::Status::Done)
|
||||
{
|
||||
std::cerr << "Error sending JOIN_GAME to player 1" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(player_num == 2) {
|
||||
std::cout << "Player " << player_num << " is CROSSES" << std::endl;
|
||||
char buffer[2] = {
|
||||
GameMessageType::JOIN_GAME,
|
||||
Token::CROSSES
|
||||
};
|
||||
|
||||
status = client->send(buffer, message_size(GameMessageType::JOIN_GAME));
|
||||
|
||||
if (status != sf::Socket::Status::Done)
|
||||
{
|
||||
std::cerr << "Error sending JOIN_GAME to player 2" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return; // No more players please!!!
|
||||
}
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
// RECEIVING
|
||||
char payload[1024];
|
||||
std::memset(payload, 0, 1024);
|
||||
size_t received;
|
||||
sf::Socket::Status status = client->receive(payload, 1024, received);
|
||||
if (status != sf::Socket::Status::Done)
|
||||
{
|
||||
std::cerr << "Error receiving message from client" << std::endl;
|
||||
break;
|
||||
} else {
|
||||
// Actually, there is no need to print the message if the message is not a string
|
||||
debug_message(payload);
|
||||
|
||||
broadcast_message(payload, client);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
|
||||
if(++m_turns_played == 9) {
|
||||
send_game_over_to_clients();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Everything that follows only makes sense if we have a graceful way to exiting the loop.
|
||||
// Remove the client from the list when done
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_clients_mutex);
|
||||
m_clients.erase(std::remove(m_clients.begin(), m_clients.end(), client),
|
||||
m_clients.end());
|
||||
}
|
||||
delete client;
|
||||
}
|
||||
|
||||
// Sends `message` from `sender` to all the other connected clients
|
||||
bool broadcast_message(const char *buffer, sf::TcpSocket* sender)
|
||||
{
|
||||
size_t msgSize { message_size(buffer[0]) };
|
||||
|
||||
// You might want to validate the message before you send it.
|
||||
// A few reasons for that:
|
||||
// 1. Make sure the message makes sense in the game.
|
||||
// 2. Make sure the sender is not cheating.
|
||||
// 3. First need to synchronise the players inputs (usually done in Lockstep).
|
||||
// 4. Compensate for latency and perform rollbacks (usually done in Ded Reckoning).
|
||||
// 5. Delay the sending of messages to make the game fairer wrt high ping players.
|
||||
// This is where you can write the authoritative part of the server.
|
||||
std::lock_guard<std::mutex> lock(m_clients_mutex);
|
||||
for (auto& client : m_clients)
|
||||
{
|
||||
if (client != sender)
|
||||
{
|
||||
// SENDING
|
||||
sf::Socket::Status status = client->send(buffer, msgSize) ;
|
||||
if (status != sf::Socket::Status::Done)
|
||||
{
|
||||
std::cerr << "Error sending message to client" << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr size_t message_size(const char messageType)
|
||||
{
|
||||
switch(messageType) {
|
||||
case JOIN_GAME: return 2;
|
||||
case PLACE_TOKEN: return sizeof(int) * 2 + 2;
|
||||
case START_GAME: return 1;
|
||||
case GAME_OVER: return 1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void debug_message(const char *buf)
|
||||
{
|
||||
const unsigned char msgType = buf[0];
|
||||
|
||||
switch(msgType) {
|
||||
case JOIN_GAME: {
|
||||
std::cout << "Player Joined The Game" << std::endl;
|
||||
break;
|
||||
}
|
||||
case PLACE_TOKEN: {
|
||||
const unsigned char *row { (unsigned char* )buf + 1 };
|
||||
const unsigned char *col { (unsigned char* )buf + 1 + sizeof(int) };
|
||||
unsigned int rowI = be32toh(*((unsigned int *) row));
|
||||
unsigned int colI = be32toh(*((unsigned int *) col));
|
||||
std::cout << "Player Placed A Token: (" << rowI << ", " << colI << ")" << std::endl;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
GameServer server(4331);
|
||||
|
||||
server.tcp_start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
16
Exercises/NetworkedTicTacToe/GameServer/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
SFML_PATH=/usr/local/Cellar/sfml/2.6.1/
|
||||
CXXFLAGS= -std=c++14 -Wall -Wpedantic -I${SFML_PATH}include/
|
||||
LDFLAGS=-L${SFML_PATH}lib/
|
||||
CFLAGS=-g -lsfml-graphics -lsfml-window -lsfml-system -lsfml-network -pthread
|
||||
CPPFLAGS=
|
||||
LDLIBS=
|
||||
LIBS=
|
||||
CPP=g++
|
||||
|
||||
all: server
|
||||
|
||||
server: GameServer.o
|
||||
$(CPP) $(CXXFLAGS) $(LDFLAGS) $(LIBS) $^ -o $@ $(CFLAGS)
|
||||
|
||||
clean:
|
||||
\rm -f *.o server
|
||||
35
Exercises/NetworkedTicTacToe/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# NetworkedTicTacToe
|
||||
|
||||
A [libGDX](https://libgdx.com/) project generated with [gdx-liftoff](https://github.com/libgdx/gdx-liftoff).
|
||||
|
||||
This project was generated with a Kotlin project template that includes Kotlin application launchers and [KTX](https://libktx.github.io/) utilities.
|
||||
|
||||
## Platforms
|
||||
|
||||
- `core`: Main module with the application logic shared by all platforms.
|
||||
- `lwjgl3`: Primary desktop platform using LWJGL3; was called 'desktop' in older docs.
|
||||
- `android`: Android mobile platform. Needs Android SDK.
|
||||
|
||||
## Gradle
|
||||
|
||||
This project uses [Gradle](https://gradle.org/) to manage dependencies.
|
||||
The Gradle wrapper was included, so you can run Gradle tasks using `gradlew.bat` or `./gradlew` commands.
|
||||
Useful Gradle tasks and flags:
|
||||
|
||||
- `--continue`: when using this flag, errors will not stop the tasks from running.
|
||||
- `--daemon`: thanks to this flag, Gradle daemon will be used to run chosen tasks.
|
||||
- `--offline`: when using this flag, cached dependency archives will be used.
|
||||
- `--refresh-dependencies`: this flag forces validation of all dependencies. Useful for snapshot versions.
|
||||
- `android:lint`: performs Android project validation.
|
||||
- `build`: builds sources and archives of every project.
|
||||
- `cleanEclipse`: removes Eclipse project data.
|
||||
- `cleanIdea`: removes IntelliJ project data.
|
||||
- `clean`: removes `build` folders, which store compiled classes and built archives.
|
||||
- `eclipse`: generates Eclipse project data.
|
||||
- `idea`: generates IntelliJ project data.
|
||||
- `lwjgl3:jar`: builds application's runnable jar, which can be found at `lwjgl3/build/libs`.
|
||||
- `lwjgl3:run`: starts the application.
|
||||
- `test`: runs unit tests (if any).
|
||||
|
||||
Note that most tasks that are not specific to a single project can be run with `name:` prefix, where the `name` should be replaced with the ID of a specific project.
|
||||
For example, `core:clean` removes `build` folder only from the `core` project.
|
||||
29
Exercises/NetworkedTicTacToe/android/AndroidManifest.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:isGame="true"
|
||||
android:appCategory="game"
|
||||
android:label="@string/app_name"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:theme="@style/GdxTheme">
|
||||
<activity
|
||||
android:name="u0012604.tictactoe.android.AndroidLauncher"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="landscape"
|
||||
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
136
Exercises/NetworkedTicTacToe/android/build.gradle
Normal file
@@ -0,0 +1,136 @@
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
}
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
namespace = "u0012604.tictactoe"
|
||||
compileSdk = 35
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.setSrcDirs(['src/main/java', 'src/main/kotlin'])
|
||||
aidl.setSrcDirs(['src/main/java', 'src/main/kotlin'])
|
||||
renderscript.setSrcDirs(['src/main/java', 'src/main/kotlin'])
|
||||
res.setSrcDirs(['res'])
|
||||
assets.setSrcDirs(['../assets'])
|
||||
jniLibs.setSrcDirs(['libs'])
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
excludes += ['META-INF/robovm/ios/robovm.xml', 'META-INF/DEPENDENCIES.txt', 'META-INF/DEPENDENCIES',
|
||||
'META-INF/dependencies.txt', '**/*.gwt.xml']
|
||||
pickFirsts += ['META-INF/LICENSE.txt', 'META-INF/LICENSE', 'META-INF/license.txt', 'META-INF/LGPL2.1',
|
||||
'META-INF/NOTICE.txt', 'META-INF/NOTICE', 'META-INF/notice.txt']
|
||||
}
|
||||
}
|
||||
defaultConfig {
|
||||
applicationId 'u0012604.tictactoe'
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 35
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility "8"
|
||||
targetCompatibility "8"
|
||||
coreLibraryDesugaringEnabled = true
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
kotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
|
||||
|
||||
}
|
||||
|
||||
repositories {
|
||||
// needed for AAPT2, may be needed for other tools
|
||||
google()
|
||||
}
|
||||
|
||||
configurations { natives }
|
||||
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||
implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
|
||||
implementation project(':core')
|
||||
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-arm64-v8a"
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86"
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86_64"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
|
||||
|
||||
}
|
||||
|
||||
// Called every time gradle gets executed, takes the native dependencies of
|
||||
// the natives configuration, and extracts them to the proper libs/ folders
|
||||
// so they get packed with the APK.
|
||||
tasks.register('copyAndroidNatives') {
|
||||
doFirst {
|
||||
file("libs/armeabi-v7a/").mkdirs()
|
||||
file("libs/arm64-v8a/").mkdirs()
|
||||
file("libs/x86_64/").mkdirs()
|
||||
file("libs/x86/").mkdirs()
|
||||
|
||||
configurations.natives.copy().files.each { jar ->
|
||||
def outputDir = null
|
||||
if(jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a")
|
||||
if(jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a")
|
||||
if(jar.name.endsWith("natives-x86_64.jar")) outputDir = file("libs/x86_64")
|
||||
if(jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86")
|
||||
if(outputDir != null) {
|
||||
copy {
|
||||
from zipTree(jar)
|
||||
into outputDir
|
||||
include "*.so"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.matching { it.name.contains("merge") && it.name.contains("JniLibFolders") }.configureEach { packageTask ->
|
||||
packageTask.dependsOn 'copyAndroidNatives'
|
||||
}
|
||||
|
||||
tasks.register('run', Exec) {
|
||||
def path
|
||||
def localProperties = project.file("../local.properties")
|
||||
if (localProperties.exists()) {
|
||||
Properties properties = new Properties()
|
||||
localProperties.withInputStream { instr ->
|
||||
properties.load(instr)
|
||||
}
|
||||
def sdkDir = properties.getProperty('sdk.dir')
|
||||
if (sdkDir) {
|
||||
path = sdkDir
|
||||
} else {
|
||||
path = "$System.env.ANDROID_SDK_ROOT"
|
||||
}
|
||||
} else {
|
||||
path = "$System.env.ANDROID_SDK_ROOT"
|
||||
}
|
||||
|
||||
def adb = path + "/platform-tools/adb"
|
||||
commandLine "$adb", 'shell', 'am', 'start', '-n', 'u0012604.tictactoe/u0012604.tictactoe.android.AndroidLauncher'
|
||||
}
|
||||
|
||||
eclipse.project.name = appName + "-android"
|
||||
BIN
Exercises/NetworkedTicTacToe/android/ic_launcher-web.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
52
Exercises/NetworkedTicTacToe/android/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# https://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
-verbose
|
||||
|
||||
-dontwarn android.support.**
|
||||
-dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication
|
||||
|
||||
# Needed by the gdx-controllers official extension.
|
||||
-keep class com.badlogic.gdx.controllers.android.AndroidControllers
|
||||
|
||||
# Needed by the Box2D official extension.
|
||||
-keepclassmembers class com.badlogic.gdx.physics.box2d.World {
|
||||
boolean contactFilter(long, long);
|
||||
boolean getUseDefaultContactFilter();
|
||||
void beginContact(long);
|
||||
void endContact(long);
|
||||
void preSolve(long, long);
|
||||
void postSolve(long, long);
|
||||
boolean reportFixture(long);
|
||||
float reportRayFixture(long, float, float, float, float, float);
|
||||
}
|
||||
|
||||
# You will need the next three lines if you use scene2d for UI or gameplay.
|
||||
# If you don't use scene2d at all, you can remove or comment out the next line:
|
||||
-keep public class com.badlogic.gdx.scenes.scene2d.** { *; }
|
||||
# You will need the next two lines if you use BitmapFont or any scene2d.ui text:
|
||||
-keep public class com.badlogic.gdx.graphics.g2d.BitmapFont { *; }
|
||||
# You will probably need this line in most cases:
|
||||
-keep public class com.badlogic.gdx.graphics.Color { *; }
|
||||
|
||||
# These two lines are used with mapping files; see https://developer.android.com/build/shrink-code#retracing
|
||||
-keepattributes LineNumberTable,SourceFile
|
||||
-renamesourcefileattribute SourceFile
|
||||
14
Exercises/NetworkedTicTacToe/android/project.properties
Normal file
@@ -0,0 +1,14 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-rules.pro
|
||||
|
||||
# Project target.
|
||||
target=android-21
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_background_color"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,28 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M457.78,372.5l-201.78,116.5l-201.78,-116.5l0,-233l201.78,-116.5l201.78,116.5z"
|
||||
android:strokeWidth="23"
|
||||
android:fillColor="#4a4a4a"
|
||||
android:strokeColor="#000000"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M449.71,363.84l-193.71,111.84l-193.71,-111.84l0,-223.68l193.71,-111.84l193.71,111.84z"/>
|
||||
<path
|
||||
android:pathData="M256,67.33c-0.36,0.13 -1.07,0.4 -2,0.99 -1.67,1.07 -3.94,2.89 -6.4,5.26 -4.93,4.75 -10.72,11.66 -16.1,19.34a142.77,142.77 0,0 0,-2.95 4.41c9.43,-1.86 18.44,-2.8 27.45,-2.8 9.01,0 18.03,0.94 27.45,2.8a142.77,142.77 135,0 0,-2.95 -4.41c-5.38,-7.68 -11.17,-14.6 -16.1,-19.34 -2.46,-2.37 -4.73,-4.2 -6.4,-5.26a9.93,9.93 135,0 0,-2 -0.99zM256,108.66c-11.75,0 -23.5,1.9 -36.98,5.69C214.74,123.36 212,131.66 212,136.8l0,127.71c4.08,-13.81 7.7,-30.59 11.2,-51.52L223.2,200.8c0,-8.8 3.65,-18.74 9.03,-27.7 2.69,-4.48 5.85,-8.63 9.66,-11.94C245.69,157.86 250.4,155.2 256,155.2s10.31,2.66 14.12,5.96c3.81,3.3 6.97,7.45 9.66,11.94C285.15,182.06 288.8,192 288.8,200.8l0,12.19c3.5,20.94 7.12,37.71 11.2,51.52L300,136.8c0,-5.14 -2.74,-13.44 -7.02,-22.45 -13.47,-3.79 -25.23,-5.69 -36.98,-5.69zM185.6,150.71c-5.21,9.21 -12,23.48 -12,37.29l0,31.2l24,0l0,-31.2c0,-13.81 -6.79,-28.08 -12,-37.29zM326.4,150.71c-5.21,9.21 -12,23.48 -12,37.29l0,31.2l24,0l0,-31.2c0,-13.81 -6.79,-28.08 -12,-37.29zM256,169.6c-0.8,0 -2.49,0.54 -4.68,2.44 -2.19,1.9 -4.63,4.95 -6.74,8.46C240.35,187.54 237.6,196.8 237.6,200.8l0,131.02l-2.16,2.12c-8.49,8.33 -10.26,28.91 -10.52,42.22 5.34,2.83 14.26,5.13 23.88,5.94L248.8,341.6l14.4,0l0,40.49c9.62,-0.8 18.54,-3.11 23.88,-5.94 -0.25,-13.27 -1.97,-33.66 -10.57,-42.26L274.4,331.78L274.4,200.8c0,-4 -2.75,-13.26 -6.97,-20.3 -2.11,-3.52 -4.55,-6.57 -6.74,-8.46C258.49,170.14 256.8,169.6 256,169.6zM243.2,193.6l25.6,0l0,14.4l-25.6,0l0,-14.4zM173.6,233.6l0,93.05c9.94,-8.52 17.6,-17.06 24,-27.75L197.6,233.6l-24,0zM314.4,233.6l0,65.3c6.4,10.69 14.06,19.24 24,27.75L338.4,233.6l-24,0zM223.2,276.78c-2.81,8.32 -5.87,15.8 -9.36,22.54 -7.44,14.41 -16.73,25.6 -28.37,36.03l30.94,1.55c1.73,-3.88 3.94,-7.57 6.78,-10.87l0,-49.24zM288.8,276.78l0,49.28c2.81,3.3 5,6.98 6.72,10.84l31,-1.55c-11.64,-10.42 -20.92,-21.62 -28.37,-36.03 -3.48,-6.74 -6.55,-14.22 -9.36,-22.54zM446.4,289.61c-10.84,4.52 -15.22,15.65 -21.56,33.46 0,0 -36.65,0.34 -42.7,14.05 -6.46,14.65 19.67,43.83 19.67,43.83s-21.71,-6.98 -30.34,-1.69c-9.59,5.88 -13.61,30.87 -13.61,30.87 -2.83,-0.68 -5.52,-1.24 -8.11,-1.71L341.33,383.2l8.53,0l-4.79,-8.77 -42.81,2.14 -0.65,1.2c-0,0.73 -0.01,1.56 -0.01,2.22l0,3.2l5.6,0l-8.53,25.6 17.07,-12.8 4,12.01c-11.83,2.51 -20.44,8.55 -28.72,16.43L281.6,405.6l12.8,0l-10.24,-12.49C275.61,395.79 265.83,396.8 256,396.8c-9.85,0 -19.66,-1.02 -28.22,-3.7L217.6,405.6l12.8,0l-10.31,20.62c-9.71,-4.02 -20.02,-8.02 -30.08,-11.44L196.27,396l17.07,12.8L204.8,383.2l5.6,0l0,-3.2c0,-0.65 -0.01,-1.47 -0.01,-2.18l-0.68,-1.24 -42.82,-2.14 -4.76,8.77l8.53,0l-7.96,23.89c-3.19,-0.65 -6.24,-1.16 -9.1,-1.49 -25.25,-2.9 -31.78,3.71 -46.35,9.93 0,0 13.33,-77.26 -13.35,-94.7 -3.3,-2.16 -7.43,-3.03 -11.99,-2.98 -5.06,0.04 -10.67,1.22 -16.31,2.99L65.6,442.4l189.6,0l0.8,1.6 12.8,-25.6 18.79,9.4c-4.45,4.5 -8.93,9.46 -13.88,14.6L446.4,442.4L446.4,289.61zM168.82,348.93c-4.32,3.9 -5.52,7.7 -5.45,9.24 0.04,0.88 0.19,1 0.41,1.19 0.22,0.19 0.81,0.63 2.63,0.63l0.18,0l44.16,2.21c0.25,-3.58 0.68,-7.33 1.39,-11.11l-43.31,-2.17zM343.18,348.93l-43.35,2.17c0.72,3.78 1.15,7.53 1.41,11.11l44.18,-2.21L345.6,360c1.82,0 2.42,-0.44 2.63,-0.63 0.22,-0.19 0.37,-0.32 0.41,-1.19 0.06,-1.54 -1.14,-5.34 -5.45,-9.24zM179.2,396l5.7,17.09c-7.29,-2.35 -14.35,-4.32 -20.86,-5.72L179.2,396zM332.8,396l16.44,12.33c-7.58,-1.34 -14.17,-1.78 -20.05,-1.5L332.8,396zM243.2,418.4l11.64,23.27c-7.9,-3.74 -18.63,-8.66 -30.68,-13.75L243.2,418.4z"
|
||||
android:fillColor="#ffda54"/>
|
||||
</group>
|
||||
<path
|
||||
android:pathData="M135.76,190.05L112.46,190.05v-15.61q0,-6.81 -0.77,-8.47 -0.72,-1.72 -3.26,-1.72 -2.88,0 -3.65,2.05 -0.77,2.05 -0.77,8.85v41.61q0,6.53 0.77,8.52 0.77,1.99 3.49,1.99 2.6,0 3.38,-1.99 0.83,-1.99 0.83,-9.35v-11.23h23.3v3.49q0,13.89 -1.99,19.7 -1.94,5.81 -8.69,10.18 -6.7,4.37 -16.55,4.37 -10.24,0 -16.88,-3.71 -6.64,-3.71 -8.8,-10.24 -2.16,-6.59 -2.16,-19.76L80.7,182.58q0,-9.68 0.66,-14.5 0.66,-4.87 3.93,-9.35 3.32,-4.48 9.13,-7.03 5.87,-2.6 13.45,-2.6 10.29,0 16.99,3.98 6.7,3.98 8.8,9.96 2.1,5.92 2.1,18.48zM197.68,150.98v89.59h-23.3v-37.63h-6.97v37.63h-23.3v-89.59h23.3v32.04h6.97v-32.04zM247.27,150.98 L260.6,240.57L236.75,240.57l-1.16,-16.1h-8.36l-1.38,16.1h-24.13l11.84,-89.59zM234.93,208.59q-1.77,-15.22 -3.54,-37.57 -3.54,25.68 -4.43,37.57zM316.6,150.98v89.59h-20.42l-12.12,-40.73v40.73h-19.48v-89.59h19.48l13.06,40.34v-40.34zM379.41,183.96h-23.3v-8.13q0,-7.69 -0.66,-9.63 -0.66,-1.94 -3.15,-1.94 -2.16,0 -2.93,1.66 -0.77,1.66 -0.77,8.52v43q0,6.03 0.77,7.97 0.77,1.88 3.1,1.88 2.55,0 3.43,-2.16 0.94,-2.16 0.94,-8.41v-10.62h-4.7v-13.61h27.28v48.09h-14.66l-2.16,-6.42q-2.38,4.15 -6.03,6.25 -3.6,2.05 -8.52,2.05 -5.87,0 -11.01,-2.82 -5.09,-2.88 -7.75,-7.08 -2.66,-4.21 -3.32,-8.8 -0.66,-4.65 -0.66,-13.89v-26.62q0,-12.84 1.38,-18.65 1.38,-5.81 7.91,-10.62 6.59,-4.87 16.99,-4.87 10.24,0 16.99,4.21 6.75,4.21 8.8,10.02 2.05,5.76 2.05,16.77zM388.43,150.98h38.85v17.93h-15.55v16.99h14.55v17.04h-14.55v19.7h17.1v17.93L388.43,240.57Z"
|
||||
android:strokeWidth="6.1"
|
||||
android:fillColor="#f30d0d"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="m202.17,286.98v17.93h-13.83v71.66h-23.3v-71.66h-13.78v-17.93zM261.05,286.98v89.59h-23.3v-37.63h-6.97v37.63L207.48,376.57v-89.59h23.3v32.04h6.97v-32.04zM293.69,286.98v89.59h-23.3v-89.59zM352.41,314.09L330.77,314.09v-6.64q0,-4.65 -0.83,-5.92 -0.83,-1.27 -2.77,-1.27 -2.1,0 -3.21,1.72 -1.05,1.72 -1.05,5.2 0,4.48 1.22,6.75 1.16,2.27 6.59,5.48 15.55,9.24 19.59,15.16 4.04,5.92 4.04,19.09 0,9.57 -2.27,14.11 -2.21,4.54 -8.63,7.64 -6.42,3.04 -14.94,3.04 -9.35,0 -15.99,-3.54 -6.59,-3.54 -8.63,-9.02 -2.05,-5.48 -2.05,-15.55v-5.87h21.64v10.9q0,5.04 0.89,6.47 0.94,1.44 3.26,1.44 2.32,0 3.43,-1.83 1.16,-1.83 1.16,-5.42 0,-7.91 -2.16,-10.35 -2.21,-2.43 -10.9,-8.13 -8.69,-5.76 -11.51,-8.36 -2.82,-2.6 -4.7,-7.19 -1.83,-4.59 -1.83,-11.73 0,-10.29 2.6,-15.05 2.66,-4.76 8.52,-7.42 5.87,-2.71 14.17,-2.71 9.08,0 15.44,2.93 6.42,2.93 8.47,7.42 2.1,4.43 2.1,15.11z"
|
||||
android:strokeWidth="6.1"
|
||||
android:fillColor="#f30d0d"
|
||||
android:strokeColor="#000000"/>
|
||||
</vector>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_background_color">#F5A623FF</color>
|
||||
<color name="background">#FFFFFFFF</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">NetworkedTicTacToe</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<resources>
|
||||
<style name="GdxTheme" parent="android:Theme.Material.Light.NoActionBar.Fullscreen">
|
||||
<item name="android:colorBackground">@color/background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,18 @@
|
||||
package u0012604.tictactoe.android
|
||||
|
||||
import android.os.Bundle
|
||||
|
||||
import com.badlogic.gdx.backends.android.AndroidApplication
|
||||
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration
|
||||
import u0012604.tictactoe.Main
|
||||
|
||||
/** Launches the Android application. */
|
||||
class AndroidLauncher : AndroidApplication() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
initialize(Main(), AndroidApplicationConfiguration().apply {
|
||||
// Configure your application here.
|
||||
useImmersiveMode = true // Recommended, but not required.
|
||||
})
|
||||
}
|
||||
}
|
||||
BIN
Exercises/NetworkedTicTacToe/assets/logo.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
74
Exercises/NetworkedTicTacToe/build.gradle
Normal file
@@ -0,0 +1,74 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
mavenLocal()
|
||||
google()
|
||||
maven { url = 'https://central.sonatype.com/repository/maven-snapshots/' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
|
||||
// This allows you to "Build and run using IntelliJ IDEA", an option in IDEA's Settings.
|
||||
idea {
|
||||
module {
|
||||
outputDir = file('build/classes/java/main')
|
||||
testOutputDir = file('build/classes/java/test')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure(subprojects - project(':android')) {
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
java.sourceCompatibility = 8
|
||||
|
||||
// From https://lyze.dev/2021/04/29/libGDX-Internal-Assets-List/
|
||||
// The article can be helpful when using assets.txt in your project.
|
||||
tasks.register('generateAssetList') {
|
||||
inputs.dir("${project.rootDir}/assets/")
|
||||
// projectFolder/assets
|
||||
File assetsFolder = new File("${project.rootDir}/assets/")
|
||||
// projectFolder/assets/assets.txt
|
||||
File assetsFile = new File(assetsFolder, "assets.txt")
|
||||
// delete that file in case we've already created it
|
||||
assetsFile.delete()
|
||||
|
||||
// iterate through all files inside that folder
|
||||
// convert it to a relative path
|
||||
// and append it to the file assets.txt
|
||||
fileTree(assetsFolder).collect { assetsFolder.relativePath(it) }.sort().each {
|
||||
assetsFile.append(it + "\n")
|
||||
}
|
||||
}
|
||||
processResources.dependsOn 'generateAssetList'
|
||||
|
||||
compileJava {
|
||||
options.incremental = true
|
||||
}
|
||||
compileKotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
|
||||
compileTestKotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
|
||||
|
||||
}
|
||||
|
||||
subprojects {
|
||||
version = "$projectVersion"
|
||||
ext.appName = 'NetworkedTicTacToe'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
// You may want to remove the following line if you have errors downloading dependencies.
|
||||
mavenLocal()
|
||||
maven { url = 'https://central.sonatype.com/repository/maven-snapshots/' }
|
||||
maven { url = 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
eclipse.project.name = 'NetworkedTicTacToe' + '-parent'
|
||||
43
Exercises/NetworkedTicTacToe/core/build.gradle
Normal file
@@ -0,0 +1,43 @@
|
||||
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||
eclipse.project.name = appName + '-core'
|
||||
|
||||
dependencies {
|
||||
api "com.badlogicgames.ashley:ashley:$ashleyVersion"
|
||||
api "com.badlogicgames.gdx:gdx-ai:$aiVersion"
|
||||
api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
|
||||
api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||
api "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||
api "com.kotcrab.vis:vis-ui:$visUiVersion"
|
||||
api "io.github.libktx:ktx-actors:$ktxVersion"
|
||||
api "io.github.libktx:ktx-ai:$ktxVersion"
|
||||
api "io.github.libktx:ktx-app:$ktxVersion"
|
||||
api "io.github.libktx:ktx-artemis:$ktxVersion"
|
||||
api "io.github.libktx:ktx-ashley:$ktxVersion"
|
||||
api "io.github.libktx:ktx-assets-async:$ktxVersion"
|
||||
api "io.github.libktx:ktx-assets:$ktxVersion"
|
||||
api "io.github.libktx:ktx-async:$ktxVersion"
|
||||
api "io.github.libktx:ktx-box2d:$ktxVersion"
|
||||
api "io.github.libktx:ktx-collections:$ktxVersion"
|
||||
api "io.github.libktx:ktx-freetype-async:$ktxVersion"
|
||||
api "io.github.libktx:ktx-freetype:$ktxVersion"
|
||||
api "io.github.libktx:ktx-graphics:$ktxVersion"
|
||||
api "io.github.libktx:ktx-i18n:$ktxVersion"
|
||||
api "io.github.libktx:ktx-inject:$ktxVersion"
|
||||
api "io.github.libktx:ktx-json:$ktxVersion"
|
||||
api "io.github.libktx:ktx-log:$ktxVersion"
|
||||
api "io.github.libktx:ktx-math:$ktxVersion"
|
||||
api "io.github.libktx:ktx-preferences:$ktxVersion"
|
||||
api "io.github.libktx:ktx-reflect:$ktxVersion"
|
||||
api "io.github.libktx:ktx-scene2d:$ktxVersion"
|
||||
api "io.github.libktx:ktx-style:$ktxVersion"
|
||||
api "io.github.libktx:ktx-tiled:$ktxVersion"
|
||||
api "io.github.libktx:ktx-vis-style:$ktxVersion"
|
||||
api "io.github.libktx:ktx-vis:$ktxVersion"
|
||||
api "net.onedaybeard.artemis:artemis-odb:$artemisOdbVersion"
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion"
|
||||
|
||||
if(enableGraalNative == 'true') {
|
||||
implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package u0012604.tictactoe
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.Batch
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.viewport.Viewport
|
||||
import ktx.assets.disposeSafely
|
||||
import ktx.graphics.use
|
||||
import u0012604.tictactoe.screens.FirstScreen.Companion.NOUGHT_RADIUS
|
||||
|
||||
class Board(val viewport: Viewport) : Disposable {
|
||||
private var thirdOfWidth = 0f
|
||||
private var thirdOfHeight = 0f
|
||||
|
||||
private var halfCellW = 0f
|
||||
private var halfCellH = 0f
|
||||
|
||||
private val shapeRenderer = ShapeRenderer()
|
||||
|
||||
private var boardLines = emptyArray<Pair<Vector2, Vector2>>()
|
||||
|
||||
private val board = arrayOf(
|
||||
arrayOf(Token.EMPTY, Token.EMPTY, Token.EMPTY),
|
||||
arrayOf(Token.EMPTY, Token.EMPTY, Token.EMPTY),
|
||||
arrayOf(Token.EMPTY, Token.EMPTY, Token.EMPTY)
|
||||
)
|
||||
|
||||
fun placeToken(row: Int, col: Int, token: Token) =
|
||||
if(row in (0..2) && col in (0 .. 2) && board[row][col] == Token.EMPTY) {
|
||||
board[row][col] = token
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
|
||||
fun draw(batch: Batch) {
|
||||
shapeRenderer.use(ShapeRenderer.ShapeType.Filled, viewport.camera.combined) { sr ->
|
||||
|
||||
sr.color = Color.RED
|
||||
|
||||
boardLines.forEach { line ->
|
||||
// Gdx.app.log(TAG, "p0:${line.first}, ${line.second}")
|
||||
|
||||
sr.rectLine(line.first, line.second, 10f)
|
||||
}
|
||||
|
||||
board.forEachIndexed { rowIndex, row ->
|
||||
row.forEachIndexed { colIndex, col ->
|
||||
when(col) {
|
||||
Token.NOUGHT -> drawNought(rowIndex, colIndex, sr)
|
||||
|
||||
Token.CROSS -> drawCross(rowIndex, colIndex, sr)
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resize(width: Int, height: Int) {
|
||||
boardLines = emptyArray()
|
||||
|
||||
thirdOfWidth = width / 3f
|
||||
thirdOfHeight = height / 3f
|
||||
|
||||
// Vertical lines
|
||||
val x1 = thirdOfWidth
|
||||
val x2 = Gdx.graphics.width / 1.5f
|
||||
boardLines += Pair(Vector2(x1, 0f), Vector2(x1, height.toFloat()))
|
||||
boardLines += Pair(Vector2(x2, 0f), Vector2(x2, height.toFloat()))
|
||||
|
||||
// Horizontal lines
|
||||
val y1 = thirdOfHeight
|
||||
val v2 = Gdx.graphics.height.toFloat() / 1.5f
|
||||
|
||||
boardLines += Pair(Vector2(0f, y1), Vector2(width.toFloat(), y1))
|
||||
boardLines += Pair(Vector2(0f, v2), Vector2(width.toFloat(), v2))
|
||||
|
||||
halfCellW = x1 / 2f
|
||||
halfCellH = y1 / 2f
|
||||
}
|
||||
|
||||
private fun drawNought(row: Int, col: Int, sr: ShapeRenderer) {
|
||||
val x = col * thirdOfWidth + halfCellW
|
||||
val y = (2 - row) * thirdOfHeight + halfCellH
|
||||
|
||||
sr.circle(x, y, NOUGHT_RADIUS)
|
||||
}
|
||||
|
||||
private fun drawCross(row: Int, col: Int, sr: ShapeRenderer) {
|
||||
val flipRow = 2 - row
|
||||
|
||||
val l1x1 = col * thirdOfWidth + 50f
|
||||
val l1y1 = flipRow * thirdOfHeight + 50f
|
||||
val l1x2 = col * thirdOfWidth - 50f + 2 * halfCellW
|
||||
val l1y2 = flipRow * thirdOfHeight - 50f + 2 * halfCellH
|
||||
|
||||
sr.rectLine(l1x1, l1y1, l1x2, l1y2, 10f)
|
||||
sr.rectLine(l1x1, l1y2, l1x2, l1y1, 10f)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
shapeRenderer.disposeSafely()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package u0012604.tictactoe
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
interface Serializable {
|
||||
fun serialize() : ByteArray
|
||||
}
|
||||
|
||||
interface Deserializable {
|
||||
fun deserialize(bb: ByteBuffer) : GameMessage
|
||||
}
|
||||
|
||||
enum class GameMessageType(val id: Byte) {
|
||||
JOIN_GAME(1),
|
||||
PLACE_TOKEN(2),
|
||||
START_GAME(3),
|
||||
GAME_OVER(4);
|
||||
|
||||
companion object {
|
||||
fun fromByte(id: Byte) = entries.first { it.id == id }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class GameMessage(val type: GameMessageType) : Serializable {
|
||||
|
||||
override fun serialize() = byteArrayOf(type.id)
|
||||
|
||||
object StartGameMessage : GameMessage(GameMessageType.START_GAME)
|
||||
object GameOverMessage : GameMessage(GameMessageType.GAME_OVER)
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
data class JoinGameMessage(val token: Token) : GameMessage(GameMessageType.JOIN_GAME) {
|
||||
|
||||
override fun serialize(): ByteArray = with(ByteBuffer.allocate(2)) {
|
||||
put(token.type)
|
||||
super.serialize() + array()
|
||||
}
|
||||
|
||||
companion object : Deserializable {
|
||||
|
||||
override fun deserialize(bb: ByteBuffer) = with(bb) {
|
||||
JoinGameMessage(Token.fromByte(get()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
data class PlaceTokenMessage(val row: Int, val col: Int, val token: Token) : GameMessage(GameMessageType.PLACE_TOKEN) {
|
||||
|
||||
override fun serialize(): ByteArray = with(ByteBuffer.allocate(10)) {
|
||||
putInt(row)
|
||||
putInt(col)
|
||||
put(token.type)
|
||||
super.serialize() + array()
|
||||
}
|
||||
|
||||
companion object : Deserializable {
|
||||
override fun deserialize(bb: ByteBuffer) = with(bb) {
|
||||
|
||||
val row = getInt()
|
||||
val col = getInt()
|
||||
val token = Token.fromByte(get())
|
||||
|
||||
PlaceTokenMessage(row, col, token)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package u0012604.tictactoe
|
||||
|
||||
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import ktx.app.KtxGame
|
||||
import ktx.app.KtxScreen
|
||||
import ktx.assets.disposeSafely
|
||||
import ktx.async.KtxAsync
|
||||
import u0012604.tictactoe.networking.NetworkHandler
|
||||
import u0012604.tictactoe.screens.FirstScreen
|
||||
import u0012604.tictactoe.screens.GameOverScreen
|
||||
|
||||
class Main : KtxGame<KtxScreen>() {
|
||||
|
||||
private val clientChannel = Channel<GameMessage>(10)
|
||||
private val serverChannel = Channel<GameMessage>(10)
|
||||
|
||||
private lateinit var networkHandler: NetworkHandler
|
||||
|
||||
override fun create() {
|
||||
KtxAsync.initiate()
|
||||
|
||||
networkHandler = NetworkHandler("152.105.66.120", 4331, serverChannel, clientChannel)
|
||||
|
||||
addScreen(FirstScreen(this, clientChannel, serverChannel))
|
||||
|
||||
addScreen(GameOverScreen(0))
|
||||
|
||||
setScreen<FirstScreen>()
|
||||
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
super.dispose()
|
||||
serverChannel.close()
|
||||
clientChannel.close()
|
||||
networkHandler.disposeSafely()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package u0012604.tictactoe
|
||||
|
||||
enum class Token(val type: Byte) {
|
||||
EMPTY(0), NOUGHT(1), CROSS(2);
|
||||
|
||||
companion object {
|
||||
fun fromByte(type: Byte) = Token.entries.first { it.type == type }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package u0012604.tictactoe.networking
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import u0012604.tictactoe.GameMessage
|
||||
import u0012604.tictactoe.GameMessageType
|
||||
import java.net.ConnectException
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Socket
|
||||
import java.net.SocketException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class NetworkHandler(
|
||||
private val host: String,
|
||||
private val port: Int,
|
||||
private val toServerChannel: Channel<GameMessage>, // Messages being received elsewhere in the client to send onwards to the client
|
||||
private val fromServerChannel: SendChannel<GameMessage>, // Messages being sent from the server to elsewhere within client
|
||||
private val connectionTimeout: Int = 3000,
|
||||
private val maxRetries: Int = 10
|
||||
) : Disposable
|
||||
{
|
||||
fun ByteArray.processMessage() = decodeToString().trimEnd{it == Char(0)} // Removes trailing null character
|
||||
|
||||
private val coroutineScope: CoroutineScope =
|
||||
CoroutineScope(SupervisorJob() + Dispatchers.IO).apply {
|
||||
launch {
|
||||
var retries = 0
|
||||
|
||||
while(retries < maxRetries) {
|
||||
if(startNetwork(host, port)) {
|
||||
break;
|
||||
}
|
||||
delay(retries * 500L)
|
||||
retries++
|
||||
}
|
||||
if(retries == maxRetries) {
|
||||
Gdx.app.error(TAG, "Maximum retries ($maxRetries) exceeded, giving up :(")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var socket: Socket? = null
|
||||
|
||||
val isReady: Boolean
|
||||
get() = socket?.isConnected ?: false
|
||||
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun startNetwork(
|
||||
host: String,
|
||||
port: Int
|
||||
) = try {
|
||||
var assignedClientId: UShort = 0U
|
||||
|
||||
// Create our socket
|
||||
socket = Socket()
|
||||
|
||||
// Connect with timeout set.
|
||||
socket?.let {
|
||||
val socketAddress = InetSocketAddress(host, port)
|
||||
it.connect(socketAddress, connectionTimeout)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Coroutine to handle messages
|
||||
// to be sent to the server
|
||||
// -------------------------------------------------------------
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
it.outputStream.apply {
|
||||
while (true) {
|
||||
// 1. Get the next message in the channel
|
||||
// to send onward to the server.
|
||||
val nextMessage = toServerChannel.receive()
|
||||
|
||||
// 2. Write the message to the server
|
||||
// via the socket's output stream
|
||||
write(nextMessage.serialize())
|
||||
|
||||
flush()
|
||||
|
||||
Gdx.app.log(TAG, "Sent the message $nextMessage")
|
||||
|
||||
delay(10L)
|
||||
}
|
||||
}
|
||||
} catch (ex: java.net.SocketException) {
|
||||
Gdx.app.error(TAG, "[SEND] Socket Failed: ${ex.message}")
|
||||
}
|
||||
}
|
||||
// -------------------------------------------------------------
|
||||
// Coroutine to handle messages
|
||||
// being received from the server
|
||||
//
|
||||
// Messages received are then forwarded via the
|
||||
// -------------------------------------------------------------
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
it.inputStream.apply {
|
||||
launch {
|
||||
while (true) {
|
||||
val byteArray = ByteArray(1024)
|
||||
|
||||
// delay(250L)
|
||||
|
||||
// 1. Read data from the socket's
|
||||
// input stream.
|
||||
val count = read(byteArray, 0, 1024)
|
||||
|
||||
if (count == -1) {
|
||||
Gdx.app.error(TAG, "Socket Read Error!")
|
||||
break
|
||||
}
|
||||
|
||||
val gameMessage = buildGameMessage(byteArray)
|
||||
|
||||
fromServerChannel.send(gameMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex: java.net.SocketException) {
|
||||
Gdx.app.log(TAG, "[RECEIVE] Socket Failure::[${ex.message}")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
true
|
||||
} catch (ex: java.net.SocketTimeoutException) {
|
||||
Gdx.app.error(TAG, "Timeout Exception: ${ex.message}")
|
||||
false
|
||||
} catch (ex: java.net.ConnectException) {
|
||||
Gdx.app.error(TAG, "Connection Exception: ${ex.message}")
|
||||
false
|
||||
} catch (ex: java.net.SocketException) {
|
||||
Gdx.app.error(TAG, "Exception Raised: ${ex.message}")
|
||||
false
|
||||
}
|
||||
|
||||
fun buildGameMessage(ba: ByteArray) = with(ByteBuffer.wrap(ba)) {
|
||||
val messageType = GameMessageType.fromByte(get())
|
||||
|
||||
when(messageType) {
|
||||
GameMessageType.JOIN_GAME -> GameMessage.JoinGameMessage.deserialize(this)
|
||||
|
||||
GameMessageType.PLACE_TOKEN -> GameMessage.PlaceTokenMessage.deserialize(this)
|
||||
|
||||
GameMessageType.START_GAME -> GameMessage.StartGameMessage
|
||||
|
||||
GameMessageType.GAME_OVER -> GameMessage.GameOverMessage
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
coroutineScope.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = NetworkHandler::class.simpleName!!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package u0012604.tictactoe.screens
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.InputProcessor
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.utils.viewport.FitViewport
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import ktx.app.KtxGame
|
||||
import ktx.app.KtxScreen
|
||||
import ktx.app.clearScreen
|
||||
import ktx.assets.disposeSafely
|
||||
import ktx.graphics.use
|
||||
import u0012604.tictactoe.Board
|
||||
import u0012604.tictactoe.GameMessage
|
||||
import u0012604.tictactoe.Token
|
||||
|
||||
class FirstScreen(
|
||||
val game: KtxGame<KtxScreen>,
|
||||
private val receiveChannel: ReceiveChannel<GameMessage>,
|
||||
private val sendChannel: SendChannel<GameMessage>
|
||||
) : KtxScreen, InputProcessor {
|
||||
private var gameStarted = false
|
||||
|
||||
private var gameOver = false
|
||||
|
||||
private val batch = SpriteBatch()
|
||||
|
||||
|
||||
private val camera =
|
||||
OrthographicCamera(WIDTH, HEIGHT).apply {
|
||||
position.set(Gdx.graphics.width / 2f, Gdx.graphics.height / 2f, 0f)
|
||||
};
|
||||
private val viewport = FitViewport(Gdx.graphics.width.toFloat(), Gdx.graphics.height.toFloat(), camera)
|
||||
|
||||
private val board = Board(viewport)
|
||||
|
||||
private var touchPosition = Vector2.Zero
|
||||
|
||||
private var localPlayerToken: Token? = null
|
||||
|
||||
private var localPlayerTurn = false
|
||||
|
||||
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
init {
|
||||
Gdx.input.inputProcessor = this
|
||||
|
||||
initiateIncomingGameMessageHandling()
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
clearScreen(red = 0.7f, green = 0.7f, blue = 0.7f)
|
||||
|
||||
if (gameOver) {
|
||||
game.setScreen<GameOverScreen>()
|
||||
disposeSafely()
|
||||
return
|
||||
}
|
||||
|
||||
camera.update()
|
||||
|
||||
batch.use { board.draw(it) }
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
viewport.update(width, height)
|
||||
|
||||
board.resize(width, height)
|
||||
}
|
||||
|
||||
private fun initiateIncomingGameMessageHandling() {
|
||||
coroutineScope.launch {
|
||||
while(true) {
|
||||
val gm = receiveChannel.receive()
|
||||
|
||||
when(gm) {
|
||||
is GameMessage.JoinGameMessage -> {
|
||||
localPlayerToken = gm.token
|
||||
|
||||
localPlayerTurn = localPlayerToken == Token.NOUGHT
|
||||
}
|
||||
|
||||
is GameMessage.PlaceTokenMessage -> {
|
||||
Gdx.app.log(TAG, "The other player placed a token at: (${gm.row}, ${gm.col})")
|
||||
|
||||
board.placeToken(gm.row, gm.col, gm.token)
|
||||
|
||||
localPlayerTurn = true
|
||||
}
|
||||
|
||||
is GameMessage.StartGameMessage -> {
|
||||
Gdx.app.log(TAG, "The Server has started the game")
|
||||
|
||||
gameStarted = true
|
||||
}
|
||||
|
||||
is GameMessage.GameOverMessage -> {
|
||||
Gdx.app.log(TAG, "The Server has sent Game Over")
|
||||
|
||||
gameStarted = false
|
||||
gameOver = true
|
||||
}
|
||||
}
|
||||
|
||||
Gdx.app.log(TAG, "THE MESSAGE RECEIVED IS: $gm")
|
||||
|
||||
delay(10L)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
batch.disposeSafely()
|
||||
board.disposeSafely()
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int) = true
|
||||
|
||||
override fun keyUp(keycode: Int) = true
|
||||
|
||||
override fun keyTyped(character: Char) = true
|
||||
|
||||
override fun touchDown(
|
||||
screenX: Int,
|
||||
screenY: Int,
|
||||
pointer: Int,
|
||||
button: Int
|
||||
): Boolean {
|
||||
|
||||
if(!gameStarted || !localPlayerTurn)
|
||||
return true;
|
||||
|
||||
val col = ((screenX.toFloat() / Gdx.graphics.width) * 3).toInt()
|
||||
val row = ((screenY.toFloat() / Gdx.graphics.height) * 3).toInt()
|
||||
|
||||
localPlayerToken?.let {
|
||||
if (board.placeToken(row, col, it)) {
|
||||
|
||||
localPlayerTurn = false
|
||||
|
||||
val gameMessage = GameMessage.PlaceTokenMessage(row, col, it)
|
||||
|
||||
coroutineScope.launch {
|
||||
sendChannel.send(gameMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Gdx.app.log(TAG, "THE ROW IS: ($row, $col)")
|
||||
|
||||
touchPosition.set(screenX.toFloat(), screenY.toFloat())
|
||||
|
||||
viewport.unproject(touchPosition)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchUp(
|
||||
screenX: Int,
|
||||
screenY: Int,
|
||||
pointer: Int,
|
||||
button: Int
|
||||
) = true
|
||||
|
||||
override fun touchCancelled(
|
||||
screenX: Int,
|
||||
screenY: Int,
|
||||
pointer: Int,
|
||||
button: Int
|
||||
) = true
|
||||
|
||||
override fun touchDragged(
|
||||
screenX: Int,
|
||||
screenY: Int,
|
||||
pointer: Int
|
||||
) = true
|
||||
|
||||
override fun mouseMoved(screenX: Int, screenY: Int) = true
|
||||
|
||||
override fun scrolled(amountX: Float, amountY: Float) = true
|
||||
|
||||
companion object {
|
||||
val TAG = FirstScreen::class.simpleName!!
|
||||
|
||||
const val WIDTH = 100f
|
||||
const val HEIGHT = 16f * WIDTH / 9f
|
||||
|
||||
const val NOUGHT_RADIUS = 100f
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package u0012604.tictactoe.screens
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import ktx.app.KtxScreen
|
||||
import ktx.app.clearScreen
|
||||
import ktx.graphics.use
|
||||
|
||||
class GameOverScreen(private val winType: Int) : KtxScreen {
|
||||
private var label = winType.toString()
|
||||
private val font = BitmapFont()
|
||||
private val batch = SpriteBatch()
|
||||
|
||||
override fun show() {
|
||||
when (winType) {
|
||||
0 -> label = "You Win!"
|
||||
1 -> label = "You Lose."
|
||||
2 -> label = "Game Over!"
|
||||
else -> "Invalid type!"
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
clearScreen(red = 0.7f, green = 0.7f, blue = 0.7f)
|
||||
|
||||
batch.use {
|
||||
font.draw(it, label, 10f, 10f)
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Exercises/NetworkedTicTacToe/gradle.properties
Normal file
@@ -0,0 +1,28 @@
|
||||
# This doesn't need to be false, and some projects may be able to take advantage of setting daemon to true.
|
||||
# We set it to false by default in order to avoid too many daemons from being created and persisting; each needs RAM.
|
||||
org.gradle.daemon=false
|
||||
# Sets starting memory usage to 512MB, maximum memory usage to 1GB, and tries to set as much to use Unicode as we can.
|
||||
org.gradle.jvmargs=-Xms512M -Xmx1G -Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8
|
||||
# "Configure on-demand" must be false because it breaks projects that have Android modules. The default is also false.
|
||||
org.gradle.configureondemand=false
|
||||
# The logging level determines which messages get shown about how Gradle itself is working, such as if build.gradle
|
||||
# files are fully future-proof (which they never are, because Gradle constantly deprecates working APIs).
|
||||
# You can change 'quiet' below to 'lifecycle' to use Gradle's default behavior, which shows some confusing messages.
|
||||
# You could instead change 'quiet' below to 'info' to see info that's important mainly while debugging build files.
|
||||
# Note that if you want to use Gradle Build Scans, you should set the below logging level to 'lifecycle', otherwise
|
||||
# the link to the scan won't get shown at all.
|
||||
# Documented at: https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_logging
|
||||
org.gradle.logging.level=quiet
|
||||
ktxVersion=1.13.1-rc1
|
||||
kotlinVersion=2.2.21
|
||||
kotlinxCoroutinesVersion=1.8.1
|
||||
aiVersion=1.8.2
|
||||
artemisOdbVersion=2.3.0
|
||||
ashleyVersion=1.7.4
|
||||
visUiVersion=1.5.7
|
||||
android.useAndroidX=true
|
||||
android.enableR8.fullMode=false
|
||||
enableGraalNative=false
|
||||
graalHelperVersion=2.0.1
|
||||
gdxVersion=1.14.0
|
||||
projectVersion=1.0.0
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73c462e34475aeb6509ab7ba3eda218f/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/54001d0b636ad500b432d20ef3d580d0/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73c462e34475aeb6509ab7ba3eda218f/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/54001d0b636ad500b432d20ef3d580d0/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29c55e6bad8a0049163f0184625cecd9/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/3ac7a5361c25c0b23d933f44bdb0abd9/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73c462e34475aeb6509ab7ba3eda218f/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/54001d0b636ad500b432d20ef3d580d0/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/28937bb8a7f83f57de92429a9a11c04e/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/52fa104f4f641439587f75dd68b31bc2/redirect
|
||||
toolchainVersion=17
|
||||
BIN
Exercises/NetworkedTicTacToe/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
7
Exercises/NetworkedTicTacToe/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-milestone-1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
251
Exercises/NetworkedTicTacToe/gradlew
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
94
Exercises/NetworkedTicTacToe/gradlew.bat
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
185
Exercises/NetworkedTicTacToe/lwjgl3/build.gradle
Normal file
@@ -0,0 +1,185 @@
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
dependencies {
|
||||
classpath "io.github.fourlastor:construo:2.1.0"
|
||||
if(enableGraalNative == 'true') {
|
||||
classpath "org.graalvm.buildtools.native:org.graalvm.buildtools.native.gradle.plugin:0.9.28"
|
||||
}
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id "application"
|
||||
}
|
||||
apply plugin: 'io.github.fourlastor.construo'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
|
||||
|
||||
import io.github.fourlastor.construo.Target
|
||||
|
||||
sourceSets.main.resources.srcDirs += [ rootProject.file('assets').path ]
|
||||
application.mainClass = 'u0012604.tictactoe.lwjgl3.Lwjgl3Launcher'
|
||||
eclipse.project.name = appName + '-lwjgl3'
|
||||
java.sourceCompatibility = 8
|
||||
java.targetCompatibility = 8
|
||||
if (JavaVersion.current().isJava9Compatible()) {
|
||||
compileJava.options.release.set(8)
|
||||
}
|
||||
kotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
|
||||
|
||||
dependencies {
|
||||
implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
|
||||
implementation "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop"
|
||||
implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
|
||||
implementation "com.badlogicgames.gdx:gdx-lwjgl3-angle:$gdxVersion"
|
||||
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
|
||||
implementation project(':core')
|
||||
|
||||
if(enableGraalNative == 'true') {
|
||||
implementation "io.github.berstanio:gdx-svmhelper-backend-lwjgl3:$graalHelperVersion"
|
||||
implementation "io.github.berstanio:gdx-svmhelper-extension-freetype:$graalHelperVersion"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def os = System.properties['os.name'].toLowerCase(Locale.ROOT)
|
||||
|
||||
run {
|
||||
workingDir = rootProject.file('assets').path
|
||||
// You can uncomment the next line if your IDE claims a build failure even when the app closed properly.
|
||||
//setIgnoreExitValue(true)
|
||||
|
||||
if (os.contains('mac')) jvmArgs += "-XstartOnFirstThread"
|
||||
}
|
||||
|
||||
jar {
|
||||
// sets the name of the .jar file this produces to the name of the game or app, with the version after.
|
||||
archiveFileName.set("${appName}-${projectVersion}.jar")
|
||||
// the duplicatesStrategy matters starting in Gradle 7.0; this setting works.
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
dependsOn configurations.runtimeClasspath
|
||||
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||
// these "exclude" lines remove some unnecessary duplicate files in the output JAR.
|
||||
exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA')
|
||||
dependencies {
|
||||
exclude('META-INF/INDEX.LIST', 'META-INF/maven/**')
|
||||
}
|
||||
// setting the manifest makes the JAR runnable.
|
||||
// enabling native access helps avoid a warning when Java 24 or later runs the JAR.
|
||||
manifest {
|
||||
attributes 'Main-Class': application.mainClass, 'Enable-Native-Access': 'ALL-UNNAMED'
|
||||
}
|
||||
// this last step may help on some OSes that need extra instruction to make runnable JARs.
|
||||
doLast {
|
||||
file(archiveFile).setExecutable(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a JAR that only includes the files needed to run on macOS, not Windows or Linux.
|
||||
// The file size for a Mac-only JAR is about 7MB smaller than a cross-platform JAR.
|
||||
tasks.register("jarMac") {
|
||||
dependsOn("jar")
|
||||
group("build")
|
||||
jar.archiveFileName.set("${appName}-${projectVersion}-mac.jar")
|
||||
jar.exclude("windows/x86/**", "windows/x64/**", "linux/arm32/**", "linux/arm64/**", "linux/x64/**", "**/*.dll", "**/*.so",
|
||||
'META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA')
|
||||
dependencies {
|
||||
jar.exclude("windows/x86/**", "windows/x64/**", "linux/arm32/**", "linux/arm64/**", "linux/x64/**",
|
||||
'META-INF/INDEX.LIST', 'META-INF/maven/**')
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a JAR that only includes the files needed to run on Linux, not Windows or macOS.
|
||||
// The file size for a Linux-only JAR is about 5MB smaller than a cross-platform JAR.
|
||||
tasks.register("jarLinux") {
|
||||
dependsOn("jar")
|
||||
group("build")
|
||||
jar.archiveFileName.set("${appName}-${projectVersion}-linux.jar")
|
||||
jar.exclude("windows/x86/**", "windows/x64/**", "macos/arm64/**", "macos/x64/**", "**/*.dll", "**/*.dylib",
|
||||
'META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA')
|
||||
dependencies {
|
||||
jar.exclude("windows/x86/**", "windows/x64/**", "macos/arm64/**", "macos/x64/**",
|
||||
'META-INF/INDEX.LIST', 'META-INF/maven/**')
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a JAR that only includes the files needed to run on Windows, not Linux or macOS.
|
||||
// The file size for a Windows-only JAR is about 6MB smaller than a cross-platform JAR.
|
||||
tasks.register("jarWin") {
|
||||
dependsOn("jar")
|
||||
group("build")
|
||||
jar.archiveFileName.set("${appName}-${projectVersion}-win.jar")
|
||||
jar.exclude("macos/arm64/**", "macos/x64/**", "linux/arm32/**", "linux/arm64/**", "linux/x64/**", "**/*.dylib", "**/*.so",
|
||||
'META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA')
|
||||
dependencies {
|
||||
jar.exclude("macos/arm64/**", "macos/x64/**", "linux/arm32/**", "linux/arm64/**", "linux/x64/**",
|
||||
'META-INF/INDEX.LIST', 'META-INF/maven/**')
|
||||
}
|
||||
}
|
||||
|
||||
construo {
|
||||
// name of the executable
|
||||
name.set(appName)
|
||||
// human-readable name, used for example in the `.app` name for macOS
|
||||
humanName.set(appName)
|
||||
|
||||
targets.configure {
|
||||
register("linuxX64", Target.Linux) {
|
||||
architecture.set(Target.Architecture.X86_64)
|
||||
jdkUrl.set("https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_x64_linux_hotspot_17.0.15_6.tar.gz")
|
||||
// Linux does not currently have a way to set the icon on the executable
|
||||
}
|
||||
register("macM1", Target.MacOs) {
|
||||
architecture.set(Target.Architecture.AARCH64)
|
||||
jdkUrl.set("https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.15_6.tar.gz")
|
||||
// macOS needs an identifier
|
||||
identifier.set("u0012604.tictactoe." + appName)
|
||||
// Optional: icon for macOS, as an ICNS file
|
||||
macIcon.set(project.file("icons/logo.icns"))
|
||||
}
|
||||
register("macX64", Target.MacOs) {
|
||||
architecture.set(Target.Architecture.X86_64)
|
||||
jdkUrl.set("https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_x64_mac_hotspot_17.0.15_6.tar.gz")
|
||||
// macOS needs an identifier
|
||||
identifier.set("u0012604.tictactoe." + appName)
|
||||
// Optional: icon for macOS, as an ICNS file
|
||||
macIcon.set(project.file("icons/logo.icns"))
|
||||
}
|
||||
register("winX64", Target.Windows) {
|
||||
architecture.set(Target.Architecture.X86_64)
|
||||
// Optional: icon for Windows, as a PNG
|
||||
icon.set(project.file("icons/logo.png"))
|
||||
jdkUrl.set("https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_x64_windows_hotspot_17.0.15_6.zip")
|
||||
// Uncomment the next line to show a console when the game runs, to print messages.
|
||||
//useConsole.set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent to the jar task; here for compatibility with gdx-setup.
|
||||
tasks.register('dist') {
|
||||
dependsOn 'jar'
|
||||
}
|
||||
|
||||
distributions {
|
||||
main {
|
||||
contents {
|
||||
into('libs') {
|
||||
project.configurations.runtimeClasspath.files.findAll { file ->
|
||||
file.getName() != project.tasks.jar.outputs.files.singleFile.name
|
||||
}.each { file ->
|
||||
exclude file.name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startScripts.dependsOn(':lwjgl3:jar')
|
||||
startScripts.classpath = project.tasks.jar.outputs.files
|
||||
|
||||
if(enableGraalNative == 'true') {
|
||||
apply from: file("nativeimage.gradle")
|
||||
}
|
||||
BIN
Exercises/NetworkedTicTacToe/lwjgl3/icons/logo.icns
Normal file
BIN
Exercises/NetworkedTicTacToe/lwjgl3/icons/logo.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
Exercises/NetworkedTicTacToe/lwjgl3/icons/logo.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
54
Exercises/NetworkedTicTacToe/lwjgl3/nativeimage.gradle
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
project(":lwjgl3") {
|
||||
apply plugin: "org.graalvm.buildtools.native"
|
||||
|
||||
graalvmNative {
|
||||
binaries {
|
||||
main {
|
||||
imageName = appName
|
||||
mainClass = application.mainClass
|
||||
requiredVersion = '23.0'
|
||||
buildArgs.add("-march=compatibility")
|
||||
jvmArgs.addAll("-Dfile.encoding=UTF8")
|
||||
sharedLibrary = false
|
||||
resources.autodetect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run {
|
||||
doNotTrackState("Running the app should not be affected by Graal.")
|
||||
}
|
||||
|
||||
// Modified from https://lyze.dev/2021/04/29/libGDX-Internal-Assets-List/ ; thanks again, Lyze!
|
||||
// This creates a resource-config.json file based on the contents of the assets folder (and the libGDX icons).
|
||||
// This file is used by Graal Native to embed those specific files.
|
||||
// This has to run before nativeCompile, so it runs at the start of an unrelated resource-handling command.
|
||||
generateResourcesConfigFile.doFirst {
|
||||
def assetsFolder = new File("${project.rootDir}/assets/")
|
||||
def lwjgl3 = project(':lwjgl3')
|
||||
def resFolder = new File("${lwjgl3.projectDir}/src/main/resources/META-INF/native-image/${lwjgl3.ext.appName}")
|
||||
resFolder.mkdirs()
|
||||
def resFile = new File(resFolder, "resource-config.json")
|
||||
resFile.delete()
|
||||
resFile.append(
|
||||
"""{
|
||||
"resources":{
|
||||
"includes":[
|
||||
{
|
||||
"pattern": ".*(""")
|
||||
// This adds every filename in the assets/ folder to a pattern that adds those files as resources.
|
||||
fileTree(assetsFolder).each {
|
||||
// The backslash-Q and backslash-E escape the start and end of a literal string, respectively.
|
||||
resFile.append("\\\\Q${it.name}\\\\E|")
|
||||
}
|
||||
// We also match all of the window icon images this way and the font files that are part of libGDX.
|
||||
resFile.append(
|
||||
"""libgdx.+\\\\.png|lsans.+)"
|
||||
}
|
||||
]},
|
||||
"bundles":[]
|
||||
}"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
@file:JvmName("Lwjgl3Launcher")
|
||||
|
||||
package u0012604.tictactoe.lwjgl3
|
||||
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import u0012604.tictactoe.Main
|
||||
|
||||
/** Launches the desktop (LWJGL3) application. */
|
||||
fun main() {
|
||||
// This handles macOS support and helps on Windows.
|
||||
if (StartupHelper.startNewJvmIfRequired())
|
||||
return
|
||||
Lwjgl3Application(Main(), Lwjgl3ApplicationConfiguration().apply {
|
||||
setTitle("NetworkedTicTacToe")
|
||||
//// Vsync limits the frames per second to what your hardware can display, and helps eliminate
|
||||
//// screen tearing. This setting doesn't always work on Linux, so the line after is a safeguard.
|
||||
useVsync(true)
|
||||
//// Limits FPS to the refresh rate of the currently active monitor, plus 1 to try to match fractional
|
||||
//// refresh rates. The Vsync setting above should limit the actual FPS to match the monitor.
|
||||
setForegroundFPS(Lwjgl3ApplicationConfiguration.getDisplayMode().refreshRate + 1)
|
||||
//// If you remove the above line and set Vsync to false, you can get unlimited FPS, which can be
|
||||
//// useful for testing performance, but can also be very stressful to some hardware.
|
||||
//// You may also need to configure GPU drivers to fully disable Vsync; this can cause screen tearing.
|
||||
|
||||
|
||||
setWindowedMode(640, 480)
|
||||
//// You can change these files; they are in lwjgl3/src/main/resources/ .
|
||||
//// They can also be loaded from the root of assets/ .
|
||||
setWindowIcon(*(arrayOf(128, 64, 32, 16).map { "libgdx$it.png" }.toTypedArray()))
|
||||
|
||||
//// This should improve compatibility with Windows machines with buggy OpenGL drivers, Macs
|
||||
//// with Apple Silicon that have to emulate compatibility with OpenGL anyway, and more.
|
||||
//// This uses the dependency `com.badlogicgames.gdx:gdx-lwjgl3-angle` to function.
|
||||
//// You can choose to remove the following line and the mentioned dependency if you want; they
|
||||
//// are not intended for games that use GL30 (which is compatibility with OpenGL ES 3.0).
|
||||
setOpenGLEmulation(Lwjgl3ApplicationConfiguration.GLEmulation.ANGLE_GLES20, 0, 0)
|
||||
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
|
||||
/*
|
||||
* Copyright 2020 damios
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//Note, the above license and copyright applies to this file only.
|
||||
package u0012604.tictactoe.lwjgl3
|
||||
|
||||
import com.badlogic.gdx.Version
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3NativesLoader
|
||||
import org.lwjgl.system.JNI
|
||||
import org.lwjgl.system.macosx.LibC
|
||||
import org.lwjgl.system.macosx.ObjCRuntime
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Adds some utilities to ensure that the JVM was started with the
|
||||
* `-XstartOnFirstThread` argument, which is required on macOS for LWJGL 3
|
||||
* to function. Also helps on Windows when users have names with characters from
|
||||
* outside the Latin alphabet, a common cause of startup crashes.
|
||||
*
|
||||
* [Based on this java-gaming.org post by kappa](https://jvm-gaming.org/t/starting-jvm-on-mac-with-xstartonfirstthread-programmatically/57547)
|
||||
* @author damios
|
||||
*/
|
||||
class StartupHelper private constructor() {
|
||||
init {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val JVM_RESTARTED_ARG = "jvmIsRestarted"
|
||||
/**
|
||||
* Starts a new JVM if the application was started on macOS without the
|
||||
* `-XstartOnFirstThread` argument. This also includes some code for
|
||||
* Windows, for the case where the user's home directory includes certain
|
||||
* non-Latin-alphabet characters (without this code, most LWJGL3 apps fail
|
||||
* immediately for those users). Returns whether a new JVM was started and
|
||||
* thus no code should be executed.
|
||||
*
|
||||
* **Usage:**
|
||||
*
|
||||
* ```
|
||||
* fun main() {
|
||||
* if (StartupHelper.startNewJvmIfRequired(true)) return // This handles macOS support and helps on Windows.
|
||||
* // after this is the actual main method code
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param redirectOutput
|
||||
* whether the output of the new JVM should be rerouted to the
|
||||
* old JVM, so it can be accessed in the same place; keeps the
|
||||
* old JVM running if enabled
|
||||
* @return whether a new JVM was started and thus no code should be executed
|
||||
* in this one
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun startNewJvmIfRequired(redirectOutput: Boolean = true): Boolean {
|
||||
val osName = System.getProperty("os.name").lowercase(Locale.ROOT)
|
||||
if (!osName.contains("mac")) {
|
||||
if (osName.contains("windows")) {
|
||||
// Here, we are trying to work around an issue with how LWJGL3 loads its extracted .dll files.
|
||||
// By default, LWJGL3 extracts to the directory specified by "java.io.tmpdir", which is usually the user's home.
|
||||
// If the user's name has non-ASCII (or some non-alphanumeric) characters in it, that would fail.
|
||||
// By extracting to the relevant "ProgramData" folder, which is usually "C:\ProgramData", we avoid this.
|
||||
// We also temporarily change the "user.name" property to one without any chars that would be invalid.
|
||||
// We revert our changes immediately after loading LWJGL3 natives.
|
||||
val programData = System.getenv("ProgramData") ?: "C:\\Temp\\"
|
||||
val prevTmpDir = System.getProperty("java.io.tmpdir", programData)
|
||||
val prevUser = System.getProperty("user.name", "libGDX_User")
|
||||
System.setProperty("java.io.tmpdir", "$programData/libGDX-temp")
|
||||
System.setProperty("user.name", "User_${prevUser.hashCode()}_GDX${Version.VERSION}".replace('.', '_'))
|
||||
Lwjgl3NativesLoader.load()
|
||||
System.setProperty("java.io.tmpdir", prevTmpDir)
|
||||
System.setProperty("user.name", prevUser)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// There is no need for -XstartOnFirstThread on Graal native image
|
||||
if (System.getProperty("org.graalvm.nativeimage.imagecode", "").isNotEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Checks if we are already on the main thread, such as from running via Construo.
|
||||
val objcMsgSend = ObjCRuntime.getLibrary().getFunctionAddress("objc_msgSend")
|
||||
val nsThread = ObjCRuntime.objc_getClass("NSThread")
|
||||
val currentThread = JNI.invokePPP(nsThread, ObjCRuntime.sel_getUid("currentThread"), objcMsgSend)
|
||||
val isMainThread = JNI.invokePPZ(currentThread, ObjCRuntime.sel_getUid("isMainThread"), objcMsgSend)
|
||||
if (isMainThread) return false
|
||||
|
||||
val pid = LibC.getpid()
|
||||
|
||||
// check whether -XstartOnFirstThread is enabled
|
||||
if ("1" == System.getenv("JAVA_STARTED_ON_FIRST_THREAD_$pid")) {
|
||||
return false
|
||||
}
|
||||
|
||||
// check whether the JVM was previously restarted
|
||||
// avoids looping, but most certainly leads to a crash
|
||||
if ("true" == System.getProperty(JVM_RESTARTED_ARG)) {
|
||||
System.err.println(
|
||||
"There was a problem evaluating whether the JVM was started with the -XstartOnFirstThread argument."
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
// Restart the JVM with -XstartOnFirstThread
|
||||
val jvmArgs = ArrayList<String?>()
|
||||
val separator = System.getProperty("file.separator", "/")
|
||||
// The following line is used assuming you target Java 8, the minimum for LWJGL3.
|
||||
val javaExecPath = System.getProperty("java.home") + separator + "bin" + separator + "java"
|
||||
// If targeting Java 9 or higher, you could use the following instead of the above line:
|
||||
//String javaExecPath = ProcessHandle.current().info().command().orElseThrow();
|
||||
if (!File(javaExecPath).exists()) {
|
||||
System.err.println(
|
||||
"A Java installation could not be found. If you are distributing this app with a bundled JRE, be sure to set the -XstartOnFirstThread argument manually!"
|
||||
)
|
||||
return false
|
||||
}
|
||||
jvmArgs.add(javaExecPath)
|
||||
jvmArgs.add("-XstartOnFirstThread")
|
||||
jvmArgs.add("-D$JVM_RESTARTED_ARG=true")
|
||||
jvmArgs.addAll(ManagementFactory.getRuntimeMXBean().inputArguments)
|
||||
jvmArgs.add("-cp")
|
||||
jvmArgs.add(System.getProperty("java.class.path"))
|
||||
var mainClass = System.getenv("JAVA_MAIN_CLASS_$pid")
|
||||
if (mainClass == null) {
|
||||
val trace = Thread.currentThread().stackTrace
|
||||
mainClass = if (trace.isNotEmpty()) {
|
||||
trace[trace.size - 1].className
|
||||
} else {
|
||||
System.err.println("The main class could not be determined.")
|
||||
return false
|
||||
}
|
||||
}
|
||||
jvmArgs.add(mainClass)
|
||||
try {
|
||||
if (!redirectOutput) {
|
||||
val processBuilder = ProcessBuilder(jvmArgs)
|
||||
processBuilder.start()
|
||||
} else {
|
||||
val process = ProcessBuilder(jvmArgs)
|
||||
.redirectErrorStream(true).start()
|
||||
val processOutput = BufferedReader(
|
||||
InputStreamReader(process.inputStream)
|
||||
)
|
||||
var line: String?
|
||||
while (processOutput.readLine().also { line = it } != null) {
|
||||
println(line)
|
||||
}
|
||||
process.waitFor()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
System.err.println("There was a problem restarting the JVM")
|
||||
e.printStackTrace()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 806 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
8
Exercises/NetworkedTicTacToe/settings.gradle
Normal file
@@ -0,0 +1,8 @@
|
||||
plugins {
|
||||
// Applies the foojay-resolver plugin to allow automatic download of JDKs.
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
}
|
||||
// A list of which subprojects to load as part of the same larger project.
|
||||
// You can remove Strings from the list and reload the Gradle project
|
||||
// if you want to temporarily disable a subproject.
|
||||
include 'android', 'core', 'lwjgl3'
|
||||
56
Formative Assessment/Formative Assessment.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# The Witch Queen
|
||||
### Outline
|
||||
1. [[Formative Assessment#Gameplay|Gameplay]]
|
||||
1. [[Formative Assessment#Co-Op|Co-Op]]
|
||||
2. [[Formative Assessment#Competitive|Competitive]]
|
||||
3. [[Formative Assessment#Combat|Combat]]
|
||||
4. [[Formative Assessment#The Witch|The Witch]]
|
||||
2. [[Formative Assessment#Art|Art]]
|
||||
3. [[Formative Assessment#Required Resources|Required Resources]]
|
||||
4. [[Formative Assessment#Rough Plan|Rough Plan]]
|
||||
### Gameplay
|
||||
The game will be played with the phone held vertically. The game will be a roguelite with a both a cooperative and a competitive game mode.
|
||||
|
||||
Players must enter a dungeon with another player in order to kill The Witch. They may enter with some prepared items in Co-op, but will be going in without in the competitive game mode.
|
||||
|
||||
Upon entering a room, the player will be given some options. If there are enemies, they will be given the option to fight them. They will be given the option to search clutter if it exists within the room. Any chests can be looted with additional chests maybe reviled behind clutter. All of these activities can reward equipment that can be used in future fights/games.
|
||||
|
||||
After the player determines they have sufficiently cleared the room they can pick adjacent rooms. Players can end up meeting each other if they end up picking the same room. Players may group up and take rooms together. In co-op this will result in the loot being split. In competitive this will result in the person who initiated the action, if it was searching clutter or looting a chest, or dealt the final blow (maybe dice roll instead) in a combat encounter.
|
||||
##### Co-Op
|
||||
Players will be allowed to bring prepared items, such as potions, and must work with their partner to scour the dungeon in order to get powerful enough to kill The Witch. Some collected loot can be taken back and used in future runs if the players were not able to finish a run completely.
|
||||
|
||||
Players may be resurrected at certain interactable that may spawn randomly in rooms.
|
||||
##### Competitive
|
||||
Players must be quick but careful when doing a competitive run. The first person to kill The Witch wins.
|
||||
|
||||
Once a player is dead they are removed from the game. The final player can make it to the end and kill The Witch for a greater reward.
|
||||
##### Combat
|
||||
Upon entering a combat encounter the options available to the Player will change to reflect the actions they can take. They will be given the option to flee. This will take them to an adjacent room with all unclaimed loot in the previous room now locked to them (not chance based). Players will also have the option to attack with a certain action. If the enemy is shielded, the Player can use a shield-break attack. If the enemy is weak to fire they may use a fire attack if they have one etc. Attack options will depend on the players equipment.
|
||||
##### The Witch
|
||||
The Witch is the ultimate fight in a run. They will test the Player's breadth of held equipment. If the Player(s) do not have the equipment capable of taking down The Witch they will find the fight very difficult.
|
||||
|
||||
Players will be allowed to run and keep all the collected equipment should they manage to escape (Chance based?).
|
||||
|
||||
See [[Idea Whiteboard]] for more details. A [[Idea Whiteboard.png|PNG version]] and an [[Idea Whiteboard.svg|SVG version]] are also available.
|
||||
### Art
|
||||
These packs are along the lines of what I envision the game should look like:
|
||||
- [2D Pixel Dungeon Asset Pack by Pixel_Poem](https://pixel-poem.itch.io/dungeon-assetpuck)
|
||||
- [16x16 DungeonTileset II by 0x72](https://0x72.itch.io/dungeontileset-ii)
|
||||
- [Rogue Fantasy Catacombs by Szadi art.](https://szadiart.itch.io/rogue-fantasy-catacombs)
|
||||
I had imagined the game be isometric, but these packs will suffice.
|
||||
### Required Resources
|
||||
These resources may be useful:
|
||||
- [Procedural Dungeon Generation in Kotlin / LibGDX](https://www.youtube.com/watch?v=gEr5fbORuLM)
|
||||
- [Quillraven - YouTube](https://www.youtube.com/@Quillraven/videos) has more videos on Kotlin/LibGDX which may also be useful
|
||||
- [Kotlin | The Cogitator](https://the-cogitator.com/tags/kotlin/) has some articles on creating a roguelike in Kotlin
|
||||
### Rough Plan
|
||||
- Fights - 16 Hours
|
||||
- Equipment - 8 Hours
|
||||
- Room Generation - 12 Hours
|
||||
- Movement - 8 Hours
|
||||
- Collectables - 8 Hours
|
||||
- The Witch - 8 Hours
|
||||
- Multiplayer Implementation - 16 Hours
|
||||
- Permanent Progression (Prepared Equipment) - 8 Hours
|
||||
- Play Menu - 8 Hours
|
||||
- Equipment Menu - 8 Hours
|
||||
4190
Formative Assessment/Idea Whiteboard.md
Normal file
BIN
Formative Assessment/Idea Whiteboard.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
2
Formative Assessment/Idea Whiteboard.svg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
18
WitchQueen/.editorconfig
Normal file
@@ -0,0 +1,18 @@
|
||||
# https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{java,scala,groovy,kt,kts}]
|
||||
indent_size = 4
|
||||
|
||||
[*.gradle]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
WitchQueen/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
* text=auto eol=lf
|
||||
*.bat text=auto eol=crlf
|
||||
164
WitchQueen/.gitignore
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
## Gradle:
|
||||
.gradle/
|
||||
gradle-app.setting
|
||||
/build/
|
||||
/android/build/
|
||||
/core/build/
|
||||
/lwjgl2/build/
|
||||
/lwjgl3/build/
|
||||
/html/build/
|
||||
/teavm/build/
|
||||
/ios/build/
|
||||
/ios-moe/build/
|
||||
/headless/build/
|
||||
/server/build/
|
||||
/shared/build/
|
||||
|
||||
## Java:
|
||||
*.class
|
||||
*.war
|
||||
*.ear
|
||||
hs_err_pid*
|
||||
.attach_pid*
|
||||
|
||||
## Android:
|
||||
/android/libs/armeabi-v7a/
|
||||
/android/libs/arm64-v8a/
|
||||
/android/libs/x86/
|
||||
/android/libs/x86_64/
|
||||
/android/gen/
|
||||
/android/out/
|
||||
local.properties
|
||||
com_crashlytics_export_strings.xml
|
||||
|
||||
## Robovm:
|
||||
/ios/robovm-build/
|
||||
|
||||
## iOS:
|
||||
/ios/xcode/*.xcodeproj/*
|
||||
!/ios/xcode/*.xcodeproj/xcshareddata
|
||||
!/ios/xcode/*.xcodeproj/project.pbxproj
|
||||
/ios/xcode/native/
|
||||
/ios/IOSLauncher.app
|
||||
/ios/IOSLauncher.app.dSYM
|
||||
|
||||
## GWT:
|
||||
/html/war/
|
||||
/html/gwt-unitCache/
|
||||
.apt_generated/
|
||||
/html/war/WEB-INF/deploy/
|
||||
/html/war/WEB-INF/classes/
|
||||
.gwt/
|
||||
gwt-unitCache/
|
||||
www-test/
|
||||
.gwt-tmp/
|
||||
|
||||
## TeaVM:
|
||||
# Not sure yet...
|
||||
|
||||
## IntelliJ, Android Studio:
|
||||
.idea/
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
|
||||
## Eclipse:
|
||||
.classpath
|
||||
.project
|
||||
.metadata/
|
||||
/android/bin/
|
||||
/core/bin/
|
||||
/lwjgl2/bin/
|
||||
/lwjgl3/bin/
|
||||
/html/bin/
|
||||
/teavm/bin/
|
||||
/ios/bin/
|
||||
/ios-moe/bin/
|
||||
/headless/bin/
|
||||
/server/bin/
|
||||
/shared/bin/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
.settings/
|
||||
.loadpath
|
||||
.externalToolBuilders/
|
||||
*.launch
|
||||
|
||||
|
||||
## NetBeans:
|
||||
|
||||
/nbproject/private/
|
||||
/android/nbproject/private/
|
||||
/core/nbproject/private/
|
||||
/lwjgl2/nbproject/private/
|
||||
/lwjgl3/nbproject/private/
|
||||
/html/nbproject/private/
|
||||
/teavm/nbproject/private/
|
||||
/ios/nbproject/private/
|
||||
/ios-moe/nbproject/private/
|
||||
/headless/nbproject/private/
|
||||
/server/nbproject/private/
|
||||
/shared/nbproject/private/
|
||||
|
||||
/nbbuild/
|
||||
/android/nbbuild/
|
||||
/core/nbbuild/
|
||||
/lwjgl2/nbbuild/
|
||||
/lwjgl3/nbbuild/
|
||||
/html/nbbuild/
|
||||
/teavm/nbbuild/
|
||||
/ios/nbbuild/
|
||||
/ios-moe/nbbuild/
|
||||
/headless/nbbuild/
|
||||
/server/nbbuild/
|
||||
/shared/nbbuild/
|
||||
|
||||
/dist/
|
||||
/android/dist/
|
||||
/core/dist/
|
||||
/lwjgl2/dist/
|
||||
/lwjgl3/dist/
|
||||
/html/dist/
|
||||
/teavm/dist/
|
||||
/ios/dist/
|
||||
/ios-moe/dist/
|
||||
/headless/dist/
|
||||
/server/dist/
|
||||
/shared/dist/
|
||||
|
||||
/nbdist/
|
||||
/android/nbdist/
|
||||
/core/nbdist/
|
||||
/lwjgl2/nbdist/
|
||||
/lwjgl3/nbdist/
|
||||
/html/nbdist/
|
||||
/teavm/nbdist/
|
||||
/ios/nbdist/
|
||||
/ios-moe/nbdist/
|
||||
/headless/nbdist/
|
||||
/server/nbdist/
|
||||
/shared/nbdist/
|
||||
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
|
||||
## OS-Specific:
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
## Miscellaneous:
|
||||
*~
|
||||
*.*#
|
||||
*#*#
|
||||
/.kotlin/
|
||||
/assets/assets.txt
|
||||
|
||||
## Special cases:
|
||||
|
||||
## There is a resource-config.json file generated by nativeimage.gradle if you use Graal Native Image.
|
||||
## Some usage may need extra resource configuration in a different file with the same name.
|
||||
## You could also add that configuration to the text in nativeimage.gradle .
|
||||
## You should delete or comment out the next line if you have configuration in a different resource-config.json .
|
||||
**/resource-config.json
|
||||
32
WitchQueen/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# WitchQueen
|
||||
|
||||
A [libGDX](https://libgdx.com/) project generated with [gdx-liftoff](https://github.com/libgdx/gdx-liftoff).
|
||||
|
||||
This project was generated with a Kotlin project template that includes Kotlin application launchers and [KTX](https://libktx.github.io/) utilities.
|
||||
|
||||
## Platforms
|
||||
|
||||
- `core`: Main module with the application logic shared by all platforms.
|
||||
- `android`: Android mobile platform. Needs Android SDK.
|
||||
|
||||
## Gradle
|
||||
|
||||
This project uses [Gradle](https://gradle.org/) to manage dependencies.
|
||||
The Gradle wrapper was included, so you can run Gradle tasks using `gradlew.bat` or `./gradlew` commands.
|
||||
Useful Gradle tasks and flags:
|
||||
|
||||
- `--continue`: when using this flag, errors will not stop the tasks from running.
|
||||
- `--daemon`: thanks to this flag, Gradle daemon will be used to run chosen tasks.
|
||||
- `--offline`: when using this flag, cached dependency archives will be used.
|
||||
- `--refresh-dependencies`: this flag forces validation of all dependencies. Useful for snapshot versions.
|
||||
- `android:lint`: performs Android project validation.
|
||||
- `build`: builds sources and archives of every project.
|
||||
- `cleanEclipse`: removes Eclipse project data.
|
||||
- `cleanIdea`: removes IntelliJ project data.
|
||||
- `clean`: removes `build` folders, which store compiled classes and built archives.
|
||||
- `eclipse`: generates Eclipse project data.
|
||||
- `idea`: generates IntelliJ project data.
|
||||
- `test`: runs unit tests (if any).
|
||||
|
||||
Note that most tasks that are not specific to a single project can be run with `name:` prefix, where the `name` should be replaced with the ID of a specific project.
|
||||
For example, `core:clean` removes `build` folder only from the `core` project.
|
||||
27
WitchQueen/android/AndroidManifest.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:isGame="true"
|
||||
android:appCategory="game"
|
||||
android:label="@string/app_name"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:theme="@style/GdxTheme">
|
||||
<activity
|
||||
android:name="com.iofferyoutea.WitchQueen.android.AndroidLauncher"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="landscape"
|
||||
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
136
WitchQueen/android/build.gradle
Normal file
@@ -0,0 +1,136 @@
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
}
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
namespace = "com.iofferyoutea.WitchQueen"
|
||||
compileSdk = 35
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.setSrcDirs(['src/main/java', 'src/main/kotlin'])
|
||||
aidl.setSrcDirs(['src/main/java', 'src/main/kotlin'])
|
||||
renderscript.setSrcDirs(['src/main/java', 'src/main/kotlin'])
|
||||
res.setSrcDirs(['res'])
|
||||
assets.setSrcDirs(['../assets'])
|
||||
jniLibs.setSrcDirs(['libs'])
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
excludes += ['META-INF/robovm/ios/robovm.xml', 'META-INF/DEPENDENCIES.txt', 'META-INF/DEPENDENCIES',
|
||||
'META-INF/dependencies.txt', '**/*.gwt.xml']
|
||||
pickFirsts += ['META-INF/LICENSE.txt', 'META-INF/LICENSE', 'META-INF/license.txt', 'META-INF/LGPL2.1',
|
||||
'META-INF/NOTICE.txt', 'META-INF/NOTICE', 'META-INF/notice.txt']
|
||||
}
|
||||
}
|
||||
defaultConfig {
|
||||
applicationId 'com.iofferyoutea.WitchQueen'
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 35
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility "8"
|
||||
targetCompatibility "8"
|
||||
coreLibraryDesugaringEnabled = true
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
kotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
|
||||
|
||||
}
|
||||
|
||||
repositories {
|
||||
// needed for AAPT2, may be needed for other tools
|
||||
google()
|
||||
}
|
||||
|
||||
configurations { natives }
|
||||
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||
implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
|
||||
implementation project(':core')
|
||||
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-arm64-v8a"
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86"
|
||||
natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86_64"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
|
||||
|
||||
}
|
||||
|
||||
// Called every time gradle gets executed, takes the native dependencies of
|
||||
// the natives configuration, and extracts them to the proper libs/ folders
|
||||
// so they get packed with the APK.
|
||||
tasks.register('copyAndroidNatives') {
|
||||
doFirst {
|
||||
file("libs/armeabi-v7a/").mkdirs()
|
||||
file("libs/arm64-v8a/").mkdirs()
|
||||
file("libs/x86_64/").mkdirs()
|
||||
file("libs/x86/").mkdirs()
|
||||
|
||||
configurations.natives.copy().files.each { jar ->
|
||||
def outputDir = null
|
||||
if(jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a")
|
||||
if(jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a")
|
||||
if(jar.name.endsWith("natives-x86_64.jar")) outputDir = file("libs/x86_64")
|
||||
if(jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86")
|
||||
if(outputDir != null) {
|
||||
copy {
|
||||
from zipTree(jar)
|
||||
into outputDir
|
||||
include "*.so"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.matching { it.name.contains("merge") && it.name.contains("JniLibFolders") }.configureEach { packageTask ->
|
||||
packageTask.dependsOn 'copyAndroidNatives'
|
||||
}
|
||||
|
||||
tasks.register('run', Exec) {
|
||||
def path
|
||||
def localProperties = project.file("../local.properties")
|
||||
if (localProperties.exists()) {
|
||||
Properties properties = new Properties()
|
||||
localProperties.withInputStream { instr ->
|
||||
properties.load(instr)
|
||||
}
|
||||
def sdkDir = properties.getProperty('sdk.dir')
|
||||
if (sdkDir) {
|
||||
path = sdkDir
|
||||
} else {
|
||||
path = "$System.env.ANDROID_SDK_ROOT"
|
||||
}
|
||||
} else {
|
||||
path = "$System.env.ANDROID_SDK_ROOT"
|
||||
}
|
||||
|
||||
def adb = path + "/platform-tools/adb"
|
||||
commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.iofferyoutea.WitchQueen/com.iofferyoutea.WitchQueen.android.AndroidLauncher'
|
||||
}
|
||||
|
||||
eclipse.project.name = appName + "-android"
|
||||
BIN
WitchQueen/android/ic_launcher-web.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
52
WitchQueen/android/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# https://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
-verbose
|
||||
|
||||
-dontwarn android.support.**
|
||||
-dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication
|
||||
|
||||
# Needed by the gdx-controllers official extension.
|
||||
-keep class com.badlogic.gdx.controllers.android.AndroidControllers
|
||||
|
||||
# Needed by the Box2D official extension.
|
||||
-keepclassmembers class com.badlogic.gdx.physics.box2d.World {
|
||||
boolean contactFilter(long, long);
|
||||
boolean getUseDefaultContactFilter();
|
||||
void beginContact(long);
|
||||
void endContact(long);
|
||||
void preSolve(long, long);
|
||||
void postSolve(long, long);
|
||||
boolean reportFixture(long);
|
||||
float reportRayFixture(long, float, float, float, float, float);
|
||||
}
|
||||
|
||||
# You will need the next three lines if you use scene2d for UI or gameplay.
|
||||
# If you don't use scene2d at all, you can remove or comment out the next line:
|
||||
-keep public class com.badlogic.gdx.scenes.scene2d.** { *; }
|
||||
# You will need the next two lines if you use BitmapFont or any scene2d.ui text:
|
||||
-keep public class com.badlogic.gdx.graphics.g2d.BitmapFont { *; }
|
||||
# You will probably need this line in most cases:
|
||||
-keep public class com.badlogic.gdx.graphics.Color { *; }
|
||||
|
||||
# These two lines are used with mapping files; see https://developer.android.com/build/shrink-code#retracing
|
||||
-keepattributes LineNumberTable,SourceFile
|
||||
-renamesourcefileattribute SourceFile
|
||||
14
WitchQueen/android/project.properties
Normal file
@@ -0,0 +1,14 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-rules.pro
|
||||
|
||||
# Project target.
|
||||
target=android-21
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_background_color"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,28 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M457.78,372.5l-201.78,116.5l-201.78,-116.5l0,-233l201.78,-116.5l201.78,116.5z"
|
||||
android:strokeWidth="23"
|
||||
android:fillColor="#4a4a4a"
|
||||
android:strokeColor="#000000"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M449.71,363.84l-193.71,111.84l-193.71,-111.84l0,-223.68l193.71,-111.84l193.71,111.84z"/>
|
||||
<path
|
||||
android:pathData="M256,67.33c-0.36,0.13 -1.07,0.4 -2,0.99 -1.67,1.07 -3.94,2.89 -6.4,5.26 -4.93,4.75 -10.72,11.66 -16.1,19.34a142.77,142.77 0,0 0,-2.95 4.41c9.43,-1.86 18.44,-2.8 27.45,-2.8 9.01,0 18.03,0.94 27.45,2.8a142.77,142.77 135,0 0,-2.95 -4.41c-5.38,-7.68 -11.17,-14.6 -16.1,-19.34 -2.46,-2.37 -4.73,-4.2 -6.4,-5.26a9.93,9.93 135,0 0,-2 -0.99zM256,108.66c-11.75,0 -23.5,1.9 -36.98,5.69C214.74,123.36 212,131.66 212,136.8l0,127.71c4.08,-13.81 7.7,-30.59 11.2,-51.52L223.2,200.8c0,-8.8 3.65,-18.74 9.03,-27.7 2.69,-4.48 5.85,-8.63 9.66,-11.94C245.69,157.86 250.4,155.2 256,155.2s10.31,2.66 14.12,5.96c3.81,3.3 6.97,7.45 9.66,11.94C285.15,182.06 288.8,192 288.8,200.8l0,12.19c3.5,20.94 7.12,37.71 11.2,51.52L300,136.8c0,-5.14 -2.74,-13.44 -7.02,-22.45 -13.47,-3.79 -25.23,-5.69 -36.98,-5.69zM185.6,150.71c-5.21,9.21 -12,23.48 -12,37.29l0,31.2l24,0l0,-31.2c0,-13.81 -6.79,-28.08 -12,-37.29zM326.4,150.71c-5.21,9.21 -12,23.48 -12,37.29l0,31.2l24,0l0,-31.2c0,-13.81 -6.79,-28.08 -12,-37.29zM256,169.6c-0.8,0 -2.49,0.54 -4.68,2.44 -2.19,1.9 -4.63,4.95 -6.74,8.46C240.35,187.54 237.6,196.8 237.6,200.8l0,131.02l-2.16,2.12c-8.49,8.33 -10.26,28.91 -10.52,42.22 5.34,2.83 14.26,5.13 23.88,5.94L248.8,341.6l14.4,0l0,40.49c9.62,-0.8 18.54,-3.11 23.88,-5.94 -0.25,-13.27 -1.97,-33.66 -10.57,-42.26L274.4,331.78L274.4,200.8c0,-4 -2.75,-13.26 -6.97,-20.3 -2.11,-3.52 -4.55,-6.57 -6.74,-8.46C258.49,170.14 256.8,169.6 256,169.6zM243.2,193.6l25.6,0l0,14.4l-25.6,0l0,-14.4zM173.6,233.6l0,93.05c9.94,-8.52 17.6,-17.06 24,-27.75L197.6,233.6l-24,0zM314.4,233.6l0,65.3c6.4,10.69 14.06,19.24 24,27.75L338.4,233.6l-24,0zM223.2,276.78c-2.81,8.32 -5.87,15.8 -9.36,22.54 -7.44,14.41 -16.73,25.6 -28.37,36.03l30.94,1.55c1.73,-3.88 3.94,-7.57 6.78,-10.87l0,-49.24zM288.8,276.78l0,49.28c2.81,3.3 5,6.98 6.72,10.84l31,-1.55c-11.64,-10.42 -20.92,-21.62 -28.37,-36.03 -3.48,-6.74 -6.55,-14.22 -9.36,-22.54zM446.4,289.61c-10.84,4.52 -15.22,15.65 -21.56,33.46 0,0 -36.65,0.34 -42.7,14.05 -6.46,14.65 19.67,43.83 19.67,43.83s-21.71,-6.98 -30.34,-1.69c-9.59,5.88 -13.61,30.87 -13.61,30.87 -2.83,-0.68 -5.52,-1.24 -8.11,-1.71L341.33,383.2l8.53,0l-4.79,-8.77 -42.81,2.14 -0.65,1.2c-0,0.73 -0.01,1.56 -0.01,2.22l0,3.2l5.6,0l-8.53,25.6 17.07,-12.8 4,12.01c-11.83,2.51 -20.44,8.55 -28.72,16.43L281.6,405.6l12.8,0l-10.24,-12.49C275.61,395.79 265.83,396.8 256,396.8c-9.85,0 -19.66,-1.02 -28.22,-3.7L217.6,405.6l12.8,0l-10.31,20.62c-9.71,-4.02 -20.02,-8.02 -30.08,-11.44L196.27,396l17.07,12.8L204.8,383.2l5.6,0l0,-3.2c0,-0.65 -0.01,-1.47 -0.01,-2.18l-0.68,-1.24 -42.82,-2.14 -4.76,8.77l8.53,0l-7.96,23.89c-3.19,-0.65 -6.24,-1.16 -9.1,-1.49 -25.25,-2.9 -31.78,3.71 -46.35,9.93 0,0 13.33,-77.26 -13.35,-94.7 -3.3,-2.16 -7.43,-3.03 -11.99,-2.98 -5.06,0.04 -10.67,1.22 -16.31,2.99L65.6,442.4l189.6,0l0.8,1.6 12.8,-25.6 18.79,9.4c-4.45,4.5 -8.93,9.46 -13.88,14.6L446.4,442.4L446.4,289.61zM168.82,348.93c-4.32,3.9 -5.52,7.7 -5.45,9.24 0.04,0.88 0.19,1 0.41,1.19 0.22,0.19 0.81,0.63 2.63,0.63l0.18,0l44.16,2.21c0.25,-3.58 0.68,-7.33 1.39,-11.11l-43.31,-2.17zM343.18,348.93l-43.35,2.17c0.72,3.78 1.15,7.53 1.41,11.11l44.18,-2.21L345.6,360c1.82,0 2.42,-0.44 2.63,-0.63 0.22,-0.19 0.37,-0.32 0.41,-1.19 0.06,-1.54 -1.14,-5.34 -5.45,-9.24zM179.2,396l5.7,17.09c-7.29,-2.35 -14.35,-4.32 -20.86,-5.72L179.2,396zM332.8,396l16.44,12.33c-7.58,-1.34 -14.17,-1.78 -20.05,-1.5L332.8,396zM243.2,418.4l11.64,23.27c-7.9,-3.74 -18.63,-8.66 -30.68,-13.75L243.2,418.4z"
|
||||
android:fillColor="#ffda54"/>
|
||||
</group>
|
||||
<path
|
||||
android:pathData="M135.76,190.05L112.46,190.05v-15.61q0,-6.81 -0.77,-8.47 -0.72,-1.72 -3.26,-1.72 -2.88,0 -3.65,2.05 -0.77,2.05 -0.77,8.85v41.61q0,6.53 0.77,8.52 0.77,1.99 3.49,1.99 2.6,0 3.38,-1.99 0.83,-1.99 0.83,-9.35v-11.23h23.3v3.49q0,13.89 -1.99,19.7 -1.94,5.81 -8.69,10.18 -6.7,4.37 -16.55,4.37 -10.24,0 -16.88,-3.71 -6.64,-3.71 -8.8,-10.24 -2.16,-6.59 -2.16,-19.76L80.7,182.58q0,-9.68 0.66,-14.5 0.66,-4.87 3.93,-9.35 3.32,-4.48 9.13,-7.03 5.87,-2.6 13.45,-2.6 10.29,0 16.99,3.98 6.7,3.98 8.8,9.96 2.1,5.92 2.1,18.48zM197.68,150.98v89.59h-23.3v-37.63h-6.97v37.63h-23.3v-89.59h23.3v32.04h6.97v-32.04zM247.27,150.98 L260.6,240.57L236.75,240.57l-1.16,-16.1h-8.36l-1.38,16.1h-24.13l11.84,-89.59zM234.93,208.59q-1.77,-15.22 -3.54,-37.57 -3.54,25.68 -4.43,37.57zM316.6,150.98v89.59h-20.42l-12.12,-40.73v40.73h-19.48v-89.59h19.48l13.06,40.34v-40.34zM379.41,183.96h-23.3v-8.13q0,-7.69 -0.66,-9.63 -0.66,-1.94 -3.15,-1.94 -2.16,0 -2.93,1.66 -0.77,1.66 -0.77,8.52v43q0,6.03 0.77,7.97 0.77,1.88 3.1,1.88 2.55,0 3.43,-2.16 0.94,-2.16 0.94,-8.41v-10.62h-4.7v-13.61h27.28v48.09h-14.66l-2.16,-6.42q-2.38,4.15 -6.03,6.25 -3.6,2.05 -8.52,2.05 -5.87,0 -11.01,-2.82 -5.09,-2.88 -7.75,-7.08 -2.66,-4.21 -3.32,-8.8 -0.66,-4.65 -0.66,-13.89v-26.62q0,-12.84 1.38,-18.65 1.38,-5.81 7.91,-10.62 6.59,-4.87 16.99,-4.87 10.24,0 16.99,4.21 6.75,4.21 8.8,10.02 2.05,5.76 2.05,16.77zM388.43,150.98h38.85v17.93h-15.55v16.99h14.55v17.04h-14.55v19.7h17.1v17.93L388.43,240.57Z"
|
||||
android:strokeWidth="6.1"
|
||||
android:fillColor="#f30d0d"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="m202.17,286.98v17.93h-13.83v71.66h-23.3v-71.66h-13.78v-17.93zM261.05,286.98v89.59h-23.3v-37.63h-6.97v37.63L207.48,376.57v-89.59h23.3v32.04h6.97v-32.04zM293.69,286.98v89.59h-23.3v-89.59zM352.41,314.09L330.77,314.09v-6.64q0,-4.65 -0.83,-5.92 -0.83,-1.27 -2.77,-1.27 -2.1,0 -3.21,1.72 -1.05,1.72 -1.05,5.2 0,4.48 1.22,6.75 1.16,2.27 6.59,5.48 15.55,9.24 19.59,15.16 4.04,5.92 4.04,19.09 0,9.57 -2.27,14.11 -2.21,4.54 -8.63,7.64 -6.42,3.04 -14.94,3.04 -9.35,0 -15.99,-3.54 -6.59,-3.54 -8.63,-9.02 -2.05,-5.48 -2.05,-15.55v-5.87h21.64v10.9q0,5.04 0.89,6.47 0.94,1.44 3.26,1.44 2.32,0 3.43,-1.83 1.16,-1.83 1.16,-5.42 0,-7.91 -2.16,-10.35 -2.21,-2.43 -10.9,-8.13 -8.69,-5.76 -11.51,-8.36 -2.82,-2.6 -4.7,-7.19 -1.83,-4.59 -1.83,-11.73 0,-10.29 2.6,-15.05 2.66,-4.76 8.52,-7.42 5.87,-2.71 14.17,-2.71 9.08,0 15.44,2.93 6.42,2.93 8.47,7.42 2.1,4.43 2.1,15.11z"
|
||||
android:strokeWidth="6.1"
|
||||
android:fillColor="#f30d0d"
|
||||
android:strokeColor="#000000"/>
|
||||
</vector>
|
||||
BIN
WitchQueen/android/res/drawable-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
WitchQueen/android/res/drawable-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
WitchQueen/android/res/drawable-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
WitchQueen/android/res/drawable-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
WitchQueen/android/res/drawable-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
5
WitchQueen/android/res/values/color.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_background_color">#F5A623FF</color>
|
||||
<color name="background">#FFFFFFFF</color>
|
||||
</resources>
|
||||
4
WitchQueen/android/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">WitchQueen</string>
|
||||
</resources>
|
||||
5
WitchQueen/android/res/values/styles.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<resources>
|
||||
<style name="GdxTheme" parent="android:Theme.Material.Light.NoActionBar.Fullscreen">
|
||||
<item name="android:colorBackground">@color/background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.iofferyoutea.WitchQueen.android
|
||||
|
||||
import android.os.Bundle
|
||||
|
||||
import com.badlogic.gdx.backends.android.AndroidApplication
|
||||
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration
|
||||
import com.iofferyoutea.WitchQueen.Main
|
||||
|
||||
/** Launches the Android application. */
|
||||
class AndroidLauncher : AndroidApplication() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
initialize(Main(), AndroidApplicationConfiguration().apply {
|
||||
// Configure your application here.
|
||||
useImmersiveMode = true // Recommended, but not required.
|
||||
})
|
||||
}
|
||||
}
|
||||
BIN
WitchQueen/assets/default-4096x4096.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
101
WitchQueen/assets/default.fnt
Normal file
@@ -0,0 +1,101 @@
|
||||
info face="Droid Sans" size=17 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1
|
||||
common lineHeight=20 base=18 scaleW=256 scaleH=128 pages=1 packed=0
|
||||
page id=0 file="default.png"
|
||||
chars count=96
|
||||
char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=16 xadvance=4 page=0 chnl=0
|
||||
char id=124 x=0 y=0 width=6 height=20 xoffset=1 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=106 x=6 y=0 width=9 height=20 xoffset=-4 yoffset=3 xadvance=4 page=0 chnl=0
|
||||
char id=81 x=15 y=0 width=15 height=19 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0
|
||||
char id=74 x=30 y=0 width=11 height=19 xoffset=-5 yoffset=3 xadvance=4 page=0 chnl=0
|
||||
char id=125 x=41 y=0 width=10 height=18 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0
|
||||
char id=123 x=51 y=0 width=10 height=18 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0
|
||||
char id=93 x=61 y=0 width=8 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0
|
||||
char id=91 x=69 y=0 width=8 height=18 xoffset=-2 yoffset=3 xadvance=5 page=0 chnl=0
|
||||
char id=41 x=77 y=0 width=9 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0
|
||||
char id=40 x=86 y=0 width=9 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0
|
||||
char id=64 x=95 y=0 width=18 height=17 xoffset=-3 yoffset=3 xadvance=14 page=0 chnl=0
|
||||
char id=121 x=113 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0
|
||||
char id=113 x=126 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0
|
||||
char id=112 x=139 y=0 width=13 height=17 xoffset=-2 yoffset=6 xadvance=9 page=0 chnl=0
|
||||
char id=103 x=152 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0
|
||||
char id=38 x=165 y=0 width=16 height=16 xoffset=-3 yoffset=3 xadvance=11 page=0 chnl=0
|
||||
char id=37 x=181 y=0 width=18 height=16 xoffset=-3 yoffset=3 xadvance=14 page=0 chnl=0
|
||||
char id=36 x=199 y=0 width=12 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=63 x=211 y=0 width=11 height=16 xoffset=-3 yoffset=3 xadvance=7 page=0 chnl=0
|
||||
char id=33 x=222 y=0 width=7 height=16 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0
|
||||
char id=48 x=229 y=0 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=57 x=242 y=0 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=56 x=0 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=54 x=13 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=53 x=26 y=20 width=12 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=51 x=38 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=100 x=51 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=98 x=64 y=20 width=13 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=85 x=77 y=20 width=14 height=16 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0
|
||||
char id=83 x=91 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0
|
||||
char id=79 x=104 y=20 width=15 height=16 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0
|
||||
char id=71 x=119 y=20 width=14 height=16 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0
|
||||
char id=67 x=133 y=20 width=13 height=16 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0
|
||||
char id=127 x=146 y=20 width=12 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0
|
||||
char id=35 x=158 y=20 width=15 height=15 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=0
|
||||
char id=92 x=173 y=20 width=11 height=15 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0
|
||||
char id=47 x=184 y=20 width=11 height=15 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0
|
||||
char id=59 x=195 y=20 width=8 height=15 xoffset=-3 yoffset=6 xadvance=4 page=0 chnl=0
|
||||
char id=55 x=203 y=20 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=52 x=216 y=20 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=50 x=230 y=20 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=49 x=243 y=20 width=9 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=116 x=0 y=36 width=10 height=15 xoffset=-3 yoffset=4 xadvance=5 page=0 chnl=0
|
||||
char id=108 x=10 y=36 width=6 height=15 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0
|
||||
char id=107 x=16 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0
|
||||
char id=105 x=28 y=36 width=7 height=15 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0
|
||||
char id=104 x=35 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0
|
||||
char id=102 x=47 y=36 width=11 height=15 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0
|
||||
char id=90 x=58 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=89 x=71 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0
|
||||
char id=88 x=84 y=36 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=87 x=98 y=36 width=19 height=15 xoffset=-3 yoffset=3 xadvance=15 page=0 chnl=0
|
||||
char id=86 x=117 y=36 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=84 x=131 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0
|
||||
char id=82 x=144 y=36 width=13 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0
|
||||
char id=80 x=157 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=78 x=169 y=36 width=14 height=15 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0
|
||||
char id=77 x=183 y=36 width=17 height=15 xoffset=-2 yoffset=3 xadvance=14 page=0 chnl=0
|
||||
char id=76 x=200 y=36 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0
|
||||
char id=75 x=211 y=36 width=13 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=73 x=224 y=36 width=10 height=15 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0
|
||||
char id=72 x=234 y=36 width=14 height=15 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0
|
||||
char id=70 x=0 y=51 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0
|
||||
char id=69 x=11 y=51 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0
|
||||
char id=68 x=22 y=51 width=14 height=15 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0
|
||||
char id=66 x=36 y=51 width=13 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0
|
||||
char id=65 x=49 y=51 width=15 height=15 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=0
|
||||
char id=58 x=64 y=51 width=7 height=13 xoffset=-2 yoffset=6 xadvance=4 page=0 chnl=0
|
||||
char id=117 x=71 y=51 width=12 height=13 xoffset=-2 yoffset=6 xadvance=10 page=0 chnl=0
|
||||
char id=115 x=83 y=51 width=11 height=13 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0
|
||||
char id=111 x=94 y=51 width=13 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0
|
||||
char id=101 x=107 y=51 width=13 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0
|
||||
char id=99 x=120 y=51 width=12 height=13 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0
|
||||
char id=97 x=132 y=51 width=12 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0
|
||||
char id=60 x=144 y=51 width=13 height=12 xoffset=-3 yoffset=5 xadvance=9 page=0 chnl=0
|
||||
char id=122 x=157 y=51 width=11 height=12 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0
|
||||
char id=120 x=168 y=51 width=13 height=12 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0
|
||||
char id=119 x=181 y=51 width=17 height=12 xoffset=-3 yoffset=6 xadvance=12 page=0 chnl=0
|
||||
char id=118 x=198 y=51 width=13 height=12 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0
|
||||
char id=114 x=211 y=51 width=10 height=12 xoffset=-2 yoffset=6 xadvance=6 page=0 chnl=0
|
||||
char id=110 x=221 y=51 width=12 height=12 xoffset=-2 yoffset=6 xadvance=10 page=0 chnl=0
|
||||
char id=109 x=233 y=51 width=17 height=12 xoffset=-2 yoffset=6 xadvance=15 page=0 chnl=0
|
||||
char id=94 x=0 y=66 width=13 height=11 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=62 x=13 y=66 width=13 height=11 xoffset=-3 yoffset=5 xadvance=9 page=0 chnl=0
|
||||
char id=42 x=26 y=66 width=13 height=10 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0
|
||||
char id=43 x=39 y=66 width=13 height=10 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0
|
||||
char id=61 x=52 y=66 width=13 height=8 xoffset=-3 yoffset=7 xadvance=9 page=0 chnl=0
|
||||
char id=39 x=65 y=66 width=6 height=8 xoffset=-2 yoffset=3 xadvance=3 page=0 chnl=0
|
||||
char id=34 x=71 y=66 width=9 height=8 xoffset=-2 yoffset=3 xadvance=6 page=0 chnl=0
|
||||
char id=44 x=80 y=66 width=8 height=7 xoffset=-3 yoffset=14 xadvance=4 page=0 chnl=0
|
||||
char id=126 x=88 y=66 width=13 height=6 xoffset=-3 yoffset=8 xadvance=9 page=0 chnl=0
|
||||
char id=46 x=101 y=66 width=7 height=6 xoffset=-2 yoffset=13 xadvance=4 page=0 chnl=0
|
||||
char id=96 x=108 y=66 width=8 height=6 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=0
|
||||
char id=45 x=116 y=66 width=9 height=5 xoffset=-3 yoffset=10 xadvance=5 page=0 chnl=0
|
||||
char id=95 x=125 y=66 width=13 height=4 xoffset=-4 yoffset=17 xadvance=6 page=0 chnl=0
|
||||
kernings count=-1
|
||||
BIN
WitchQueen/assets/default.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
WitchQueen/assets/logo.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
200
WitchQueen/assets/uiskin.atlas
Normal file
@@ -0,0 +1,200 @@
|
||||
|
||||
uiskin.png
|
||||
size: 256,128
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
check-off
|
||||
rotate: false
|
||||
xy: 11, 5
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
textfield
|
||||
rotate: false
|
||||
xy: 11, 5
|
||||
size: 14, 14
|
||||
split: 3, 3, 3, 3
|
||||
orig: 14, 14
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
check-on
|
||||
rotate: false
|
||||
xy: 125, 35
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
cursor
|
||||
rotate: false
|
||||
xy: 23, 1
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default
|
||||
rotate: false
|
||||
xy: 1, 50
|
||||
size: 254, 77
|
||||
orig: 254, 77
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-pane
|
||||
rotate: false
|
||||
xy: 11, 1
|
||||
size: 5, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 5, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-rect-pad
|
||||
rotate: false
|
||||
xy: 11, 1
|
||||
size: 5, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 5, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-pane-noborder
|
||||
rotate: false
|
||||
xy: 170, 44
|
||||
size: 1, 1
|
||||
split: 0, 0, 0, 0
|
||||
orig: 1, 1
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-rect
|
||||
rotate: false
|
||||
xy: 38, 25
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-rect-down
|
||||
rotate: false
|
||||
xy: 170, 46
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-round
|
||||
rotate: false
|
||||
xy: 112, 29
|
||||
size: 12, 20
|
||||
split: 5, 5, 5, 4
|
||||
pad: 4, 4, 1, 1
|
||||
orig: 12, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-round-down
|
||||
rotate: false
|
||||
xy: 99, 29
|
||||
size: 12, 20
|
||||
split: 5, 5, 5, 4
|
||||
pad: 4, 4, 1, 1
|
||||
orig: 12, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-round-large
|
||||
rotate: false
|
||||
xy: 57, 29
|
||||
size: 20, 20
|
||||
split: 5, 5, 5, 4
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-scroll
|
||||
rotate: false
|
||||
xy: 78, 29
|
||||
size: 20, 20
|
||||
split: 2, 2, 2, 2
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-select
|
||||
rotate: false
|
||||
xy: 29, 29
|
||||
size: 27, 20
|
||||
split: 4, 14, 4, 4
|
||||
orig: 27, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-select-selection
|
||||
rotate: false
|
||||
xy: 26, 16
|
||||
size: 3, 3
|
||||
split: 1, 1, 1, 1
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-slider
|
||||
rotate: false
|
||||
xy: 29, 20
|
||||
size: 8, 8
|
||||
split: 2, 2, 2, 2
|
||||
orig: 8, 8
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-slider-knob
|
||||
rotate: false
|
||||
xy: 1, 1
|
||||
size: 9, 18
|
||||
orig: 9, 18
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-splitpane
|
||||
rotate: false
|
||||
xy: 17, 1
|
||||
size: 5, 3
|
||||
split: 0, 5, 0, 0
|
||||
orig: 5, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-splitpane-vertical
|
||||
rotate: false
|
||||
xy: 125, 29
|
||||
size: 3, 5
|
||||
split: 0, 0, 0, 5
|
||||
orig: 3, 5
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
default-window
|
||||
rotate: false
|
||||
xy: 1, 20
|
||||
size: 27, 29
|
||||
split: 4, 3, 20, 3
|
||||
orig: 27, 29
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
selection
|
||||
rotate: false
|
||||
xy: 174, 48
|
||||
size: 1, 1
|
||||
orig: 1, 1
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tree-minus
|
||||
rotate: false
|
||||
xy: 140, 35
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tree-plus
|
||||
rotate: false
|
||||
xy: 155, 35
|
||||
size: 14, 14
|
||||
orig: 14, 14
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
white
|
||||
rotate: false
|
||||
xy: 129, 31
|
||||
size: 3, 3
|
||||
orig: 3, 3
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
71
WitchQueen/assets/uiskin.json
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
BitmapFont: { default-font: { file: default.fnt } },
|
||||
Color: {
|
||||
green: { a: 1, b: 0, g: 1, r: 0 },
|
||||
white: { a: 1, b: 1, g: 1, r: 1 },
|
||||
red: { a: 1, b: 0, g: 0, r: 1 },
|
||||
black: { a: 1, b: 0, g: 0, r: 0 },
|
||||
gray: { a: 1, b: 0.8, g: 0.8, r: 0.8 },
|
||||
},
|
||||
TintedDrawable: {
|
||||
dialogDim: { name: white, color: { r: 0, g: 0, b: 0, a: 0.45 } },
|
||||
},
|
||||
ButtonStyle: {
|
||||
default: { down: default-round-down, up: default-round, disabled: default-round },
|
||||
toggle: { parent: default, checked: default-round-down }
|
||||
},
|
||||
TextButtonStyle: {
|
||||
default: { parent: default, font: default-font, fontColor: white, disabledFontColor: gray },
|
||||
toggle: { parent: default, checked: default-round-down, downFontColor: red }
|
||||
},
|
||||
ScrollPaneStyle: {
|
||||
default: { vScroll: default-scroll, hScrollKnob: default-round-large, background: default-rect, hScroll: default-scroll, vScrollKnob: default-round-large }
|
||||
},
|
||||
SelectBoxStyle: {
|
||||
default: {
|
||||
font: default-font, fontColor: white, background: default-select,
|
||||
scrollStyle: default,
|
||||
listStyle: { font: default-font, selection: default-select-selection }
|
||||
}
|
||||
},
|
||||
SplitPaneStyle: {
|
||||
default-vertical: { handle: default-splitpane-vertical },
|
||||
default-horizontal: { handle: default-splitpane }
|
||||
},
|
||||
WindowStyle: {
|
||||
default: { titleFont: default-font, background: default-window, titleFontColor: white },
|
||||
dialog: { parent: default, stageBackground: dialogDim }
|
||||
},
|
||||
ProgressBarStyle: {
|
||||
default-horizontal: { background: default-slider, knob: default-slider-knob },
|
||||
default-vertical: { background: default-slider, knob: default-round-large }
|
||||
},
|
||||
SliderStyle: {
|
||||
default-horizontal: { parent: default-horizontal },
|
||||
default-vertical: { parent: default-vertical }
|
||||
},
|
||||
LabelStyle: {
|
||||
default: { font: default-font, fontColor: white }
|
||||
},
|
||||
TextFieldStyle: {
|
||||
default: { selection: selection, background: textfield, font: default-font, fontColor: white, cursor: cursor }
|
||||
},
|
||||
CheckBoxStyle: {
|
||||
default: { checkboxOn: check-on, checkboxOff: check-off, font: default-font, fontColor: white }
|
||||
},
|
||||
ListStyle: {
|
||||
default: { fontColorUnselected: white, selection: selection, fontColorSelected: white, font: default-font }
|
||||
},
|
||||
TouchpadStyle: {
|
||||
default: { background: default-pane, knob: default-round-large }
|
||||
},
|
||||
TreeStyle: {
|
||||
default: { minus: tree-minus, plus: tree-plus, selection: default-select-selection }
|
||||
},
|
||||
TextTooltipStyle: {
|
||||
default: {
|
||||
label: { font: default-font, fontColor: white },
|
||||
background: default-pane, wrapWidth: 150
|
||||
}
|
||||
},
|
||||
}
|
||||
BIN
WitchQueen/assets/uiskin.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
74
WitchQueen/build.gradle
Normal file
@@ -0,0 +1,74 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
mavenLocal()
|
||||
google()
|
||||
maven { url = 'https://central.sonatype.com/repository/maven-snapshots/' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
|
||||
// This allows you to "Build and run using IntelliJ IDEA", an option in IDEA's Settings.
|
||||
idea {
|
||||
module {
|
||||
outputDir = file('build/classes/java/main')
|
||||
testOutputDir = file('build/classes/java/test')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure(subprojects - project(':android')) {
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
java.sourceCompatibility = 8
|
||||
|
||||
// From https://lyze.dev/2021/04/29/libGDX-Internal-Assets-List/
|
||||
// The article can be helpful when using assets.txt in your project.
|
||||
tasks.register('generateAssetList') {
|
||||
inputs.dir("${project.rootDir}/assets/")
|
||||
// projectFolder/assets
|
||||
File assetsFolder = new File("${project.rootDir}/assets/")
|
||||
// projectFolder/assets/assets.txt
|
||||
File assetsFile = new File(assetsFolder, "assets.txt")
|
||||
// delete that file in case we've already created it
|
||||
assetsFile.delete()
|
||||
|
||||
// iterate through all files inside that folder
|
||||
// convert it to a relative path
|
||||
// and append it to the file assets.txt
|
||||
fileTree(assetsFolder).collect { assetsFolder.relativePath(it) }.sort().each {
|
||||
assetsFile.append(it + "\n")
|
||||
}
|
||||
}
|
||||
processResources.dependsOn 'generateAssetList'
|
||||
|
||||
compileJava {
|
||||
options.incremental = true
|
||||
}
|
||||
compileKotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
|
||||
compileTestKotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
|
||||
|
||||
}
|
||||
|
||||
subprojects {
|
||||
version = "$projectVersion"
|
||||
ext.appName = 'WitchQueen'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
// You may want to remove the following line if you have errors downloading dependencies.
|
||||
mavenLocal()
|
||||
maven { url = 'https://central.sonatype.com/repository/maven-snapshots/' }
|
||||
maven { url = 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
eclipse.project.name = 'WitchQueen' + '-parent'
|
||||
43
WitchQueen/core/build.gradle
Normal file
@@ -0,0 +1,43 @@
|
||||
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||
eclipse.project.name = appName + '-core'
|
||||
|
||||
dependencies {
|
||||
api "com.badlogicgames.ashley:ashley:$ashleyVersion"
|
||||
api "com.badlogicgames.gdx:gdx-ai:$aiVersion"
|
||||
api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
|
||||
api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||
api "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||
api "com.github.kotcrab.vis-ui:vis-ui:$visUiVersion"
|
||||
api "io.github.libktx:ktx-actors:$ktxVersion"
|
||||
api "io.github.libktx:ktx-ai:$ktxVersion"
|
||||
api "io.github.libktx:ktx-app:$ktxVersion"
|
||||
api "io.github.libktx:ktx-artemis:$ktxVersion"
|
||||
api "io.github.libktx:ktx-ashley:$ktxVersion"
|
||||
api "io.github.libktx:ktx-assets-async:$ktxVersion"
|
||||
api "io.github.libktx:ktx-assets:$ktxVersion"
|
||||
api "io.github.libktx:ktx-async:$ktxVersion"
|
||||
api "io.github.libktx:ktx-box2d:$ktxVersion"
|
||||
api "io.github.libktx:ktx-collections:$ktxVersion"
|
||||
api "io.github.libktx:ktx-freetype-async:$ktxVersion"
|
||||
api "io.github.libktx:ktx-freetype:$ktxVersion"
|
||||
api "io.github.libktx:ktx-graphics:$ktxVersion"
|
||||
api "io.github.libktx:ktx-i18n:$ktxVersion"
|
||||
api "io.github.libktx:ktx-inject:$ktxVersion"
|
||||
api "io.github.libktx:ktx-json:$ktxVersion"
|
||||
api "io.github.libktx:ktx-log:$ktxVersion"
|
||||
api "io.github.libktx:ktx-math:$ktxVersion"
|
||||
api "io.github.libktx:ktx-preferences:$ktxVersion"
|
||||
api "io.github.libktx:ktx-reflect:$ktxVersion"
|
||||
api "io.github.libktx:ktx-scene2d:$ktxVersion"
|
||||
api "io.github.libktx:ktx-style:$ktxVersion"
|
||||
api "io.github.libktx:ktx-tiled:$ktxVersion"
|
||||
api "io.github.libktx:ktx-vis-style:$ktxVersion"
|
||||
api "io.github.libktx:ktx-vis:$ktxVersion"
|
||||
api "net.onedaybeard.artemis:artemis-odb:$artemisOdbVersion"
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion"
|
||||
|
||||
if(enableGraalNative == 'true') {
|
||||
implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.iofferyoutea.WitchQueen
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.Texture.TextureFilter.Linear
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import ktx.app.KtxGame
|
||||
import ktx.app.KtxScreen
|
||||
import ktx.app.clearScreen
|
||||
import ktx.assets.disposeSafely
|
||||
import ktx.assets.toInternalFile
|
||||
import ktx.async.KtxAsync
|
||||
import ktx.graphics.use
|
||||
|
||||
class Main : KtxGame<KtxScreen>() {
|
||||
override fun create() {
|
||||
KtxAsync.initiate()
|
||||
|
||||
addScreen(FirstScreen())
|
||||
setScreen<FirstScreen>()
|
||||
}
|
||||
}
|
||||
|
||||
class FirstScreen : KtxScreen {
|
||||
private val image = Texture("logo.png".toInternalFile(), true).apply { setFilter(Linear, Linear) }
|
||||
private val batch = SpriteBatch()
|
||||
|
||||
override fun render(delta: Float) {
|
||||
clearScreen(red = 0.7f, green = 0.7f, blue = 0.7f)
|
||||
batch.use {
|
||||
it.draw(image, 100f, 160f)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
image.disposeSafely()
|
||||
batch.disposeSafely()
|
||||
}
|
||||
}
|
||||
27
WitchQueen/gradle.properties
Normal file
@@ -0,0 +1,27 @@
|
||||
# This doesn't need to be false, and some projects may be able to take advantage of setting daemon to true.
|
||||
# We set it to false by default in order to avoid too many daemons from being created and persisting; each needs RAM.
|
||||
org.gradle.daemon=false
|
||||
# Sets starting memory usage to 512MB, maximum memory usage to 1GB, and tries to set as much to use Unicode as we can.
|
||||
org.gradle.jvmargs=-Xms512M -Xmx1G -Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8
|
||||
# "Configure on-demand" must be false because it breaks projects that have Android modules. The default is also false.
|
||||
org.gradle.configureondemand=false
|
||||
# The logging level determines which messages get shown about how Gradle itself is working, such as if build.gradle
|
||||
# files are fully future-proof (which they never are, because Gradle constantly deprecates working APIs).
|
||||
# You can change 'quiet' below to 'lifecycle' to use Gradle's default behavior, which shows some confusing messages.
|
||||
# You could instead change 'quiet' below to 'info' to see info that's important mainly while debugging build files.
|
||||
# Note that if you want to use Gradle Build Scans, you should set the below logging level to 'lifecycle', otherwise
|
||||
# the link to the scan won't get shown at all.
|
||||
# Documented at: https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_logging
|
||||
org.gradle.logging.level=quiet
|
||||
ktxVersion=1.13.1-rc1
|
||||
kotlinVersion=2.3.0
|
||||
artemisOdbVersion=2.3.0
|
||||
aiVersion=1.8.2
|
||||
ashleyVersion=1.7.4
|
||||
kotlinxCoroutinesVersion=1.10.2
|
||||
visUiVersion=1f8b37a24b
|
||||
android.useAndroidX=true
|
||||
android.enableR8.fullMode=false
|
||||
enableGraalNative=false
|
||||
gdxVersion=1.14.0
|
||||
projectVersion=1.0.0
|
||||
12
WitchQueen/gradle/gradle-daemon-jvm.properties
Normal file
@@ -0,0 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73c462e34475aeb6509ab7ba3eda218f/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/54001d0b636ad500b432d20ef3d580d0/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73c462e34475aeb6509ab7ba3eda218f/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/54001d0b636ad500b432d20ef3d580d0/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29c55e6bad8a0049163f0184625cecd9/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/3ac7a5361c25c0b23d933f44bdb0abd9/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73c462e34475aeb6509ab7ba3eda218f/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/54001d0b636ad500b432d20ef3d580d0/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/dd5b582862cacd4b8e0d82037f92a53f/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/16008c489780dfb402c44316e612a16c/redirect
|
||||
toolchainVersion=17
|
||||
BIN
WitchQueen/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
7
WitchQueen/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
248
WitchQueen/gradlew
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
93
WitchQueen/gradlew.bat
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
8
WitchQueen/settings.gradle
Normal file
@@ -0,0 +1,8 @@
|
||||
plugins {
|
||||
// Applies the foojay-resolver plugin to allow automatic download of JDKs.
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
}
|
||||
// A list of which subprojects to load as part of the same larger project.
|
||||
// You can remove Strings from the list and reload the Gradle project
|
||||
// if you want to temporarily disable a subproject.
|
||||
include 'android', 'core'
|
||||