v3.1.1: various stability improvements for low/inconsistent FPS:

- game now has a max delta time of 200ms
- added some checks to ensure non-looped animations do not complete twice
- adjusted 'enemy' reference in hero to 'attackTarget'
This commit is contained in:
Evan Debenham
2025-06-11 17:27:41 -04:00
parent 9fb18b3b45
commit b6dee52811
8 changed files with 32 additions and 30 deletions

View File

@@ -283,7 +283,9 @@ public class Game implements ApplicationListener {
}
protected void update() {
Game.elapsed = Game.timeScale * Gdx.graphics.getDeltaTime();
//game will not process more than 200ms of graphics time per frame
float frameDelta = Math.min(0.2f, Gdx.graphics.getDeltaTime());
Game.elapsed = Game.timeScale * frameDelta;
Game.timeTotal += Game.elapsed;
Game.realTime = TimeUtils.millis();

View File

@@ -63,9 +63,11 @@ public class MovieClip extends Image {
while (frameTimer > curAnim.delay) {
frameTimer -= curAnim.delay;
if (curFrame >= curAnim.frames.length - 1) {
curFrame = curAnim.frames.length - 1;
if (curAnim.looped) {
curFrame = 0;
} else {
curFrame = curAnim.frames.length - 1;
frameTimer = 0;
}
finished = true;
if (listener != null) {

View File

@@ -215,7 +215,8 @@ public class Hero extends Char {
public HeroAction curAction = null;
public HeroAction lastAction = null;
private Char enemy;
//reference to the enemy the hero is currently in the process of attacking
private Char attackTarget;
public boolean resting = false;
@@ -460,7 +461,7 @@ public class Hero extends Char {
public boolean shoot( Char enemy, MissileWeapon wep ) {
this.enemy = enemy;
attackTarget = enemy;
boolean wasEnemy = enemy.alignment == Alignment.ENEMY
|| (enemy instanceof Mimic && enemy.alignment == Alignment.NEUTRAL);
@@ -479,6 +480,7 @@ public class Hero extends Char {
Buff.affect( this, Sai.ComboStrikeTracker.class).addHit();
}
attackTarget = null;
return hit;
}
@@ -1373,15 +1375,15 @@ public class Hero extends Char {
private boolean actAttack( HeroAction.Attack action ) {
enemy = action.target;
attackTarget = action.target;
if (isCharmedBy( enemy )){
if (isCharmedBy(attackTarget)){
GLog.w( Messages.get(Charm.class, "cant_attack"));
ready();
return false;
}
if (enemy.isAlive() && canAttack( enemy ) && enemy.invisible == 0) {
if (attackTarget.isAlive() && canAttack(attackTarget) && attackTarget.invisible == 0) {
if (heroClass != HeroClass.DUELIST
&& hasTalent(Talent.AGGRESSIVE_BARRIER)
@@ -1393,26 +1395,29 @@ public class Hero extends Char {
Buff.affect(this, Talent.AggressiveBarrierCooldown.class, 50f);
}
sprite.attack( enemy.pos );
//attack target cleared on onAttackComplete
sprite.attack( attackTarget.pos );
return false;
} else {
if (fieldOfView[enemy.pos] && getCloser( enemy.pos )) {
if (fieldOfView[attackTarget.pos] && getCloser( attackTarget.pos )) {
attackTarget = null;
return true;
} else {
ready();
attackTarget = null;
return false;
}
}
}
public Char enemy(){
return enemy;
public Char attackTarget(){
return attackTarget;
}
public void rest( boolean fullRest ) {
@@ -2257,23 +2262,23 @@ public class Hero extends Char {
@Override
public void onAttackComplete() {
if (enemy == null){
if (attackTarget == null){
curAction = null;
super.onAttackComplete();
return;
}
AttackIndicator.target(enemy);
boolean wasEnemy = enemy.alignment == Alignment.ENEMY
|| (enemy instanceof Mimic && enemy.alignment == Alignment.NEUTRAL);
AttackIndicator.target(attackTarget);
boolean wasEnemy = attackTarget.alignment == Alignment.ENEMY
|| (attackTarget instanceof Mimic && attackTarget.alignment == Alignment.NEUTRAL);
boolean hit = attack( enemy );
boolean hit = attack(attackTarget);
Invisibility.dispel();
spend( attackDelay() );
if (hit && subClass == HeroSubClass.GLADIATOR && wasEnemy){
Buff.affect( this, Combo.class ).hit( enemy );
Buff.affect( this, Combo.class ).hit(attackTarget);
}
if (hit && heroClass == HeroClass.DUELIST && wasEnemy){
@@ -2281,6 +2286,7 @@ public class Hero extends Char {
}
curAction = null;
attackTarget = null;
super.onAttackComplete();
}

View File

@@ -48,7 +48,7 @@ public class AssassinsBlade extends MeleeWeapon {
public int damageRoll(Char owner) {
if (owner instanceof Hero) {
Hero hero = (Hero)owner;
Char enemy = hero.enemy();
Char enemy = hero.attackTarget();
if (enemy instanceof Mob && ((Mob) enemy).surprisedBy(hero)) {
//deals 50% toward max to max on surprise, instead of min to max.
int diff = max() - min();

View File

@@ -62,7 +62,7 @@ public class Dagger extends MeleeWeapon {
public int damageRoll(Char owner) {
if (owner instanceof Hero) {
Hero hero = (Hero)owner;
Char enemy = hero.enemy();
Char enemy = hero.attackTarget();
if (enemy instanceof Mob && ((Mob) enemy).surprisedBy(hero)) {
//deals 75% toward max to max on surprise, instead of min to max.
int diff = max() - min();

View File

@@ -48,7 +48,7 @@ public class Dirk extends MeleeWeapon {
public int damageRoll(Char owner) {
if (owner instanceof Hero) {
Hero hero = (Hero)owner;
Char enemy = hero.enemy();
Char enemy = hero.attackTarget();
if (enemy instanceof Mob && ((Mob) enemy).surprisedBy(hero)) {
//deals 67% toward max to max on surprise, instead of min to max.
int diff = max() - min();

View File

@@ -22,7 +22,6 @@
package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
@@ -39,18 +38,11 @@ public class Kunai extends MissileWeapon {
baseUses = 5;
}
private Char enemy;
@Override
protected void onThrow(int cell) {
enemy = Actor.findChar(cell);
super.onThrow(cell);
}
@Override
public int damageRoll(Char owner) {
if (owner instanceof Hero) {
Hero hero = (Hero)owner;
Char enemy = hero.attackTarget();
if (enemy instanceof Mob && ((Mob) enemy).surprisedBy(hero)) {
//deals 60% toward max to max on surprise, instead of min to max.
int diff = max() - min();

View File

@@ -50,7 +50,7 @@ public class ThrowingKnife extends MissileWeapon {
public int damageRoll(Char owner) {
if (owner instanceof Hero) {
Hero hero = (Hero)owner;
Char enemy = hero.enemy();
Char enemy = hero.attackTarget();
if (enemy instanceof Mob && ((Mob) enemy).surprisedBy(hero)) {
//deals 75% toward max to max on surprise, instead of min to max.
int diff = max() - min();