Skip to content

Commit

Permalink
Feature/save game state (#38)
Browse files Browse the repository at this point in the history
* fix issue that player does not enter fall state anymore

* add SaveSystem to store player progress (first draft)

* fix some issues with savesystem

- entities of a map are now correctly loaded again
- tutorialsystem runs before the savesystem to correctly store the tutorial progress
- fix issue that the fireball skill was added multiple times to the game HUD

* fix falling state of player. It is now only entered if the player is really falling down

* add trigger conditions to run triggers only under certain conditions

* adds TmxMapComponent to portal targets

* fix issue that fireball icon was not correctly set when loading a savestate

* fix preference name

* save game when changing maps

* add debug message to analyze entity cache when changing maps

* add new trigger to reactivate portal when boss is already dead

* add support for loading a previous save state

* add new widgets to go back from game to menu screen (android support)

* fix issue that fireball was not correctly saved/loaded

* ignore android release build folder
  • Loading branch information
Quillraven authored Mar 29, 2020
1 parent 43b4cc4 commit fc947b5
Show file tree
Hide file tree
Showing 23 changed files with 630 additions and 112 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,4 @@ Thumbs.db
/buildSrc/build/

android/local.properties
/android/release/
7 changes: 6 additions & 1 deletion assets/map/map2.tmx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.3.1" orientation="orthogonal" renderorder="right-up" compressionlevel="0" width="32" height="96" tilewidth="16" tileheight="16" infinite="0" nextlayerid="35" nextobjectid="116">
<map version="1.2" tiledversion="1.3.2" orientation="orthogonal" renderorder="right-up" compressionlevel="0" width="32" height="96" tilewidth="16" tileheight="16" infinite="0" nextlayerid="35" nextobjectid="117">
<tileset firstgid="1" source="tilesets.tsx"/>
<layer id="28" name="bgd0" width="32" height="96">
<data encoding="base64" compression="zlib">
Expand Down Expand Up @@ -153,5 +153,10 @@
<property name="TriggerReactOnCollision" type="bool" value="true"/>
</properties>
</object>
<object id="116" name="TriggerMap2.setupAfterBoss" x="76.25" y="1299.83" width="49.5" height="31">
<properties>
<property name="TriggerReactOnCollision" type="bool" value="false"/>
</properties>
</object>
</objectgroup>
</map>
7 changes: 7 additions & 0 deletions assets/ui/i18n.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
armor=Armor
backToMenu.info=Do you really want to go back to the menu? Your progress will be lost until the last \
checkpoint that you have reached or until the last map that you have entered.
Boss1Dialog1.1=[BROWN]Minotaur[]: Who is there?\n\
[RED]Quilly[]: Are you the one who kidnapped my girlfriend?\n\
[BROWN]Minotaur[]: *harharhar*, then you are the little worm of whom the girl was talking about all the time.
Expand All @@ -16,6 +18,9 @@ Time to continue your search!
Boss1Dialog3.2=This is already the end of version one of Quilly's Adventure.\n\
If you enjoyed it then please let me know at [RED][email protected][].\n\
Thanks for playing!
clearGameState.info=You already started a game before. If you want to continue the game please click on \
[RED]Continue[] in the menu. If you want to start a new game and delete your old \
progress then click on [RED]Yes[].
continue=Continue
credits=Credits
credits.info=Special thanks to [RED]DRSchlaubi[] for his great assistance throughout the project with Kotlin and Gradle.\
Expand Down Expand Up @@ -56,6 +61,7 @@ map.name.MAP1=Path to cave
map.name.MAP2=Cave
music=Music
newGame=New Game
no=No
quitGame=Quit Game
requiresLvl3=requires Level 3
skills=[BROWN]Skills[]
Expand Down Expand Up @@ -94,3 +100,4 @@ Use the attack button or CTRL key to make Quilly [RED]attack[].\n\n\
Be careful of the blue slimes ahead! They will attack you.
xp=Experience
xpAbbreviation=XP
yes=Yes
7 changes: 7 additions & 0 deletions assets/ui/i18n_de.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
armor=Rüstung
backToMenu.info=Willst du wirklich zurück ins Menü? Dein Fortschritt ist verloren bis zum letzten \
Speicherpunkt oder zur letzten Karte, die du betreten hast.
Boss1Dialog1.1=[BROWN]Minotaure[]: Schau an, wen haben wir denn da?\n\
[RED]Quilly[]: Bist du derjenige, der meine Freundin entführt hat?\n\
[BROWN]Minotaure[]: *harharhar*, dann bist du also der kleine Wurm, von dem \
Expand All @@ -16,6 +18,9 @@ Zeit, deine Suche fortzusetzen!
Boss1Dialog3.2=Dies ist leider bereits schon das Ende von der ersten Version von Quilly's Abenteuer.\n\
Wenn es dir Spaß gemacht hat, dann lass es mich bitte unter [RED][email protected][] wissen.\n\
Vielen Dank fürs Spielen!
clearGameState.info=Du hast bereits ein Spiel begonnen. Wenn du es fortsetzen möchtest, dann klicke bitte auf \
[RED]Fortsetzen[] im Menü. Wenn du ein neues Spiel beginnen möchtest und den aktuellen \
Fortschritt löschen möchtest, dann klicke auf [RED]Ja[].
continue=Fortfahren
credits=Danksagungen
credits.info=Ein besonderes Dankeschön geht an [RED]DRSchlaubi[] für seine großartige Unterstützung während des ganzen Projektes mit Kotlin und Gradle. \
Expand Down Expand Up @@ -59,6 +64,7 @@ map.name.MAP1=Weg zur Höhle
map.name.MAP2=Höhle
music=Musik
newGame=Neues Spiel
no=Nein
quitGame=Spiel Beenden
requiresLvl3=benötigt Stufe 3
skills=[BROWN]Fähigkeiten[]
Expand Down Expand Up @@ -97,3 +103,4 @@ Benutze den Angriffsknopf oder STRG um [RED]anzugreifen[].\n\n\
Hüte dich vor den blauen Schleimen! Sie werden dich angreifen.
xp=Erfahrung
xpAbbreviation=ERF
yes=Ja
7 changes: 7 additions & 0 deletions assets/ui/i18n_en.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
armor=Armor
backToMenu.info=Do you really want to go back to the menu? Your progress will be lost until the last \
checkpoint that you have reached or until the last map that you have entered.
Boss1Dialog1.1=[BROWN]Minotaur[]: Who is there?\n\
[RED]Quilly[]: Are you the one who kidnapped my girlfriend?\n\
[BROWN]Minotaur[]: *harharhar*, then you are the little worm of whom the girl was talking about all the time.
Expand All @@ -16,6 +18,9 @@ Time to continue your search!
Boss1Dialog3.2=This is already the end of version one of Quilly's Adventure.\n\
If you enjoyed it then please let me know at [RED][email protected][].\n\
Thanks for playing!
clearGameState.info=You already started a game before. If you want to continue the game please click on \
[RED]Continue[] in the menu. If you want to start a new game and delete your old \
progress then click on [RED]Yes[].
continue=Continue
credits=Credits
credits.info=Special thanks to [RED]DRSchlaubi[] for his great assistance throughout the project with Kotlin and Gradle.\
Expand Down Expand Up @@ -56,6 +61,7 @@ map.name.MAP1=Path to cave
map.name.MAP2=Cave
music=Music
newGame=New Game
no=No
quitGame=Quit Game
requiresLvl3=requires Level 3
skills=[BROWN]Skills[]
Expand Down Expand Up @@ -94,3 +100,4 @@ Use the attack button or CTRL key to make Quilly [RED]attack[].\n\n\
Be careful of the blue slimes ahead! They will attack you.
xp=Experience
xpAbbreviation=XP
yes=Yes
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ private val LOG = logger<Main>()

const val VIRTUAL_W = 1280
const val VIRTUAL_H = 720
private const val PREF_NAME = "quilly-jumper"
private const val PREF_NAME = "quilly-adventure"
const val UNIT_SCALE = 1 / 32f
const val FIXTURE_TYPE_FOOT_SENSOR = 1
const val FIXTURE_TYPE_AGGRO_SENSOR = 2 shl 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ class PhysicContactListener : ContactListener {
* time to time and entities are not 100% cleaned removed at that time.
* Therefore two additional checks are added that it is really a relevant **collision entity** with a certain **type**.
*/
private fun isRemoved(entity: Entity) =
entity.isRemoved() || entity[CollisionComponent.mapper] == null || entity[EntityTypeComponent.mapper] == null
private fun isRemoved(srcEntity: Entity, collEntity: Entity) =
srcEntity.isRemoved() || collEntity.isRemoved()
|| srcEntity[CollisionComponent.mapper] == null
|| collEntity[EntityTypeComponent.mapper] == null

/**
* @param srcFixture the fixture of the entity for which you want to update the collision data
Expand All @@ -56,7 +58,7 @@ class PhysicContactListener : ContactListener {
* @param collEntity the colliding entity from [endContact] method
*/
private fun removeCollisionData(srcFixture: Fixture, srcEntity: Entity, collFixture: Fixture, collEntity: Entity) {
if (isRemoved(srcEntity) || isRemoved(collEntity)) {
if (isRemoved(srcEntity, collEntity)) {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,27 @@ enum class PlayerState(
entity.attackCmp.order == AttackOrder.START -> changeState(ATTACK)
entity.jumpCmp.order == JumpOrder.JUMP -> changeState(JUMP)
entity.moveCmp.order != MoveOrder.NONE -> changeState(RUN)
entity.physicCmp.body.linearVelocity.y <= 0f && entity.collCmp.numGroundContacts == 0 ->
changeState(FALL)
isFalling(entity.physicCmp, entity.collCmp) -> changeState(FALL)
}
}
}
},
RUN(AnimationType.RUN) {
override fun update(entity: Entity) {
val velocity = entity.physicCmp.body.linearVelocity
val physicCmp = entity.physicCmp
val velocity = physicCmp.body.linearVelocity
with(entity.stateCmp.stateMachine) {
when {
entity.abilityCmp.order == CastOrder.BEGIN_CAST -> changeState(CAST)
entity.attackCmp.order == AttackOrder.START -> changeState(ATTACK)
entity.jumpCmp.order == JumpOrder.JUMP -> changeState(JUMP)
velocity.y <= 0f && entity.collCmp.numGroundContacts == 0 -> changeState(FALL)
isFalling(physicCmp, entity.collCmp) -> changeState(FALL)
entity.moveCmp.order == MoveOrder.NONE && abs(velocity.x) <= 0.5f -> changeState(IDLE)
}
}
}
},
JUMP(AnimationType.JUMP, Animation.PlayMode.NORMAL) {
private fun isFalling(physic: PhysicComponent, collision: CollisionComponent) =
physic.body.linearVelocity.y <= 0f && collision.numGroundContacts == 0

override fun update(entity: Entity) {
val collision = entity.collCmp
with(entity.stateCmp) {
Expand Down Expand Up @@ -134,5 +131,8 @@ enum class PlayerState(
super.exit(entity)
entity.aniCmp.animationSpeed = 1f
}
}
};

fun isFalling(physic: PhysicComponent, collision: CollisionComponent) =
physic.body.linearVelocity.y < 0f && collision.numGroundContacts == 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.github.quillraven.quillysadventure.ecs.component.RenderComponent
import com.github.quillraven.quillysadventure.ecs.component.StateComponent
import com.github.quillraven.quillysadventure.ecs.component.StatsComponent
import com.github.quillraven.quillysadventure.ecs.component.TakeDamageComponent
import com.github.quillraven.quillysadventure.ecs.component.TmxMapComponent
import com.github.quillraven.quillysadventure.ecs.component.TransformComponent
import com.github.quillraven.quillysadventure.ecs.component.TriggerComponent
import com.github.quillraven.quillysadventure.ecs.component.physicCmp
Expand Down Expand Up @@ -282,7 +283,13 @@ fun Engine.character(
}
}

fun Engine.item(cfg: ItemCfg, world: World, posX: Float, posY: Float): Entity {
fun Engine.item(
cfg: ItemCfg,
world: World,
posX: Float,
posY: Float,
compData: EngineEntity.() -> Unit = { Unit }
): Entity {
return this.entity {
// transform
with<TransformComponent> {
Expand Down Expand Up @@ -325,6 +332,8 @@ fun Engine.item(cfg: ItemCfg, world: World, posX: Float, posY: Float): Entity {
with<EntityTypeComponent> {
this.type = EntityType.ITEM
}

this.compData()
}
}

Expand Down Expand Up @@ -421,6 +430,9 @@ fun Engine.portalTarget(
with<PortalComponent> {
this.portalID = portalID
}
with<TmxMapComponent> {
id = portalID
}
}
}

Expand Down Expand Up @@ -463,6 +475,10 @@ fun Engine.portal(
this.targetOffsetX = targetOffsetX
this.targetPortal = targetPortal
}
// tmx map info
with<TmxMapComponent> {
id = portalID
}
}
}

Expand Down Expand Up @@ -600,6 +616,7 @@ fun Engine.missile(
}

fun Engine.trigger(
triggerID: Int,
triggerSetupFunctionName: String,
reactOnCollision: Boolean,
world: World,
Expand All @@ -626,6 +643,10 @@ fun Engine.trigger(
withDefaultStaticPhysic(world, shape)
with<CollisionComponent>()
}

with<TmxMapComponent> {
id = triggerID
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ class AbilityComponent : Component, Pool.Poolable {

fun canCast() = abilityToCastIdx >= 0 && abilityToCastIdx < abilities.size && abilities[abilityToCastIdx].canCast()

fun hasAbility(abilityEffect: AbilityEffect): Boolean {
abilities.forEach { ability ->
if (ability.effect == abilityEffect) {
return true
}
}
return false
}

fun addAbility(entity: Entity, abilityEffect: AbilityEffect) {
abilities.forEach { ability ->
if (ability.effect == abilityEffect) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.github.quillraven.quillysadventure.ecs.component

import com.badlogic.ashley.core.Component
import com.badlogic.gdx.utils.Pool

class SaveComponent : Component, Pool.Poolable {
override fun reset() = Unit
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.quillraven.quillysadventure.ecs.component

import com.badlogic.ashley.core.Component
import com.badlogic.gdx.utils.Pool
import ktx.ashley.mapperFor

class TmxMapComponent : Component, Pool.Poolable {
var id = -1

override fun reset() {
id = -1
}

companion object {
val mapper = mapperFor<TmxMapComponent>()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.github.quillraven.quillysadventure.ecs.component.CollisionComponent
import com.github.quillraven.quillysadventure.ecs.component.EntityType
import com.github.quillraven.quillysadventure.ecs.component.PlayerComponent
import com.github.quillraven.quillysadventure.ecs.component.RemoveComponent
import com.github.quillraven.quillysadventure.ecs.component.SaveComponent
import com.github.quillraven.quillysadventure.ecs.component.collCmp
import com.github.quillraven.quillysadventure.ecs.component.heal
import com.github.quillraven.quillysadventure.ecs.component.physicCmp
Expand All @@ -36,13 +37,13 @@ import ktx.log.logger
private val LOG = logger<PlayerCollisionSystem>()

class PlayerCollisionSystem(
private val mapManager: MapManager,
private val audioService: AudioService,
private val gameEventManager: GameEventManager,
private val bundle: I18NBundle
private val mapManager: MapManager,
private val audioService: AudioService,
private val gameEventManager: GameEventManager,
private val bundle: I18NBundle
) :
IteratingSystem(allOf(PlayerComponent::class, CollisionComponent::class).get()), MapChangeListener,
GameEventListener {
IteratingSystem(allOf(PlayerComponent::class, CollisionComponent::class).get()), MapChangeListener,
GameEventListener {
private val itemInfoBuilder = StringBuilder(64)
private var lastSavepoint: Entity? = null

Expand Down Expand Up @@ -78,6 +79,8 @@ class PlayerCollisionSystem(
}
} else {
mapManager.setMap(targetMap, targetPortal, targetOffsetX)
// and save the game
entity.add(engine.createComponent(SaveComponent::class.java))
}
// ignore any other collisions for that frame because the player got moved to a new map
return
Expand All @@ -97,6 +100,8 @@ class PlayerCollisionSystem(
// also heal the player
val stats = entity.statsCmp
entity.heal(engine, stats.maxLife, stats.maxMana)
// and save the game
entity.add(engine.createComponent(SaveComponent::class.java))
}
}
EntityType.TRIGGER -> {
Expand Down Expand Up @@ -139,14 +144,14 @@ class PlayerCollisionSystem(
// show information to player about the changed stats
with(player.transfCmp) {
engine.floatingText(
position.x,
position.y + size.y,
FontType.LARGE,
itemInfoBuilder,
Color.SCARLET,
0f,
-0.6f,
4f
position.x,
position.y + size.y,
FontType.LARGE,
itemInfoBuilder,
Color.SCARLET,
0f,
-0.6f,
4f
)
}

Expand Down
Loading

0 comments on commit fc947b5

Please sign in to comment.