Commit 8de5c691 authored by Nico Eckes's avatar Nico Eckes

intermediatePost

parent 57091560
package io.ender.pathchaser
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.*
import android.os.SystemClock.sleep
import android.util.DisplayMetrics
import android.view.MotionEvent
import android.view.SurfaceHolder
......@@ -15,28 +12,25 @@ import io.ender.pathchaser.util.intersects
import java.io.Serializable
@SuppressLint("ViewConstructor")
class Game(private val gameActivity: GameActivity, val options: GameOptions) : SurfaceView(gameActivity),
class Game(@Transient private val gameActivity: GameActivity, val options: GameOptions) : SurfaceView(gameActivity),
SurfaceHolder.Callback, Serializable {
@Transient
lateinit var gameThread: GameThread
var gameThread: GameThread? = null
var ticks = 0
private set
var collectedCoins = 0
private lateinit var pathManager: PathManager
private lateinit var player: Player
var size = PointF().apply {
DisplayMetrics().also { gameActivity.windowManager.defaultDisplay.getMetrics(it) }
@Transient
val size = PointF().apply {
DisplayMetrics().also { gameActivity.windowManager.defaultDisplay.getRealMetrics(it) }
.let { set(it.widthPixels.toFloat(), it.heightPixels.toFloat()) }
}
var speed: Float = options.difficulty.initialSpeed
var background = Color.BLACK
var invincibleStart = 0
private var highscore: Int = 0
get() {
field = collectedCoins * Constants.pointsCoinSimple + (ticks * 6) / Constants.maxFPS
return field
}
var gameover = false
private var background = Color.BLACK
private val highscore
get() = collectedCoins * Constants.pointsCoinSimple + (ticks * 6) / Constants.targetFPS //????
init {
holder.addCallback(this)
......@@ -45,8 +39,6 @@ class Game(private val gameActivity: GameActivity, val options: GameOptions) : S
}
override fun surfaceCreated(surfaceHolder: SurfaceHolder) {
gameThread = GameThread(holder, this)
if (!(this::pathManager.isInitialized))
pathManager = PathManager(this)
if (!(this::player.isInitialized)) {
......@@ -54,40 +46,39 @@ class Game(private val gameActivity: GameActivity, val options: GameOptions) : S
player.setPos((width / 2).toFloat(), (height / 2).toFloat())
pathManager.player = player
}
gameThread.computeFrame()
gameThread?.computeFrame()
}
override fun surfaceChanged(surfaceHolder: SurfaceHolder, format: Int, width: Int, height: Int) = Unit
override fun surfaceDestroyed(surfaceHolder: SurfaceHolder) {
gameThread.interrupt()
gameThread?.interrupt()
}
@SuppressLint("ClickableViewAccessibility" /* performClick would be useless */)
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
if (!gameover)
if (!gameThread.isAlive) {
if (player.intersects(Path().apply {
addRect(
event.x,
event.y,
event.x + 1,
event.y + 1,
Path.Direction.CW
)
}))
gameThread = GameThread(holder, this).apply { start() }
} else {
player.setPos(event.x, event.y - 40)
if (gameThread?.paused != false) {
if (player.intersects(Path().apply {
addRect(
event.x,
event.y,
event.x + 1,
event.y + 1,
Path.Direction.CW
)
})) {
player.setTouchPos(event.x, event.y)
gameThread?.paused = false
}
} else {
player.setTouchPos(event.x, event.y)
}
}
MotionEvent.ACTION_UP -> {
gameThread.stopGame()
gameThread.interrupt()
player.setPos(event.x, event.y - 40)
gameThread?.paused = true
player.setTouchPos(event.x, event.y)
}
}
return true
......@@ -100,6 +91,8 @@ class Game(private val gameActivity: GameActivity, val options: GameOptions) : S
speed += options.difficulty.speedPerSecond
if (player.invincible)
blink()
ticks++
}
override fun draw(canvas: Canvas) {
......@@ -120,8 +113,8 @@ class Game(private val gameActivity: GameActivity, val options: GameOptions) : S
})
canvas.drawRect(RectF(0f, size.y - 10, size.x, size.y).apply { }, Paint().apply { color = Color.BLACK })
if (player.invincible) {
val timePassed = ticks - invincibleStart
val steps = size.x / (Constants.invincibleSec * Constants.maxFPS)
val timePassed = ticks - player.invincibleStart
val steps = size.x / (Constants.invincibleSec * Constants.targetFPS)
canvas.drawRect(
RectF(0f, size.y - 8, size.x - timePassed * steps, size.y).apply { },
Paint().apply { color = Color.RED })
......@@ -131,9 +124,9 @@ class Game(private val gameActivity: GameActivity, val options: GameOptions) : S
data class GameOptions(val difficulty: Constants.Difficulty) : Serializable
private fun blink() {
if (ticks % (Constants.maxFPS * Constants.blinkMs / 1000).toInt() == 0) {
if (ticks % (Constants.targetFPS * Constants.blinkMs / 1000).toInt() == 0) {
val iteration =
(ticks - invincibleStart - ((ticks - invincibleStart) % Constants.maxFPS)) / Constants.maxFPS
(ticks - player.invincibleStart - ((ticks - player.invincibleStart) % Constants.targetFPS)) / Constants.targetFPS
if (iteration < Constants.invincibleSec) {
background = if ((iteration + 1) % 2 == 0) Constants.blinkColor else Color.BLACK
} else {
......@@ -143,12 +136,8 @@ class Game(private val gameActivity: GameActivity, val options: GameOptions) : S
}
}
fun gameThreadInitialized() = this::gameThread.isInitialized
fun gameEnd() {
gameover = true
sleep(200)
gameThread?.interrupt()
gameActivity.runOnUiThread {
EndGameDialog.show(gameActivity, highscore)
}
......
package io.ender.pathchaser
import android.graphics.PointF
import android.os.Bundle
import android.os.PersistableBundle
import android.util.DisplayMetrics
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import io.ender.pathchaser.util.Preferences
......@@ -13,46 +10,32 @@ class GameActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
game = Game(
this,
Game.GameOptions(Preferences.difficulty)
)
game = Game(this, Game.GameOptions(Preferences.difficulty))
setContentView(game)
}
override fun onPause() {
super.onPause()
game.gameThread.stopGame()
game.gameThread?.interrupt()
game.gameThread = null
}
override fun onResume() {
super.onResume()
if (this::game.isInitialized) {
if (game.gameThreadInitialized()) {
if (game.gameThread.isAlive)
game.gameThread.stopGame()
game.gameThread = GameThread(game.holder, game)
}
} else {
game = Game(
this,
Game.GameOptions(Preferences.difficulty)
)
setContentView(game)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putSerializable("game", game)
}
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
outState?.putSerializable("game", game)
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
game = savedInstanceState.get("game") as Game
}
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
super.onRestoreInstanceState(savedInstanceState)
game = savedInstanceState?.get("game") as Game
override fun onResume() {
super.onResume()
game.gameThread = GameThread(game.holder, game)
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
override fun onWindowFocusChanged(hasFocus: Boolean) { // fullscreen trick
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
......@@ -62,9 +45,5 @@ class GameActivity : AppCompatActivity() {
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
}
game.size = PointF().apply {
DisplayMetrics().also { windowManager.defaultDisplay.getRealMetrics(it) }
.let { set(it.widthPixels.toFloat(), it.heightPixels.toFloat()) }
}
}
}
......@@ -2,55 +2,54 @@ package io.ender.pathchaser
import android.view.SurfaceHolder
import io.ender.pathchaser.util.Constants
import java.util.*
class GameThread(private val surfaceholder: SurfaceHolder, private val game: Game) : Thread() {
private var maxfps = Constants.maxFPS
private var running = true
private var start: Double = 0.0
private var waitTime: Double = 0.0
var frameCount = 0
var totalTime = 0.0
private var time: Double = 0.0
private val targetTime = (1000 / maxfps).toDouble()
companion object {
private const val targetTime = (1000 / Constants.targetFPS)
}
var paused = true
init {
name = "PathChaser Game thread"
computeFrame()
start()
}
override fun run() {
start = System.currentTimeMillis().toDouble()
while (running && !game.gameover)
computeFrame()
while (true) computeFrame()
}
fun computeFrame() {
val canvas = surfaceholder.lockCanvas()
if (canvas != null) {
try {
synchronized(canvas) {
game.update()
game.draw(canvas)
val start = System.currentTimeMillis()
if (!paused) {
val canvas = surfaceholder.lockCanvas()
if (canvas != null) {
try {
synchronized(canvas) {
game.update()
game.draw(canvas)
}
} catch (e: Exception) {
e.printStackTrace()
}
} catch (e: Exception) {
e.printStackTrace()
surfaceholder.unlockCanvasAndPost(canvas)
}
surfaceholder.unlockCanvasAndPost(canvas)
}
time = System.currentTimeMillis() - start
waitTime = targetTime - time
try {
if (waitTime > 0) {
Thread.sleep(waitTime.toLong())
val waitTime = targetTime - (System.currentTimeMillis() - start)
println("${Date()},$waitTime")
if (waitTime > 0) {
try {
Thread.sleep(waitTime)
} catch (e: InterruptedException) {
return
}
} catch (e: InterruptedException) {
return
}
totalTime += System.currentTimeMillis() - start
frameCount = (frameCount + 1) % maxfps
game.ticks++
}
fun stopGame() {
running = false
}
}
......@@ -13,15 +13,21 @@ class Player(pm: PathManager) : Sprite(pm) {
set(value) {
if (!invincible)
if (lives > 1) {
invincible = true
pm.game.invincibleStart = pm.game.ticks
field = value
invincible = true
} else {
field = 0
thread { pm.game.gameEnd() }
}
}
var invincible = false
var invincibleStart = -1
private set
var invincible: Boolean
get() = invincibleStart >= 0
set(value) {
invincibleStart = if (value) pm.game.ticks else -1
}
lateinit var pos: PointF
val shields: MutableCollection<Shields> = mutableSetOf()
......@@ -37,6 +43,8 @@ class Player(pm: PathManager) : Sprite(pm) {
pos = PointF(x, y)
}
fun setTouchPos(x: Float, y: Float) = setPos(x + Constants.playerOffset.x, y + Constants.playerOffset.y)
override fun getPaint(): Paint {
val paint = Paint()
paint.color = if (isOnPath()) Color.GREEN else Color.RED.apply { this@Player.lives-- }
......
package io.ender.pathchaser.util
import android.graphics.Color
import android.graphics.PointF
import io.ender.pathchaser.R
import splitties.resources.appStr
......@@ -11,9 +12,10 @@ object Constants {
const val pointsCoinSimple = 100
const val blinkMs = 300L
const val invincibleSec = 4
const val maxFPS = 30
const val targetFPS = 30
const val blinkColor = Color.RED
const val maxTrackedHighscoreCount = 30
val playerOffset: PointF = PointF(0f, -40f)
object ExtensionPercentages {
const val arc = 0.25
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment