Выделить CorpseManager

This commit is contained in:
2026-08-19 03:43:20 +03:00
parent 62ee6877f9
commit cc3b5902cc
8 changed files with 436 additions and 69 deletions
@@ -1,5 +1,7 @@
package com.projectsacrifice.game;
import com.projectsacrifice.game.CorpseManager.Body;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -190,18 +192,6 @@ public final class GameView extends View implements Runnable {
int facing = 1;
}
private static final class Corpse {
float x, y, width = 72f, height = 54f, vx, vy;
boolean frozen;
boolean conductive;
boolean pinned;
boolean grounded;
int supportIndex = -1;
DeathType type;
RectF rect() { return new RectF(x, y, x + width, y + height); }
}
private static final class PlatformState {
float x, y, previousX, previousY, motionTime;
final LevelDefinition.Platform definition;
@@ -235,7 +225,8 @@ public final class GameView extends View implements Runnable {
private final Player player = new Player();
private final CharacterStateMachine characterStateMachine =
new CharacterStateMachine(PHYSICS);
private final ArrayList<Corpse> corpses = new ArrayList<>();
private final CorpseManager corpseManager = new CorpseManager(MAX_CORPSES);
private final List<Body> corpses = corpseManager.bodies();
private final ArrayList<PlatformState> platformStates = new ArrayList<>();
private final Map<String, Boolean> toggleSignals = new HashMap<>();
private final Map<String, Float> timedSignals = new HashMap<>();
@@ -400,7 +391,7 @@ public final class GameView extends View implements Runnable {
userPaused = false;
pointers.clear();
deriveControls();
corpses.clear();
corpseManager.reset();
platformStates.clear();
toggleSignals.clear();
timedSignals.clear();
@@ -517,7 +508,7 @@ public final class GameView extends View implements Runnable {
private boolean switchContact(LevelDefinition.Switch item) {
int mass = 0;
if (player.alive && intersects(player.x, player.y, PLAYER_WIDTH, PLAYER_HEIGHT, item.box)) mass++;
for (Corpse corpse : corpses) {
for (Body corpse : corpses) {
if (intersects(corpse.x, corpse.y, corpse.width, corpse.height, item.box)) mass++;
}
return mass >= item.requiredMass;
@@ -533,7 +524,7 @@ public final class GameView extends View implements Runnable {
}
for (LevelDefinition.Hazard hazard : level.hazards) {
if (id.equals(hazard.relayId)) {
for (Corpse corpse : corpses) {
for (Body corpse : corpses) {
if (corpse.conductive && intersects(corpse.x, corpse.y, corpse.width, corpse.height, hazard.box)) return true;
}
}
@@ -566,7 +557,7 @@ public final class GameView extends View implements Runnable {
player.x += support.x - support.previousX;
player.y += support.y - support.previousY;
}
for (Corpse corpse : corpses) {
for (Body corpse : corpses) {
if (!corpse.frozen && corpse.supportIndex >= 0 && corpse.supportIndex < platformStates.size()) {
PlatformState support = platformStates.get(corpse.supportIndex);
corpse.x += support.x - support.previousX;
@@ -650,8 +641,8 @@ public final class GameView extends View implements Runnable {
player.vy = 0f;
current = playerRect();
}
for (Corpse corpse : corpses) {
RectF solid = corpse.rect();
for (Body corpse : corpses) {
RectF solid = corpseRect(corpse);
if (!RectF.intersects(current, solid)) continue;
if (amount >= 0f) {
player.y = solid.top - PLAYER_HEIGHT;
@@ -666,7 +657,7 @@ public final class GameView extends View implements Runnable {
}
private void updateCorpses(float dt) {
for (Corpse corpse : corpses) {
for (Body corpse : corpses) {
if (corpse.frozen || corpse.pinned) continue;
corpse.vy += GRAVITY * dt;
corpse.grounded = false;
@@ -680,7 +671,7 @@ public final class GameView extends View implements Runnable {
}
}
private boolean settleCorpseOnPressurePlate(Corpse corpse) {
private boolean settleCorpseOnPressurePlate(Body corpse) {
for (LevelDefinition.Switch item : level.switches) {
if (item.type != LevelDefinition.SwitchType.PRESSURE) continue;
if (!intersects(corpse.x, corpse.y, corpse.width, corpse.height, item.box)) continue;
@@ -691,26 +682,26 @@ public final class GameView extends View implements Runnable {
}
corpse.vx = 0f;
corpse.vy = 0f;
corpse.pinned = true;
corpseManager.transform(corpse, CorpseManager.Transformation.PINNED);
return true;
}
return false;
}
private void resolveCorpseHorizontal(Corpse corpse) {
RectF current = corpse.rect();
private void resolveCorpseHorizontal(Body corpse) {
RectF current = corpseRect(corpse);
for (RectF solid : solidRects(false)) {
if (!RectF.intersects(current, solid)) continue;
if (corpse.vx > 0f) corpse.x = solid.left - corpse.width;
else if (corpse.vx < 0f) corpse.x = solid.right;
corpse.vx *= -0.18f;
current = corpse.rect();
current = corpseRect(corpse);
}
}
private void resolveCorpseVertical(Corpse corpse) {
private void resolveCorpseVertical(Body corpse) {
corpse.supportIndex = -1;
RectF current = corpse.rect();
RectF current = corpseRect(corpse);
for (int i = 0; i < platformStates.size(); i++) {
RectF solid = platformStates.get(i).rect();
if (!RectF.intersects(current, solid)) continue;
@@ -723,7 +714,7 @@ public final class GameView extends View implements Runnable {
corpse.y = solid.bottom;
corpse.vy *= -0.1f;
}
current = corpse.rect();
current = corpseRect(corpse);
}
for (LevelDefinition.Door door : level.doors) {
if (doorOpen(door)) continue;
@@ -737,7 +728,7 @@ public final class GameView extends View implements Runnable {
corpse.y = solid.bottom;
corpse.vy *= -0.1f;
}
current = corpse.rect();
current = corpseRect(corpse);
}
}
@@ -745,7 +736,7 @@ public final class GameView extends View implements Runnable {
ArrayList<RectF> result = new ArrayList<>();
for (PlatformState platform : platformStates) result.add(platform.rect());
for (LevelDefinition.Door door : level.doors) if (!doorOpen(door)) result.add(rect(door.box));
if (includeCorpses) for (Corpse corpse : corpses) result.add(corpse.rect());
if (includeCorpses) for (Body corpse : corpses) result.add(corpseRect(corpse));
return result;
}
@@ -778,10 +769,8 @@ public final class GameView extends View implements Runnable {
cameraController.impact(type == DeathType.PIT ? 12f : 24f);
if (type != DeathType.PIT) {
Corpse corpse = new Corpse();
corpse.type = type;
corpse.x = player.x;
corpse.y = player.y + PLAYER_HEIGHT - corpse.height;
Body corpse = corpseManager.register(type.name(), player.x,
player.y + PLAYER_HEIGHT - 54f);
if (source != null) {
corpse.vx = source.impulseX;
corpse.vy = source.impulseY;
@@ -789,23 +778,21 @@ public final class GameView extends View implements Runnable {
if (type == DeathType.SPIKE && source != null) {
corpse.y = source.box.y - corpse.height;
corpse.vx = corpse.vy = 0f;
corpse.pinned = true;
corpseManager.transform(corpse, CorpseManager.Transformation.PINNED);
} else if (type == DeathType.FREEZE && source != null) {
corpse.width = 104f;
corpse.height = 104f;
corpse.x = source.box.x - 2f;
corpse.y = 880f - corpse.height;
corpse.vx = corpse.vy = 0f;
corpse.frozen = true;
corpseManager.transform(corpse, CorpseManager.Transformation.FROZEN);
} else if (type == DeathType.ELECTRIC && source != null) {
corpse.conductive = true;
corpse.x = source.box.x + (source.box.width - corpse.width) * 0.5f;
corpse.y = 880f - corpse.height;
corpse.vx = corpse.vy = 0f;
corpse.pinned = true;
corpseManager.transform(corpse, CorpseManager.Transformation.CONDUCTIVE);
corpseManager.transform(corpse, CorpseManager.Transformation.PINNED);
}
corpses.add(corpse);
while (corpses.size() > MAX_CORPSES) corpses.remove(0);
}
}
@@ -841,6 +828,11 @@ public final class GameView extends View implements Runnable {
return new RectF(player.x, player.y, player.x + PLAYER_WIDTH, player.y + PLAYER_HEIGHT);
}
private static RectF corpseRect(Body corpse) {
return new RectF(corpse.x, corpse.y,
corpse.x + corpse.width, corpse.y + corpse.height);
}
private static RectF rect(LevelDefinition.Box box) {
return new RectF(box.x, box.y, box.right(), box.bottom());
}
@@ -902,7 +894,7 @@ public final class GameView extends View implements Runnable {
drawHazards(canvas);
drawDoors(canvas);
drawGoal(canvas);
for (Corpse corpse : corpses) drawCorpse(canvas, corpse);
for (Body corpse : corpses) drawCorpse(canvas, corpse);
VolunteerRig.Skin skin = VolunteerRig.Skin.forLevel(level.number);
if (player.alive) {
VolunteerRig.Motion motion = VolunteerRig.motionFor(characterStateMachine.state());
@@ -1140,7 +1132,7 @@ public final class GameView extends View implements Runnable {
canvas.drawCircle(box.centerX() - 6f, box.centerY() - 7f, 7f, paint);
}
private void drawCorpse(Canvas canvas, Corpse corpse) {
private void drawCorpse(Canvas canvas, Body corpse) {
canvas.save();
float cx = corpse.x + corpse.width * 0.5f;
float cy = corpse.y + corpse.height * 0.5f;
@@ -2280,12 +2272,12 @@ public final class GameView extends View implements Runnable {
player.x, player.y, player.vx, player.vy,
player.alive, player.onGround, player.coyote,
player.jumpBuffer, player.supportIndex, player.facing));
for (Corpse corpse : corpses) {
for (Body corpse : corpses) {
builder.addBody(new GameSessionSnapshot.BodyData(
corpse.x, corpse.y, corpse.width, corpse.height,
corpse.vx, corpse.vy, corpse.frozen, corpse.conductive,
corpse.pinned, corpse.grounded, corpse.supportIndex,
corpse.type == null ? DeathType.SPIKE.name() : corpse.type.name()));
corpse.deathType()));
}
ArrayList<Float> motionTimes = new ArrayList<>(platformStates.size());
for (PlatformState state : platformStates) motionTimes.add(state.motionTime);
@@ -2353,22 +2345,22 @@ public final class GameView extends View implements Runnable {
characterStateMachine.reset(player.alive, player.onGround,
player.vx, player.vy, player.facing);
corpses.clear();
for (GameSessionSnapshot.BodyData savedBody : snapshot.bodies()) {
Corpse corpse = new Corpse();
corpse.x = savedBody.x();
corpse.y = savedBody.y();
corpse.width = savedBody.width();
corpse.height = savedBody.height();
corpse.vx = savedBody.velocityX();
corpse.vy = savedBody.velocityY();
corpse.frozen = savedBody.frozen();
corpse.conductive = savedBody.conductive();
corpse.pinned = savedBody.pinned();
corpse.grounded = savedBody.grounded();
corpse.supportIndex = savedBody.supportIndex();
corpse.type = DeathType.valueOf(savedBody.deathType());
corpses.add(corpse);
Body corpse = corpseManager.register(savedBody.deathType(),
savedBody.x(), savedBody.y())
.size(savedBody.width(), savedBody.height())
.velocity(savedBody.velocityX(), savedBody.velocityY())
.grounded(savedBody.grounded())
.supportIndex(savedBody.supportIndex());
if (savedBody.frozen()) {
corpseManager.transform(corpse, CorpseManager.Transformation.FROZEN);
}
if (savedBody.conductive()) {
corpseManager.transform(corpse, CorpseManager.Transformation.CONDUCTIVE);
}
if (savedBody.pinned()) {
corpseManager.transform(corpse, CorpseManager.Transformation.PINNED);
}
}
leftPressed = false;
@@ -2452,4 +2444,8 @@ public final class GameView extends View implements Runnable {
public void triggerStunForAutomation() {
characterStateMachine.stun();
}
public CorpseManager.Diagnostics corpseDiagnosticsForAutomation() {
return corpseManager.diagnostics();
}
}