/
arti4
/
IndividualProject
Обзор
Документация
Войти
/
arti4
/
IndividualProject
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
MyGame/app/src/main/java/com/example/mygame/RoadSegment.java
698 строк
27 KB
arti4
upload files
18 ноя 2025, 12:41
18 ноя 2025, 12:41
f3a2f8a
Код
Авторство
О чём код?
package com.example.mygame; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.jbox2d.dynamics.Body; public class RoadSegment { private Bitmap segmentBitmap; private int x, y; private int type; private Rect segmentRect; private Rect spikeCollisionRect; private Rect hammerCollisionRect; private int width, height; private boolean isActive = true; private int screenWidth; private float scaleFactor = 1.0f; private PhysicsWorld physicsWorld; private Body physicsBody; private Random random = new Random(); private float hammerOffsetY = 0f; private float hammerSpeed = 0f; private final float HAMMER_GRAVITY = 0.8f; private final float HAMMER_JUMP_FORCE = -15f; private boolean hammerIsRising = false; private boolean hammerIsFalling = false; private boolean hammerIsCrushing = false; private int hammerAnimationCounter = 0; private int hammerCrushDelay = 0; private final int HAMMER_HEAD_WIDTH = 100; private final int HAMMER_HEAD_HEIGHT = 40; private final int HAMMER_POLE_HEIGHT = 180; private final int HAMMER_BASE_HEIGHT = 60; private float platformOffsetX = 0f; private float platformSpeed = 0f; private float platformAmplitude = 0f; private int platformDirection = 1; private int platformPhase = 0; private Body platformBody; private final int PLATFORM_WIDTH = 180; private final int PLATFORM_HEIGHT = 24; private Rect platformCollisionRect; private int platformMovementCounter; private float platformPreviousGlobalX = 0f; private boolean isFirstUpdate = true; private boolean carWasOnRamp = false; private Body roadPhysicsBody; private boolean isEvenPlatform = false; private final float PAUSE_DURATION = 60f; private float pauseTimer = 0f; private boolean isPaused = false; private final float HAMMER_MAX_OFFSET = -180f; private final float HAMMER_MIN_OFFSET = 0f; private boolean hammerIsActive = false; private int roadFillColor; private int roadStrokeColor; private List<Crystal> crystals = new ArrayList<>(); private int segmentId; private Context context; public RoadSegment(Bitmap bitmap, int x, int y, int type, int screenWidth, PhysicsWorld physicsWorld, int roadFillColor, int roadStrokeColor, Context context) { this.segmentBitmap = bitmap; this.x = x; this.y = y; this.type = type; this.width = bitmap.getWidth(); this.height = bitmap.getHeight(); this.screenWidth = screenWidth; this.physicsWorld = physicsWorld; this.roadFillColor = roadFillColor; this.roadStrokeColor = roadStrokeColor; this.segmentRect = new Rect(x, y, x + width, y + height); createPhysicsBody(); this.context = context; if (type == 3) { hammerOffsetY = -HAMMER_POLE_HEIGHT; hammerSpeed = 0f; hammerIsRising = false; hammerIsFalling = false; hammerIsCrushing = false; hammerAnimationCounter = (int)(Math.random() * 90); hammerCrushDelay = 0; } if (type == 4) { initMovingPlatform(); } updateCollisionRect(); addCrystals(); } private void addCrystals() { switch (type) { case 1: addRampCrystals(3); break; case 5: addLongRampCrystals(5); break; case 3: addHammerCrystals(2); break; case 4: addPlatformCrystals(3); break; } } private void addRampCrystals(int count) { int[] heightOffsets = {50, 65, 80}; for (int i = 0; i < count; i++) { float progress = (i + 1f) / (count + 1f); float crystalX = x + width * progress; float surfaceY = getRampSurfaceYAt(crystalX); float crystalY = surfaceY - heightOffsets[i]; int crystalId = segmentId * 10 + i; crystals.add(new Crystal(crystalX, crystalY, crystalId, physicsWorld, scaleFactor, context)); } } private void addLongRampCrystals(int count) { int[] offsetsPixels = {60, 70, 80, 87, 95}; for (int i = 0; i < count; i++) { float progress = (i + 1f) / (count + 1f); float crystalX = x + width * progress; float surfaceY = getLongRampSurfaceYAt(crystalX); float verticalOffset = offsetsPixels[i] * scaleFactor; float crystalY = surfaceY - verticalOffset; int crystalId = segmentId * 10 + i; crystals.add(new Crystal(crystalX, crystalY, crystalId, physicsWorld, scaleFactor, context)); } } private void addHammerCrystals(int count) { float crystalX1 = x + width * 0.3f - 30 * scaleFactor; float crystalY1 = y + height - 100 * scaleFactor; int crystalId1 = segmentId * 10 + 0; crystals.add(new Crystal(crystalX1, crystalY1, crystalId1, physicsWorld, scaleFactor, context)); float crystalX2 = x + width * 0.7f; float crystalY2 = y + height - 100 * scaleFactor; int crystalId2 = segmentId * 10 + 1; crystals.add(new Crystal(crystalX2, crystalY2, crystalId2, physicsWorld, scaleFactor, context)); } private void addPlatformCrystals(int count) { for (int i = 0; i < count; i++) { float crystalX = x + width * (0.2f + i * 0.3f); float crystalY = y + height - 80 * scaleFactor; int crystalId = segmentId * 10 + i; crystals.add(new Crystal(crystalX, crystalY, crystalId, physicsWorld, scaleFactor, context)); } } private void updateHammerAnimation() { hammerAnimationCounter++; final int PAUSE_AT_TOP = 120; if (!hammerIsRising && !hammerIsFalling && !hammerIsCrushing) { if (hammerAnimationCounter > 10) { hammerIsRising = true; hammerSpeed = -5f; hammerIsActive = false; hammerAnimationCounter = 0; } } else if (hammerIsRising) { hammerOffsetY += hammerSpeed; if (hammerOffsetY <= HAMMER_MAX_OFFSET * scaleFactor) { hammerOffsetY = HAMMER_MAX_OFFSET * scaleFactor; hammerIsRising = false; hammerIsFalling = true; hammerSpeed = 0f; hammerAnimationCounter = 0; hammerIsActive = false; } } else if (hammerIsFalling) { hammerAnimationCounter++; if (hammerAnimationCounter < PAUSE_AT_TOP) { hammerOffsetY = HAMMER_MAX_OFFSET * scaleFactor + (float)Math.sin(hammerAnimationCounter * 0.3) * 3f; } else { hammerSpeed += HAMMER_GRAVITY * 8f; hammerOffsetY += hammerSpeed; if (hammerOffsetY >= (HAMMER_MIN_OFFSET - 10) * scaleFactor) { hammerIsActive = true; } if (hammerOffsetY >= HAMMER_MIN_OFFSET * scaleFactor) { hammerOffsetY = HAMMER_MIN_OFFSET * scaleFactor; hammerIsFalling = false; hammerIsCrushing = true; hammerCrushDelay = 0; hammerSpeed = 0f; hammerIsActive = true; } } } else if (hammerIsCrushing) { hammerCrushDelay++; hammerOffsetY = HAMMER_MIN_OFFSET * scaleFactor + (float)Math.sin(hammerCrushDelay * 0.4) * 15f; hammerIsActive = true; if (hammerCrushDelay > 25) { hammerIsCrushing = false; hammerIsRising = true; hammerSpeed = -3f; hammerAnimationCounter = 0; hammerCrushDelay = 0; hammerIsActive = false; } } updateCollisionRect(); } public boolean isHammerHittingCar(Rect carRect) { if (type != 3 || hammerCollisionRect == null) { return false; } boolean isColliding = Rect.intersects(hammerCollisionRect, carRect); return isColliding && hammerIsActive; } private void createPhysicsBody() { float centerX = x + width / 2.0f; switch (type) { case 0: physicsBody = physicsWorld.createGroundBody(centerX, y + height - 10, width, 20, this); break; case 1: physicsBody = physicsWorld.createRampBody( x, y, width, height, 35 * scaleFactor, height * 0.05f, this ); break; case 2: physicsBody = physicsWorld.createObstacleBody(centerX, y + height - 20, width * 0.7f, 30, this); break; case 3: roadPhysicsBody = physicsWorld.createGroundBody(centerX, y + height - 10, width, 20, this); physicsBody = null; break; case 4: platformBody = physicsWorld.createPlatformBody(centerX, y + height - 30, PLATFORM_WIDTH * scaleFactor, PLATFORM_HEIGHT * scaleFactor, this); break; case 5: physicsBody = physicsWorld.createRampBody( x, y, width, height, 35 * scaleFactor, height * 0.02f, this ); break; } } public void destroyPhysicsBodies() { if (physicsBody != null) { physicsWorld.markBodyForRemoval(physicsBody); } if (roadPhysicsBody != null) { physicsWorld.markBodyForRemoval(roadPhysicsBody); } if (platformBody != null) { physicsWorld.markBodyForRemoval(platformBody); } } public boolean isCarOnTriangleRamp(Rect carRect) { if (type != 6) return false; boolean intersects = Rect.intersects(segmentRect, carRect); if (intersects) { float carBottom = carRect.bottom; float triangleSurfaceY = getTriangleRampSurfaceYAt(carRect.centerX()); return Math.abs(carBottom - triangleSurfaceY) < 60 * scaleFactor; } return false; } public boolean isCarLeavingTriangleRamp(Rect carRect) { if (type != 6) return false; float carFront = carRect.right; float carRear = carRect.left; float triangleEnd = x + width * 0.5f + 80 * scaleFactor; boolean isLeaving = carFront > triangleEnd && carRear < triangleEnd; if (isLeaving) { float carBottom = carRect.bottom; float groundLevel = y + height; float heightDifference = groundLevel - carBottom; return heightDifference > 20 * scaleFactor; } return false; } public float getTriangleRampSurfaceYAt(float pointX) { if (type != 6) return y + height; float triangleCenterX = x + width * 0.5f; float triangleWidth = 160 * scaleFactor; float triangleHeight = 60 * scaleFactor; if (pointX < triangleCenterX - triangleWidth/2 || pointX > triangleCenterX + triangleWidth/2) { return y + height; } float relativeX = pointX - (triangleCenterX - triangleWidth/2); float slope = triangleHeight / (triangleWidth/2); if (pointX <= triangleCenterX) { return y + height - (slope * relativeX); } else { return y + height - (slope * (triangleWidth - relativeX)); } } public float getTriangleRampJumpPower() { return (float)Math.random() * 3.0f; } private void initMovingPlatform() { int platformWidth = (int)(PLATFORM_WIDTH * scaleFactor); int segmentWidth = this.width; float maxAmplitude = (segmentWidth - platformWidth) / 2 + 50 * scaleFactor; platformAmplitude = Math.min(150 * scaleFactor, maxAmplitude); platformSpeed = 2.0f; isEvenPlatform = (x / width) % 2 == 0; if (isEvenPlatform) { platformDirection = 1; platformOffsetX = -platformAmplitude; } else { platformDirection = -1; platformOffsetX = platformAmplitude; } isPaused = true; pauseTimer = 30f; platformPreviousGlobalX = getPlatformGlobalX(); isFirstUpdate = true; } public float getPlatformGlobalX() { if (type == 4) { int platformWidth = (int)(PLATFORM_WIDTH * scaleFactor); int platformCenterX = x + width / 2; return platformCenterX + platformOffsetX - platformWidth / 2; } return 0f; } public float getPlatformDeltaX() { if (type == 4) { float currentGlobalX = getPlatformGlobalX(); float deltaX = currentGlobalX - platformPreviousGlobalX; platformPreviousGlobalX = currentGlobalX; return deltaX; } return 0f; } private void updateCollisionRect() { if (type == 2) { int spikeWidth = (int)(width * 0.7f); int spikeStartX = x + (width - spikeWidth) / 2; int spikeTop = y + height - 45; int spikeBottom = y + height; this.spikeCollisionRect = new Rect(spikeStartX, spikeTop, spikeStartX + spikeWidth, spikeBottom); } else if (type == 3) { int hammerHeadWidth = (int)(HAMMER_HEAD_WIDTH * scaleFactor); int hammerHeadHeight = (int)(HAMMER_HEAD_HEIGHT * scaleFactor); int hammerHeadX = x + (width - hammerHeadWidth) / 2; int baseY = y + height - (int)(HAMMER_BASE_HEIGHT * scaleFactor) - 40; int hammerHeadY = baseY + (int)hammerOffsetY - hammerHeadHeight; this.hammerCollisionRect = new Rect( hammerHeadX, hammerHeadY, hammerHeadX + hammerHeadWidth, hammerHeadY + hammerHeadHeight ); } } public void draw(Canvas canvas) { if (isActive) { canvas.drawBitmap(segmentBitmap, x, y, null); for (Crystal crystal : crystals) { crystal.draw(canvas); } if (type == 3) { drawAnimatedHammer(canvas); } else if (type == 4) { drawMovingPlatform(canvas); } } } public List<Crystal> getCrystals() { return crystals; } public void setCrystalsCollected(List<Integer> collectedCrystalIds) { for (Crystal crystal : crystals) { if (collectedCrystalIds.contains(crystal.getCrystalId())) { crystal.setCollected(true); } } } private void drawAnimatedHammer(Canvas canvas) { Paint paint = new Paint(); paint.setColor(Color.GRAY); int baseWidth = (int)(80 * scaleFactor); int baseHeight = (int)(HAMMER_BASE_HEIGHT * scaleFactor); int baseX = x + (width - baseWidth) / 2; int baseY = y + height - baseHeight - 40; canvas.drawRect(baseX, baseY, baseX + baseWidth, baseY + baseHeight, paint); paint.setColor(Color.DKGRAY); int poleWidth = (int)(20 * scaleFactor); int poleX = baseX + (baseWidth - poleWidth) / 2; int poleTopY = baseY - (int)(HAMMER_POLE_HEIGHT * scaleFactor); int currentPoleBottom = baseY + (int)hammerOffsetY; canvas.drawRect(poleX, Math.min(poleTopY, currentPoleBottom), poleX + poleWidth, Math.max(poleTopY, currentPoleBottom), paint); paint.setColor(Color.RED); int headWidth = (int)(HAMMER_HEAD_WIDTH * scaleFactor); int headHeight = (int)(40 * scaleFactor); int headX = poleX + (poleWidth - headWidth) / 2; int headY = currentPoleBottom - headHeight; canvas.drawRect(headX, headY, headX + headWidth, headY + headHeight, paint); paint.setColor(Color.argb(255, 150, 150, 150)); int metalWidth = (int)(80 * scaleFactor); int metalHeight = (int)(25 * scaleFactor); int metalX = headX + (headWidth - metalWidth) / 2; int metalY = headY - metalHeight; canvas.drawRect(metalX, metalY, metalX + metalWidth, metalY + metalHeight, paint); if (hammerIsActive) { paint.setColor(Color.RED); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(3 * scaleFactor); canvas.drawRect(headX, headY, headX + headWidth, headY + headHeight, paint); } } private void drawMovingPlatform(Canvas canvas) { Paint paint = new Paint(); paint.setColor(roadFillColor); int platformWidth = (int)(PLATFORM_WIDTH * scaleFactor); int platformHeight = (int)(PLATFORM_HEIGHT * scaleFactor)+5; int platformCenterX = x + width / 2; int platformX = (int)(platformCenterX + platformOffsetX - platformWidth / 2); int platformY = y + height - platformHeight; canvas.drawRect(platformX, platformY, platformX + platformWidth, platformY + platformHeight, paint); paint.setColor(roadStrokeColor); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(10 * scaleFactor); canvas.drawRect(platformX, platformY, platformX + platformWidth, platformY + platformHeight, paint); } private void updateMovingPlatform() { if (isPaused) { pauseTimer--; if (pauseTimer <= 0) { isPaused = false; platformDirection *= -1; } return; } platformMovementCounter++; int platformWidth = (int)(PLATFORM_WIDTH * scaleFactor); int segmentWidth = this.width; float maxOffsetX = (segmentWidth - platformWidth) / 2 + 50 * scaleFactor; if (platformAmplitude > maxOffsetX) { platformAmplitude = maxOffsetX; } platformOffsetX += platformSpeed * platformDirection; boolean reachedEdge = false; if (isEvenPlatform) { if (platformOffsetX >= platformAmplitude) { platformOffsetX = platformAmplitude; reachedEdge = true; } else if (platformOffsetX <= -platformAmplitude) { platformOffsetX = -platformAmplitude; reachedEdge = true; } } else { if (platformOffsetX <= -platformAmplitude) { platformOffsetX = -platformAmplitude; reachedEdge = true; } else if (platformOffsetX >= platformAmplitude) { platformOffsetX = platformAmplitude; reachedEdge = true; } } if (reachedEdge) { isPaused = true; pauseTimer = PAUSE_DURATION; } if (platformBody != null) { float platformCenterX = x + width / 2 + platformOffsetX; float platformY = y + height - (PLATFORM_HEIGHT * scaleFactor) / 2; physicsWorld.setBodyPosition(platformBody, platformCenterX, platformY); } platformPreviousGlobalX = getPlatformGlobalX(); } private void updatePlatformCollisionRect() { if (type == 4) { int platformWidth = (int)(PLATFORM_WIDTH * scaleFactor); int platformHeight = (int)(PLATFORM_HEIGHT * scaleFactor); int platformCenterX = x + width / 2; int platformX = (int)(platformCenterX + platformOffsetX - platformWidth / 2); int platformY = y + height - platformHeight; this.platformCollisionRect = new Rect(platformX, platformY, platformX + platformWidth, platformY + platformHeight); this.segmentRect = new Rect(0, 0, 0, 0); } } private void updatePlatformCollisionRect(int platformX, int platformY, int platformWidth, int platformHeight) { if (type == 4) { this.platformCollisionRect = new Rect(platformX, platformY, platformX + platformWidth, platformY + platformHeight); } } public boolean isOffScreen() { return x + width < 0; } public boolean isVisibleOnScreen() { return x + width > 0 && x < screenWidth; } public boolean isCarOnPlatform(Rect carRect) { if (type == 4 && platformCollisionRect != null) { boolean isOnPlatform = Rect.intersects(platformCollisionRect, carRect); if (isOnPlatform) { float carBottom = carRect.bottom; float platformTop = platformCollisionRect.top; float heightDiff = carBottom - platformTop; boolean isCloseEnough = heightDiff >= -25f && heightDiff <= 45f; return isCloseEnough; } } return false; } public boolean isHammerCrushing() { return type == 3 && hammerIsCrushing; } public boolean hasCollisionWithCar(Rect carRect) { if (type == 2) { return Rect.intersects(spikeCollisionRect, carRect); } else if (type == 3) { return isHammerHittingCar(carRect); } return false; } public void update() { if (type == 3) { updateHammerAnimation(); if (physicsBody != null) { float hammerCenterX = x + width / 2.0f; float hammerCenterY = y + height - 100 + (hammerOffsetY * 0.5f); physicsWorld.setBodyPosition(physicsBody, hammerCenterX, hammerCenterY); } } if (type == 4) { updateMovingPlatform(); updatePlatformCollisionRect(); } } public boolean isCarOnRampEnd(Rect carRect) { if (type != 1) return false; float carFront = carRect.right; float rampEnd = x + width; boolean atRampEnd = carFront >= rampEnd - 10 && carFront <= rampEnd + 50; if (atRampEnd) { float carBottom = carRect.bottom; float rampSurfaceY = getRampSurfaceYAt(carRect.centerX()); boolean onRampSurface = Math.abs(carBottom - rampSurfaceY) < 40 * scaleFactor; return onRampSurface; } return false; } public boolean isCarLeavingRamp(Rect carRect) { if (type != 1 && type != 5) return false; float carFront = carRect.right; float carRear = carRect.left; float rampEnd = x + width; boolean isLeaving = carFront > rampEnd && carRear < rampEnd; if (isLeaving) { float carBottom = carRect.bottom; float groundLevel = y + height; float heightDifference = groundLevel - carBottom; return heightDifference > 20 * scaleFactor; } return false; } public boolean isCarOnRamp(Rect carRect) { if (type != 1 && type != 5 && type != 6) return false; boolean intersects = Rect.intersects(segmentRect, carRect); if (intersects) { float carBottom = carRect.bottom; float rampSurfaceY = getRampSurfaceYAt(carRect.centerX()); return Math.abs(carBottom - rampSurfaceY) < 60 * scaleFactor; } return false; } public float getRampSurfaceYAt(float pointX) { if (type != 1 && type != 5) return y + height; float localX = pointX - x; if (localX < 0) return y + height; if (localX > width) return y + height; float startY = y + height - 35 * scaleFactor; float endY = y + height * 0.3f; float progress = localX / width; float surfaceY = startY + (endY - startY) * progress; return surfaceY; } private float getLongRampSurfaceYAt(float pointX) { if (type != 5) return y + height; float localX = pointX - x; if (localX < 0) return y + height; if (localX > width) return y + height; float startY = y + height - 35 * scaleFactor; float endY = y + height * 0.1f; float progress = localX / width; float surfaceY = startY + (endY - startY) * progress; return surfaceY; } public float getRampJumpPower() { if (type == 5) { return (float)Math.random() * 3.0f; } else if (type == 1) { return (float)Math.random() * 2.0f; } return 10.0f; } public float getSurfaceHeightAt(float pointX) { if (type == 1 || type == 5) { float localX = pointX - x; if (localX < 0) return y + height; if (localX > width) return y + height; if (type == 5) { return y + height - (height * localX / width); } else { float startHeight = y + height; float endHeight = y + height * 0.3f; return startHeight - (startHeight - endHeight) * (localX / width); } } else if (type == 3) { return y + height - 40; } else if (type == 4) { if (platformCollisionRect != null && pointX >= platformCollisionRect.left && pointX <= platformCollisionRect.right) { return platformCollisionRect.top; } return y + height; } else { return y + height; } } public float getRampAngleAt(float pointX) { if (type != 1) return 0f; float localX = pointX - x; if (localX < 0 || localX > width) return 0f; float angle = (float) Math.toDegrees(Math.atan2(height, width)); return angle; } public Body getPhysicsBody() { return physicsBody; } public Body getPlatformBody() { return platformBody; } public Rect getHammerCollisionRect() { return hammerCollisionRect; } public boolean isHammerRising() { return hammerIsRising; } public boolean isHammerFalling() { return hammerIsFalling; } public Rect getRect() { return segmentRect; } public int getType() { return type; } public int getX() { return x; } public int getY() { return y; } public int getWidth() { return width; } public int getHeight() { return height; } public int getRight() { return x + width; } public int getRoadSurfaceY() { return y + height - 40; } public void setActive(boolean active) { isActive = active; } public void setScaleFactor(float scaleFactor) { this.scaleFactor = scaleFactor; } }