Начать этап 3 настройками управления
This commit is contained in:
@@ -38,7 +38,7 @@ public final class GameView extends View implements Runnable {
|
||||
private static final float RESPAWN_SECONDS = 0.78f;
|
||||
private static final int MAX_CORPSES = 16;
|
||||
|
||||
private enum Screen { LEVELS, PLAYING, COMPLETE }
|
||||
private enum Screen { LEVELS, SETTINGS, PLAYING, COMPLETE }
|
||||
private enum DeathType { SPIKE, SAW, FREEZE, ELECTRIC, PIT }
|
||||
|
||||
public static final class AutomationSnapshot {
|
||||
@@ -160,6 +160,7 @@ public final class GameView extends View implements Runnable {
|
||||
private final LinearGradient skyGradient = new LinearGradient(
|
||||
0, 0, 0, VIEW_HEIGHT, Color.rgb(20, 29, 55), Color.rgb(110, 81, 91), Shader.TileMode.CLAMP);
|
||||
private final ProgressStore progress;
|
||||
private final ControlSettingsStore controlSettingsStore;
|
||||
private final SparseArray<PointF> pointers = new SparseArray<>();
|
||||
private final Player player = new Player();
|
||||
private final ArrayList<Corpse> corpses = new ArrayList<>();
|
||||
@@ -185,10 +186,13 @@ public final class GameView extends View implements Runnable {
|
||||
private float canvasScale = 1f;
|
||||
private float canvasOffsetX;
|
||||
private float canvasOffsetY;
|
||||
private ControlSettings controlSettings;
|
||||
|
||||
public GameView(Context context) {
|
||||
super(context);
|
||||
progress = new ProgressStore(context);
|
||||
controlSettingsStore = new ControlSettingsStore(context);
|
||||
controlSettings = controlSettingsStore.load();
|
||||
paint.setTypeface(android.graphics.Typeface.create("sans", android.graphics.Typeface.NORMAL));
|
||||
stroke.setStyle(Paint.Style.STROKE);
|
||||
stroke.setStrokeCap(Paint.Cap.ROUND);
|
||||
@@ -227,6 +231,10 @@ public final class GameView extends View implements Runnable {
|
||||
|
||||
public boolean handleBack() {
|
||||
if (screen == Screen.LEVELS) return false;
|
||||
if (screen == Screen.SETTINGS) {
|
||||
screen = Screen.LEVELS;
|
||||
return true;
|
||||
}
|
||||
if (screen == Screen.COMPLETE) {
|
||||
screen = Screen.LEVELS;
|
||||
return true;
|
||||
@@ -315,11 +323,11 @@ public final class GameView extends View implements Runnable {
|
||||
boolean previous = Boolean.TRUE.equals(previousSwitchContact.get(contactKey));
|
||||
if (item.type == LevelDefinition.SwitchType.TOGGLE && contact && !previous) {
|
||||
toggleSignals.put(item.signalId, !Boolean.TRUE.equals(toggleSignals.get(item.signalId)));
|
||||
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
}
|
||||
if (item.type == LevelDefinition.SwitchType.TIMED && contact && !previous) {
|
||||
timedSignals.put(item.signalId, item.durationSeconds);
|
||||
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
}
|
||||
previousSwitchContact.put(contactKey, contact);
|
||||
}
|
||||
@@ -404,7 +412,7 @@ public final class GameView extends View implements Runnable {
|
||||
player.onGround = false;
|
||||
player.coyote = 0f;
|
||||
player.jumpBuffer = 0f;
|
||||
performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
|
||||
emitHaptic(HapticFeedbackConstants.CLOCK_TICK);
|
||||
}
|
||||
|
||||
player.vy += GRAVITY * dt;
|
||||
@@ -577,7 +585,7 @@ public final class GameView extends View implements Runnable {
|
||||
player.supportIndex = -1;
|
||||
deaths++;
|
||||
respawnTimer = RESPAWN_SECONDS;
|
||||
performHapticFeedback(Build.VERSION.SDK_INT >= 27
|
||||
emitHaptic(Build.VERSION.SDK_INT >= 27
|
||||
? HapticFeedbackConstants.LONG_PRESS : HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
|
||||
if (type != DeathType.PIT) {
|
||||
@@ -619,7 +627,7 @@ public final class GameView extends View implements Runnable {
|
||||
screen = Screen.COMPLETE;
|
||||
pointers.clear();
|
||||
deriveControls();
|
||||
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
emitHaptic(HapticFeedbackConstants.LONG_PRESS);
|
||||
}
|
||||
|
||||
private RectF playerRect() {
|
||||
@@ -650,6 +658,8 @@ public final class GameView extends View implements Runnable {
|
||||
canvas.scale(canvasScale, canvasScale);
|
||||
if (screen == Screen.LEVELS) {
|
||||
drawLevelSelect(canvas);
|
||||
} else if (screen == Screen.SETTINGS) {
|
||||
drawSettings(canvas);
|
||||
} else {
|
||||
drawGame(canvas);
|
||||
if (screen == Screen.COMPLETE) drawComplete(canvas);
|
||||
@@ -917,21 +927,27 @@ public final class GameView extends View implements Runnable {
|
||||
drawHudButton(canvas, new RectF(1608, 26, 1770, 112), "Restart", false);
|
||||
drawHudButton(canvas, new RectF(1790, 26, 1892, 112), "II", false);
|
||||
|
||||
drawControlCircle(canvas, 145, 925, 92, "‹", leftPressed);
|
||||
drawControlCircle(canvas, 365, 925, 92, "›", rightPressed);
|
||||
drawControlCircle(canvas, 1760, 900, 116, "▲", jumpPressed);
|
||||
float controlScale = controlSettings.controlScale();
|
||||
drawControlCircle(canvas, 145, 925, 92 * controlScale, "‹", leftPressed);
|
||||
drawControlCircle(canvas, 365, 925, 92 * controlScale, "›", rightPressed);
|
||||
drawControlCircle(canvas, 1760, 900, 116 * controlScale, "▲", jumpPressed);
|
||||
if (!player.alive) {
|
||||
drawCenteredText(canvas, "Another volunteer is on the way…", VIEW_WIDTH * 0.5f, 235, 38, Color.rgb(250, 222, 153));
|
||||
}
|
||||
}
|
||||
|
||||
private void drawControlCircle(Canvas canvas, float x, float y, float radius, String label, boolean active) {
|
||||
paint.setColor(active ? Color.argb(220, 245, 190, 74) : Color.argb(120, 22, 28, 43));
|
||||
int inactiveFillAlpha = Math.round(190f * controlSettings.controlOpacity());
|
||||
int inactiveStrokeAlpha = Math.round(230f * controlSettings.controlOpacity());
|
||||
paint.setColor(active ? Color.argb(220, 245, 190, 74)
|
||||
: Color.argb(inactiveFillAlpha, 22, 28, 43));
|
||||
canvas.drawCircle(x, y, radius, paint);
|
||||
stroke.setColor(active ? Color.rgb(255, 232, 169) : Color.argb(150, 240, 240, 245));
|
||||
stroke.setColor(active ? Color.rgb(255, 232, 169)
|
||||
: Color.argb(inactiveStrokeAlpha, 240, 240, 245));
|
||||
stroke.setStrokeWidth(5f);
|
||||
canvas.drawCircle(x, y, radius - 5, stroke);
|
||||
drawCenteredText(canvas, label, x, y + 21, 68, active ? Color.rgb(34, 36, 45) : Color.WHITE);
|
||||
drawCenteredText(canvas, label, x, y + 21, 68 * controlSettings.controlScale(),
|
||||
active ? Color.rgb(34, 36, 45) : Color.WHITE);
|
||||
}
|
||||
|
||||
private void drawLevelSelect(Canvas canvas) {
|
||||
@@ -968,9 +984,36 @@ public final class GameView extends View implements Runnable {
|
||||
drawCenteredText(canvas, "Tap to enter", card.centerX(), top + 190, 22, Color.rgb(202, 204, 214));
|
||||
}
|
||||
}
|
||||
drawHudButton(canvas, new RectF(1560, 70, 1850, 160), "Settings", false);
|
||||
drawCenteredText(canvas, "Landscape · multitouch · progress saves automatically", VIEW_WIDTH * 0.5f, 980, 24, Color.argb(190, 230, 230, 236));
|
||||
}
|
||||
|
||||
private void drawSettings(Canvas canvas) {
|
||||
drawSky(canvas);
|
||||
drawCenteredText(canvas, "SETTINGS", VIEW_WIDTH * 0.5f, 145, 64,
|
||||
Color.rgb(248, 212, 126));
|
||||
drawCenteredText(canvas, "Tap a row to change it. Changes save automatically.",
|
||||
VIEW_WIDTH * 0.5f, 205, 27, Color.rgb(225, 226, 233));
|
||||
drawSettingRow(canvas, new RectF(420, 280, 1500, 410), "Control size",
|
||||
controlSettings.controlSizeLabel());
|
||||
drawSettingRow(canvas, new RectF(420, 450, 1500, 580), "Control opacity",
|
||||
controlSettings.controlOpacityLabel());
|
||||
drawSettingRow(canvas, new RectF(420, 620, 1500, 750), "Vibration",
|
||||
controlSettings.hapticsLabel());
|
||||
drawHudButton(canvas, new RectF(710, 850, 1210, 960), "Back", true);
|
||||
}
|
||||
|
||||
private void drawSettingRow(Canvas canvas, RectF box, String label, String value) {
|
||||
paint.setColor(Color.argb(220, 38, 45, 65));
|
||||
canvas.drawRoundRect(box, 22, 22, paint);
|
||||
stroke.setColor(Color.rgb(139, 145, 160));
|
||||
stroke.setStrokeWidth(4f);
|
||||
canvas.drawRoundRect(box, 22, 22, stroke);
|
||||
drawText(canvas, label, box.left + 55f, box.centerY() + 11f, 32f, Color.WHITE, true);
|
||||
drawHudButton(canvas, new RectF(1_090f, box.top + 24f, 1_445f, box.bottom - 24f),
|
||||
value, false);
|
||||
}
|
||||
|
||||
private void drawComplete(Canvas canvas) {
|
||||
paint.setColor(Color.argb(218, 8, 12, 23));
|
||||
canvas.drawRect(0, 0, VIEW_WIDTH, VIEW_HEIGHT, paint);
|
||||
@@ -1047,6 +1090,13 @@ public final class GameView extends View implements Runnable {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (screen == Screen.SETTINGS) {
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
performClick();
|
||||
handleSettingsTap(point.x, point.y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (screen == Screen.COMPLETE) {
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
performClick();
|
||||
@@ -1106,14 +1156,20 @@ public final class GameView extends View implements Runnable {
|
||||
jumpPressed = false;
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
PointF point = pointers.valueAt(i);
|
||||
if (distance(point.x, point.y, 145, 925) <= 115f) leftPressed = true;
|
||||
if (distance(point.x, point.y, 365, 925) <= 115f) rightPressed = true;
|
||||
if (distance(point.x, point.y, 1760, 900) <= 145f) jumpPressed = true;
|
||||
float controlScale = controlSettings.controlScale();
|
||||
if (distance(point.x, point.y, 145, 925) <= 115f * controlScale) leftPressed = true;
|
||||
if (distance(point.x, point.y, 365, 925) <= 115f * controlScale) rightPressed = true;
|
||||
if (distance(point.x, point.y, 1760, 900) <= 145f * controlScale) jumpPressed = true;
|
||||
}
|
||||
if (jumpPressed && !wasJumpPressed && player.alive) player.jumpBuffer = JUMP_BUFFER_SECONDS;
|
||||
}
|
||||
|
||||
private void handleLevelSelectTap(float x, float y) {
|
||||
if (contains(1560, 70, 1850, 160, x, y)) {
|
||||
screen = Screen.SETTINGS;
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
return;
|
||||
}
|
||||
float startX = 110f;
|
||||
float cardW = 310f;
|
||||
float cardH = 250f;
|
||||
@@ -1124,7 +1180,7 @@ public final class GameView extends View implements Runnable {
|
||||
float left = startX + col * (cardW + gapX);
|
||||
float top = 260f + row * 310f;
|
||||
if (contains(left, top, left + cardW, top + cardH, x, y) && i < progress.unlockedCount()) {
|
||||
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
startLevel(i);
|
||||
return;
|
||||
}
|
||||
@@ -1145,6 +1201,26 @@ public final class GameView extends View implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSettingsTap(float x, float y) {
|
||||
if (contains(420, 280, 1500, 410, x, y)) {
|
||||
updateControlSettings(controlSettings.nextControlSize());
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
} else if (contains(420, 450, 1500, 580, x, y)) {
|
||||
updateControlSettings(controlSettings.nextControlOpacity());
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
} else if (contains(420, 620, 1500, 750, x, y)) {
|
||||
updateControlSettings(controlSettings.toggleHaptics());
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
} else if (contains(710, 850, 1210, 960, x, y)) {
|
||||
screen = Screen.LEVELS;
|
||||
emitHaptic(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
}
|
||||
}
|
||||
|
||||
private void emitHaptic(int feedbackConstant) {
|
||||
if (controlSettings.hapticsEnabled()) performHapticFeedback(feedbackConstant);
|
||||
}
|
||||
|
||||
private PointF toCanvasPoint(float x, float y) {
|
||||
return new PointF((x - canvasOffsetX) / Math.max(0.001f, canvasScale), (y - canvasOffsetY) / Math.max(0.001f, canvasScale));
|
||||
}
|
||||
@@ -1170,6 +1246,38 @@ public final class GameView extends View implements Runnable {
|
||||
restartLevel();
|
||||
}
|
||||
|
||||
public ControlSettings controlSettingsForAutomation() {
|
||||
return controlSettings;
|
||||
}
|
||||
|
||||
public boolean settingsVisibleForAutomation() {
|
||||
return screen == Screen.SETTINGS;
|
||||
}
|
||||
|
||||
public void resetControlSettingsForAutomation() {
|
||||
updateControlSettings(ControlSettings.defaults());
|
||||
}
|
||||
|
||||
public void selectNextControlSizeForAutomation() {
|
||||
updateControlSettings(controlSettings.nextControlSize());
|
||||
}
|
||||
|
||||
public void selectNextControlOpacityForAutomation() {
|
||||
updateControlSettings(controlSettings.nextControlOpacity());
|
||||
}
|
||||
|
||||
public void toggleHapticsForAutomation() {
|
||||
updateControlSettings(controlSettings.toggleHaptics());
|
||||
}
|
||||
|
||||
private void updateControlSettings(ControlSettings updated) {
|
||||
controlSettings = updated;
|
||||
controlSettingsStore.save(updated);
|
||||
pointers.clear();
|
||||
deriveControls();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setAutomationInput(boolean moveLeft, boolean moveRight, boolean jump) {
|
||||
boolean jumpWasPressed = jumpPressed;
|
||||
leftPressed = moveLeft;
|
||||
|
||||
Reference in New Issue
Block a user