Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions assets/test.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import me.stringdotjar.flixelgdx.Flixel
import me.stringdotjar.flixelgdx.graphics.FlixelState
import me.stringdotjar.flixelgdx.util.FlixelPathsUtil
import me.stringdotjar.flixelgdx.graphics.sprite.FlixelSprite
import me.stringdotjar.polyverse.menus.TitleState
import me.stringdotjar.polyverse.script.type.SystemScript

class TestScript extends SystemScript {
Expand Down Expand Up @@ -62,5 +63,9 @@ class TestState extends FlixelState {
@Override
void update(float delta) {
super.update(delta)

if (Flixel.keyJustPressed(Input.Keys.SPACE)) {
Flixel.switchState(new TitleState())
}
}
}
2 changes: 1 addition & 1 deletion flixelgdx/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ dependencies {
api "com.github.tommyettinger:anim8-gdx:$anim8Version"
api "com.github.tommyettinger:libgdx-utils:$utilsVersion"
api "games.rednblack.miniaudio:miniaudio:$miniaudioVersion"
api "org.fusesource.jansi:jansi:$jansiVersion"

implementation "org.fusesource.jansi:jansi:$jansiVersion"
implementation "org.jetbrains:annotations:26.1.0"

if (enableGraalNative == 'true') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ public static MASound playSound(@NotNull String path, float volume, boolean loop
* outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
* regular string (without {@code assets/} at the beginning).
*/
public static void playMusic(String path) {
playMusic(path, 1, true, false);
public static MASound playMusic(String path) {
return playMusic(path, 1, true, false);
}

/**
Expand All @@ -262,8 +262,8 @@ public static void playMusic(String path) {
* regular string (without {@code assets/} at the beginning).
* @param volume The volume to play the new music with.
*/
public static void playMusic(String path, float volume) {
playMusic(path, volume, true, false);
public static MASound playMusic(String path, float volume) {
return playMusic(path, volume, true, false);
}

/**
Expand All @@ -283,8 +283,8 @@ public static void playMusic(String path, float volume) {
* @param volume The volume to play the new music with.
* @param looping Should the new music loop indefinitely?
*/
public static void playMusic(String path, float volume, boolean looping) {
playMusic(path, volume, looping, false);
public static MASound playMusic(String path, float volume, boolean looping) {
return playMusic(path, volume, looping, false);
}

/**
Expand All @@ -307,7 +307,7 @@ public static void playMusic(String path, float volume, boolean looping) {
* @param looping Should the new music loop indefinitely?
* @param external Should this music be loaded externally? (This is only for mobile platforms!)
*/
public static void playMusic(String path, float volume, boolean looping, boolean external) {
public static MASound playMusic(String path, float volume, boolean looping, boolean external) {
Signals.preMusicPlayed.dispatch(new MusicPlayedSignalData(music));
if (music != null) {
music.stop();
Expand All @@ -318,6 +318,7 @@ public static void playMusic(String path, float volume, boolean looping, boolean
music.setLooping(looping);
music.play();
Signals.postMusicPlayed.dispatch(new MusicPlayedSignalData(music));
return music;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,29 @@ public void update(float elapsed) {
stage.act(elapsed);
FlixelTween.getGlobalManager().update(elapsed);

FlixelState state = Flixel.getState();
state.update(elapsed);
// Walk the state/substate chain. Each state in the chain is updated only
// if it is the active (innermost) state, or if its persistentUpdate flag is true.
FlixelState current = Flixel.getState();
while (current != null) {
FlixelState sub = current.getSubState();
boolean hasSubState = (sub != null);

if (!hasSubState || current.persistentUpdate) {
current.update(elapsed);

SnapshotArray<FlixelBasic> members = current.getMembers();
FlixelBasic[] items = members.begin();
for (int j = 0; j < members.size; j++) {
FlixelBasic item = items[j];
if (item != null) {
item.update(elapsed);
}
}
members.end();
}

state.getMembers().forEach(member -> member.update(elapsed));
current = sub;
}

// Update all cameras.
FlixelCamera[] cams = cameras.begin();
Expand All @@ -283,11 +302,10 @@ public void draw() {

ScreenUtils.clear(Color.BLACK);

// Loop through all cameras and draw the current state's members onto their set cameras.
FlixelCamera[] cams = cameras.begin();
FlixelState state = Flixel.getState();
SnapshotArray<FlixelBasic> members = state.getMembers();
FlixelBasic[] mbrs = members.begin();

// Loop through all cameras and draw the state/substate chain onto each camera.
FlixelCamera[] cams = cameras.begin();
for (int i = 0; i < cameras.size; i++) {
FlixelCamera camera = cams[i];
if (camera == null) {
Expand All @@ -297,30 +315,54 @@ public void draw() {
batch.setProjectionMatrix(camera.getCamera().combined);
batch.begin();

// Draw the background color first.
batch.setColor(state.getBgColor());
batch.draw(bgTexture, camera.x, camera.y, camera.getWorldWidth(), camera.getWorldHeight());
batch.setColor(Color.WHITE); // Set the batch color back to white so display objects aren't affected.

// Draw all the current screens members.
for (int j = 0; j < members.size; j++) {
FlixelBasic member = mbrs[j];
if (member == null) {
continue;
}
if (member instanceof FlixelObject m) {
// Check if the current sprite is in the visible part of the viewport.
// If it cannot be seen, then we don't draw the sprite to save performance.
if (camera.getCamera().frustum.boundsInFrustum(m.getX(), m.getY(), 0, m.getWidth(), m.getHeight(), 0)) {
m.draw(batch);
// Walk the state/substate chain. Each state is drawn only if it is the
// active (innermost) state, or if its persistentDraw flag is true.
FlixelState current = state;
while (current != null) {
FlixelState sub = current.getSubState();
boolean hasSubState = (sub != null);

if (!hasSubState || current.persistentDraw) {
batch.setColor(current.getBgColor());
batch.draw(bgTexture, camera.x, camera.y, camera.getWorldWidth(), camera.getWorldHeight());
batch.setColor(Color.WHITE);

SnapshotArray<FlixelBasic> members = current.getMembers();
FlixelBasic[] mbrs = members.begin();
for (int j = 0; j < members.size; j++) {
FlixelBasic member = mbrs[j];
if (member == null) {
continue;
}
if (member instanceof FlixelObject m) {
if (camera.getCamera().frustum.boundsInFrustum(m.getX(), m.getY(), 0, m.getWidth(), m.getHeight(), 0)) {
m.draw(batch);
}
}
}
members.end();
}

current = sub;
}

batch.end();
}
cameras.end();
members.end();
state.draw(batch);

// Call user draw hooks for each state in the chain.
FlixelState drawHook = state;
while (drawHook != null) {
FlixelState sub = drawHook.getSubState();
boolean hasSubState = (sub != null);

if (!hasSubState || drawHook.persistentDraw) {
drawHook.draw(batch);
}

drawHook = sub;
}

stage.draw();

Flixel.Signals.postDraw.dispatch();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,34 @@
/**
* Base class for creating a better screen display with more functionality than the default {@link
* com.badlogic.gdx.Screen} interface.
*
* <p>A {@code FlixelState} can open a {@link FlixelSubState} on top of itself.
* By default, when a substate is active the parent state will continue to be drawn
* ({@link #persistentDraw} = {@code true}) but will stop updating
* ({@link #persistentUpdate} = {@code false}).
*
* @see <a href="https://api.haxeflixel.com/flixel/FlxState.html">FlxState (HaxeFlixel)</a>
*/
public abstract class FlixelState extends FlixelGroup<FlixelBasic> implements Screen {

/** Should {@code this} screen update its logic even when a substate is currently opened? */
/** Should {@code this} state update its logic even when a substate is currently opened? */
public boolean persistentUpdate = false;

/** Should {@code this} screen draw its members even when a substate is currently opened? */
/** Should {@code this} state draw its members even when a substate is currently opened? */
public boolean persistentDraw = true;

/** The background color of {@code this} current screen. */
/**
* If substates get destroyed when they are closed. Setting this to {@code false} might
* reduce state creation time, at the cost of greater memory usage.
*/
public boolean destroySubStates = true;

/** The background color of {@code this} current state. */
protected Color bgColor;

/** The currently active substate opened on top of {@code this} state. */
private FlixelSubState subState;

public FlixelState() {
super(0);
}
Expand All @@ -31,33 +47,95 @@ public final void show() {}
public final void render(float delta) {}

/**
* Called when the screen is first created. This is where you want to assign your
* sprites and setup everything your screen uses!
*
* Called when the state is first created. This is where you want to assign your
* sprites and setup everything your state uses!
*
* <p>Make sure to override this, NOT the constructor!
*/
public void create() {}

/**
* Updates the logic of {@code this} screen.
* Updates the logic of {@code this} state.
*
* @param delta The amount of time that occurred since the last frame.
*/
public void update(float delta) {
if (!persistentUpdate) {
return;
}
}
public void update(float delta) {}

/**
* Draws {@code this} state's members onto the screen.
*
* @param batch The batch that's used to draw {@code this} state's members.
*/
public void draw(Batch batch) {
if (!persistentDraw) {
public void draw(Batch batch) {}

/**
* Opens a {@link FlixelSubState} on top of {@code this} state. If there is already
* an active substate, it will be closed first.
*
* @param subState The substate to open.
*/
public void openSubState(FlixelSubState subState) {
if (subState == null) {
return;
}
if (this.subState == subState) {
return;
}
if (this.subState != null) {
closeSubState();
}

this.subState = subState;
subState.parentState = this;
subState.create();

if (subState.openCallback != null) {
subState.openCallback.run();
}
}

/**
* Closes the currently active substate, if one exists.
*/
public void closeSubState() {
if (subState == null) {
return;
}
FlixelSubState closing = subState;
subState = null;
closing.parentState = null;

if (closing.closeCallback != null) {
closing.closeCallback.run();
}
if (destroySubStates) {
closing.dispose();
}
}

/**
* Reloads the current substate's parent reference. Called internally after state
* transitions to ensure the parent link is correct.
*/
public void resetSubState() {
if (subState != null) {
subState.parentState = this;
}
}

/**
* Called from {@link me.stringdotjar.flixelgdx.Flixel#switchState(FlixelState)} before
* the actual state switch happens. Override this to play an exit animation or transition,
* then call {@code onOutroComplete} when finished.
*
* <p>The default implementation calls {@code onOutroComplete} immediately.
*
* @param onOutroComplete Callback to invoke when the outro is complete.
*/
public void startOutro(Runnable onOutroComplete) {
if (onOutroComplete != null) {
onOutroComplete.run();
}
}

@Override
Expand All @@ -73,12 +151,15 @@ public void resume() {}
public void hide() {}

/**
* Disposes {@code this} state and all of its members. Called automatically when {@link
* me.stringdotjar.flixelgdx.Flixel#switchState(FlixelState)} is used, so that sprites and other
* objects release their resources.
* Disposes {@code this} state, any active substate, and all members. Called automatically
* when {@link me.stringdotjar.flixelgdx.Flixel#switchState(FlixelState)} is used, so that
* sprites and other objects release their resources.
*/
@Override
public void dispose() {
if (subState != null) {
closeSubState();
}
if (members == null) {
return;
}
Expand All @@ -94,17 +175,22 @@ public void dispose() {
}

/**
* Adds a new object to {@code this} screen. If it is {@code null}, it will not be added and
* Adds a new object to {@code this} state. If it is {@code null}, it will not be added and
* simply ignored.
*
* @param object The object to add to the screen.
* @param object The object to add to the state.
*/
public void add(FlixelBasic object) {
if (object != null) {
members.add(object);
}
}

/** Returns the currently active substate, or {@code null} if none is open. */
public FlixelSubState getSubState() {
return subState;
}

public Color getBgColor() {
return (bgColor != null) ? bgColor : Color.BLACK;
}
Expand Down
Loading