Начать этап 3 настройками управления

This commit is contained in:
2026-08-18 14:44:30 +03:00
parent 80822b74b1
commit 44067abde3
12 changed files with 492 additions and 22 deletions
@@ -0,0 +1,143 @@
package com.projectsacrifice.game;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
import android.os.SystemClock;
import android.view.MotionEvent;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public final class ControlSettingsPersistenceTest {
@Test
public void changedControlsSurviveActivityRecreation() {
try (ActivityScenario<MainActivity> activity = ActivityScenario.launch(MainActivity.class)) {
activity.onActivity(current -> current.gameViewForAutomation()
.resetControlSettingsForAutomation());
tap(activity, 1_700f, 115f);
activity.onActivity(current -> assertTrue(current.gameViewForAutomation()
.settingsVisibleForAutomation()));
tap(activity, 1_250f, 345f);
tap(activity, 1_250f, 515f);
tap(activity, 1_250f, 685f);
activity.recreate();
activity.onActivity(current -> {
ControlSettings settings = current.gameViewForAutomation()
.controlSettingsForAutomation();
assertEquals("Large", settings.controlSizeLabel());
assertEquals(1.2f, settings.controlScale(), 0f);
assertEquals("High", settings.controlOpacityLabel());
assertEquals(0.9f, settings.controlOpacity(), 0f);
assertFalse(settings.hapticsEnabled());
assertFalse(current.gameViewForAutomation().settingsVisibleForAutomation());
current.gameViewForAutomation().resetControlSettingsForAutomation();
});
}
}
@Test
public void largePresetExpandsTheRealTouchTarget() {
try (ActivityScenario<MainActivity> activity = ActivityScenario.launch(MainActivity.class)) {
activity.onActivity(current -> {
GameView view = current.gameViewForAutomation();
view.resetControlSettingsForAutomation();
view.startLevelForAutomation(1);
});
touch(activity, MotionEvent.ACTION_DOWN, 13f, 925f);
activity.onActivity(current -> assertFalse(current.gameViewForAutomation()
.automationSnapshot().inputActive()));
touch(activity, MotionEvent.ACTION_UP, 13f, 925f);
activity.onActivity(current -> current.gameViewForAutomation()
.selectNextControlSizeForAutomation());
touch(activity, MotionEvent.ACTION_DOWN, 13f, 925f);
activity.onActivity(current -> {
assertTrue(current.gameViewForAutomation().automationSnapshot().inputActive());
current.gameViewForAutomation().resetControlSettingsForAutomation();
});
touch(activity, MotionEvent.ACTION_UP, 13f, 925f);
}
}
@Test
public void heldJumpDoesNotRepeatAfterLanding() throws Exception {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
try (ActivityScenario<MainActivity> activity = ActivityScenario.launch(MainActivity.class)) {
GameView[] view = new GameView[1];
activity.onActivity(current -> {
view[0] = current.gameViewForAutomation();
view[0].startLevelForAutomation(1);
});
await(instrumentation, view[0], 1_000L,
GameView.AutomationSnapshot::playerOnGround);
instrumentation.runOnMainSync(
() -> view[0].setAutomationInput(false, false, true));
await(instrumentation, view[0], 2_000L,
snapshot -> snapshot.playerY() <= 700f);
await(instrumentation, view[0], 2_000L,
snapshot -> snapshot.playerOnGround() && snapshot.playerY() >= 779f);
Thread.sleep(350L);
GameView.AutomationSnapshot settled = snapshot(instrumentation, view[0]);
assertTrue("A held jump must not fire again after landing", settled.playerOnGround());
assertEquals(780f, settled.playerY(), 1f);
instrumentation.runOnMainSync(
() -> view[0].setAutomationInput(false, false, false));
}
}
private static void tap(ActivityScenario<MainActivity> activity, float canvasX, float canvasY) {
touch(activity, MotionEvent.ACTION_DOWN, canvasX, canvasY);
touch(activity, MotionEvent.ACTION_UP, canvasX, canvasY);
}
private static void touch(ActivityScenario<MainActivity> activity, int action,
float canvasX, float canvasY) {
activity.onActivity(current -> {
GameView view = current.gameViewForAutomation();
float scale = Math.min(view.getWidth() / 1_920f, view.getHeight() / 1_080f);
float x = (view.getWidth() - 1_920f * scale) * 0.5f + canvasX * scale;
float y = (view.getHeight() - 1_080f * scale) * 0.5f + canvasY * scale;
long now = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(now, now, action, x, y, 0);
view.dispatchTouchEvent(event);
event.recycle();
});
}
private static GameView.AutomationSnapshot await(
Instrumentation instrumentation, GameView view, long timeoutMillis,
LevelPlaytestBot.SnapshotCondition condition
) throws Exception {
long deadline = System.currentTimeMillis() + timeoutMillis;
GameView.AutomationSnapshot current = snapshot(instrumentation, view);
while (System.currentTimeMillis() < deadline) {
current = snapshot(instrumentation, view);
if (condition.reached(current)) return current;
Thread.sleep(32L);
}
throw new AssertionError("Control input timed out; x=" + current.playerX()
+ ", y=" + current.playerY() + ", input=" + current.inputActive());
}
private static GameView.AutomationSnapshot snapshot(
Instrumentation instrumentation, GameView view
) {
GameView.AutomationSnapshot[] value = new GameView.AutomationSnapshot[1];
instrumentation.runOnMainSync(() -> value[0] = view.automationSnapshot());
return value[0];
}
}