Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ideas for battery life / performance improvements #141

Open
mjaun opened this issue Sep 24, 2018 · 8 comments
Open

Ideas for battery life / performance improvements #141

mjaun opened this issue Sep 24, 2018 · 8 comments

Comments

@mjaun
Copy link
Owner

mjaun commented Sep 24, 2018

Main issue for ideas to optimize the game performance.

@Mannshoch
Copy link

I do not know how to develop an app. But how do you handle the audio for a shoot? it sounds nice the first time but after a while i deactivate it. But does the sound also is not anymore calculated? because I do not see any difference if sound is active or not. On a huge amount of attackers the audio overhead may plays his part here.

@zz-ha-dum
Copy link

Disable UI after setting up level. Simply have lives totaled. Ui resumes for additional configuration

now the "game" is as much "fun" as a baseball game summary matrix in a newspaper.

@blackboxlogic
Copy link

Don't play audio if the device is muted (or volume is at 0).

@rigao1981
Copy link

I would also propose not to display every little bullet once the game is accelerated.

@easyaspi314
Copy link
Contributor

easyaspi314 commented Mar 7, 2022

In addition to my fixes in #200, here is an idea to improve the collision detection algorithm, which is the majority of the runtime on the logic thread.

The current approach to collision checking is pretty inefficient. The functional filter iterators are quite clever, but they still have to iterate through each element.

Healing, aiming, and glue are the largest bottlenecks in typical play. These check every entity every time they are applied, and that adds up quickly once you get to the hundreds of thousands of enemies.

image

Note that this is with #200 applied and measuring thread time. If you include sleeping, it is active 36% of the time.

One way of improving this would be to sort the entity map up by region to avoid even thinking about entities that are clearly not applicable. This could easily be done by splitting it via the visual grid.

Moving an entity would be slightly more complex as a case for moving between cells would need to be made.

image

Glue towers should be a special case. They are everywhere in current meta, and basically affect the floor only. Therefore, the map could theoretically be divided up into a (more fine than the rough hitbox) grid with each cell having a speed modifier.

@easyaspi314
Copy link
Contributor

easyaspi314 commented Mar 17, 2022

To expand on the previous, I believe a decent data structure would be ArrayList<HashSet<Entity>>.

An iterator could use a set of cells to filter, and box an iterator for each HashSet, jumping to the next one if that is empty. Then, some function in this entity list class can use some math to find the possible cells for either a radius (e.g. aiming) or a vector (e.g. big laser).

private ArrayList... mEntities;
class FilteredEntityIterator ... {
    private ArrayList<Integer> mIndices;
    private int mIndicesPos;
    private Iterator<Entity> mCurrentSubIterator;
    public boolean hasNext() {
        if (mCurrentSubIterator.hasNext()) {
            return true;
        } else {
            // Set mCurrentSubIterator to the first mEntities[mIndices[mIndicesPos]]
            // that isn't empty, or return false
        }
    }
}

Something like this (only iterating the first few because I don't want to animate all those squares 😛)
The yellow is mIndices, red is mIndicesPos, and green is mCurrentSubIterator.

Only 22% of the cells are checked, instead of all of them.
20220317_195734 (1).gif

The yellow box could probably be calculated using the Midpoint Formula and cached for towers.

This would improve performance even more than the tweaks I made in #200, as this would reduce the constant factor of collision checking greatly.

@easyaspi314
Copy link
Contributor

While collision detection is the biggest issue, here are some other performance issues I noticed.

  • The game should pause the tick loop (and possibly re-enable screen timeout) if there are no active waves. This not only makes logical sense, but also indirectly acts as a courtesy feature to avoid draining battery if you go AFK.
  • There seems to be a few more instances of lists being used as sets that I missed.
  • Enemy counting is very inefficient.
    • In large explosions with a lot of kills, the UI thread lags. This is due to the callback chains calling setText() in HeaderFragment for each enemy killed, which has the very expensive side effect of recalculating the layout boundaries (onMeasure()). This should only happen once a frame.
    • Why does getRemainingEnemiesReward count each time? The callbacks are there, just subtract when an enemy is defeated.
    • Resetting or loading a game will actually update the scoreboard for each enemy which turns a near-instant action to a 10+ second action if you are at a high level. It should just clear everything without firing any listeners. (Also, EntityStore has a quadratic list removal loop instead of calling clear() after the loop)

Flame chart for resetting a large game:
image
image

@mjaun
Copy link
Owner Author

mjaun commented Mar 29, 2022

Thank you very much for your thorough investigations! Unfortunately I currently don't find time to do such refactorings on this project. But maybe somebody else will. I think the points you made do all make sense, especially since it is backed by your measurements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants