Initial repo commit
This commit is contained in:
15
core/build.gradle
Normal file
15
core/build.gradle
Normal file
@@ -0,0 +1,15 @@
|
||||
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||
eclipse.project.name = appName + '-core'
|
||||
|
||||
dependencies {
|
||||
api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
|
||||
api "com.badlogicgames.gdx:gdx-bullet:$gdxVersion"
|
||||
api "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||
api "com.kotcrab.vis:vis-ui:$visUiVersion"
|
||||
api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||
api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
|
||||
|
||||
if(enableGraalNative == 'true') {
|
||||
implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion"
|
||||
}
|
||||
}
|
||||
557
core/src/main/java/com/mygdx/game/AbsurdCityBuilder1.java
Normal file
557
core/src/main/java/com/mygdx/game/AbsurdCityBuilder1.java
Normal file
@@ -0,0 +1,557 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.viewport.FitViewport;
|
||||
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class AbsurdCityBuilder1 extends ApplicationAdapter {
|
||||
// Константы
|
||||
private static final int WIDTH = 1700;
|
||||
private static final int HEIGHT = 950;
|
||||
private static final int UI_INPUT_HEIGHT = 210;
|
||||
|
||||
// Основные объекты
|
||||
private SpriteBatch batch;
|
||||
private ShapeRenderer shapeRenderer;
|
||||
private OrthographicCamera camera;
|
||||
private Viewport viewport;
|
||||
private BitmapFont font;
|
||||
private GlyphLayout glyphLayout;
|
||||
private Texture whitePixel;
|
||||
|
||||
// Игровые объекты
|
||||
private Array<Building> buildings;
|
||||
private Building currentBuilding;
|
||||
private MathProblem currentProblem;
|
||||
private Random random;
|
||||
private Array<Citizen> citizens;
|
||||
private Array<JokeBubble> jokeBubbles;
|
||||
|
||||
// Переменные игры
|
||||
private float time = 0;
|
||||
private boolean showWrongAnswerJoke = false;
|
||||
private String wrongAnswerJoke = "";
|
||||
private float jokeTimer = 0;
|
||||
|
||||
// UI переменные
|
||||
private int selectedBuildingType = 0;
|
||||
private StringBuilder inputText = new StringBuilder();
|
||||
private boolean isTyping = false;
|
||||
private String messageText = "Добро пожаловать! Выберите здание и кликните на поле.";
|
||||
private Color messageColor = Color.WHITE;
|
||||
private String problemText = "Нажмите ESC для возврата в меню";
|
||||
|
||||
// Текстуры и рендереры
|
||||
private Texture backgroundTexture;
|
||||
private BuildingRenderer buildingRenderer;
|
||||
private UIRenderer uiRenderer;
|
||||
private MenuRenderer menuRenderer;
|
||||
|
||||
// Планета
|
||||
private Planet currentPlanet;
|
||||
private float planetSwitchTimer = 0;
|
||||
private boolean isSwitchingPlanets = false;
|
||||
private Planet targetPlanet;
|
||||
|
||||
// Состояние игры
|
||||
private GameState gameState = GameState.MAIN_MENU;
|
||||
private boolean wasJustClicked = false;
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
batch = new SpriteBatch();
|
||||
shapeRenderer = new ShapeRenderer();
|
||||
|
||||
GameAssets.createFonts();
|
||||
font = GameAssets.getFont();
|
||||
glyphLayout = new GlyphLayout();
|
||||
whitePixel = GameAssets.createWhitePixel();
|
||||
|
||||
camera = new OrthographicCamera();
|
||||
viewport = new FitViewport(WIDTH, HEIGHT, camera);
|
||||
viewport.apply();
|
||||
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
|
||||
|
||||
random = new Random();
|
||||
buildings = new Array<>();
|
||||
citizens = new Array<>();
|
||||
jokeBubbles = new Array<>();
|
||||
|
||||
// Начинаем с Земли
|
||||
currentPlanet = Planet.EARTH;
|
||||
|
||||
try {
|
||||
backgroundTexture = new Texture(Gdx.files.internal("фон4.png"));
|
||||
} catch (Exception e) {
|
||||
backgroundTexture = null;
|
||||
}
|
||||
|
||||
buildingRenderer = new BuildingRenderer(shapeRenderer, batch, font, glyphLayout, whitePixel);
|
||||
uiRenderer = new UIRenderer(batch, font, glyphLayout, whitePixel, WIDTH, HEIGHT, UI_INPUT_HEIGHT);
|
||||
menuRenderer = new MenuRenderer(batch, font, glyphLayout, whitePixel, WIDTH, HEIGHT);
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
handleInput();
|
||||
update();
|
||||
|
||||
Gdx.gl.glClearColor(0, 0, 0, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
camera.update();
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
shapeRenderer.setProjectionMatrix(camera.combined);
|
||||
|
||||
switch (gameState) {
|
||||
case MAIN_MENU:
|
||||
renderMainMenu();
|
||||
break;
|
||||
case PLANET_SELECT:
|
||||
renderPlanetSelect();
|
||||
break;
|
||||
case HELP:
|
||||
renderHelp();
|
||||
break;
|
||||
case ABOUT:
|
||||
renderAbout();
|
||||
break;
|
||||
case PLAYING:
|
||||
renderGame();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInput() {
|
||||
// Обработка кликов мыши
|
||||
boolean isClicked = Gdx.input.justTouched();
|
||||
float mouseX = Gdx.input.getX();
|
||||
float mouseY = HEIGHT - Gdx.input.getY(); // Инвертируем Y
|
||||
|
||||
// ESC для возврата в меню из игры
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)) {
|
||||
if (gameState == GameState.PLAYING) {
|
||||
if (isTyping) {
|
||||
// Отмена ввода
|
||||
setTyping(false);
|
||||
getInputText().setLength(0);
|
||||
setMessageText("Ввод отменен.");
|
||||
setMessageColor(Color.YELLOW);
|
||||
} else {
|
||||
// Возврат в главное меню
|
||||
gameState = GameState.MAIN_MENU;
|
||||
setMessageText("Игра приостановлена. Нажмите ESC для продолжения.");
|
||||
}
|
||||
} else if (gameState != GameState.MAIN_MENU) {
|
||||
// Возврат в главное меню из других состояний
|
||||
gameState = GameState.MAIN_MENU;
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка состояний меню
|
||||
switch (gameState) {
|
||||
case MAIN_MENU:
|
||||
handleMainMenuInput(mouseX, mouseY, isClicked);
|
||||
break;
|
||||
case PLANET_SELECT:
|
||||
handlePlanetSelectInput(mouseX, mouseY, isClicked);
|
||||
break;
|
||||
case HELP:
|
||||
handleHelpInput(mouseX, mouseY, isClicked);
|
||||
break;
|
||||
case ABOUT:
|
||||
handleAboutInput(mouseX, mouseY, isClicked);
|
||||
break;
|
||||
case PLAYING:
|
||||
InputHandler.handleInput(this);
|
||||
break;
|
||||
}
|
||||
|
||||
wasJustClicked = isClicked;
|
||||
}
|
||||
|
||||
private void handleMainMenuInput(float mouseX, float mouseY, boolean isClicked) {
|
||||
if (isClicked) {
|
||||
MenuButton clickedButton = menuRenderer.getMainMenuButtonAt(mouseX, mouseY);
|
||||
if (clickedButton != null) {
|
||||
String buttonText = clickedButton.getText(); // Используйте геттер
|
||||
|
||||
if (buttonText.contains("НОВАЯ ИГРА")) {
|
||||
startNewGame();
|
||||
} else if (buttonText.contains("ВЫБОР ПЛАНЕТЫ")) {
|
||||
gameState = GameState.PLANET_SELECT;
|
||||
} else if (buttonText.contains("ПОМОЩЬ")) {
|
||||
gameState = GameState.HELP;
|
||||
} else if (buttonText.contains("ОБ ИГРЕ")) {
|
||||
gameState = GameState.ABOUT;
|
||||
} else if (buttonText.contains("ВЫХОД")) {
|
||||
Gdx.app.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePlanetSelectInput(float mouseX, float mouseY, boolean isClicked) {
|
||||
if (isClicked) {
|
||||
MenuButton clickedButton = menuRenderer.getPlanetSelectButtonAt(mouseX, mouseY);
|
||||
if (clickedButton != null) {
|
||||
String buttonText = clickedButton.getText(); // Используйте геттер
|
||||
|
||||
if (buttonText.contains("ЗЕМЛЯ")) {
|
||||
startNewGameOnPlanet(Planet.EARTH);
|
||||
} else if (buttonText.contains("МАРС")) {
|
||||
startNewGameOnPlanet(Planet.MARS);
|
||||
} else if (buttonText.contains("ВЕНЕРА")) {
|
||||
startNewGameOnPlanet(Planet.VENUS);
|
||||
} else if (buttonText.contains("НАЗАД")) {
|
||||
gameState = GameState.MAIN_MENU;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleHelpInput(float mouseX, float mouseY, boolean isClicked) {
|
||||
if (isClicked) {
|
||||
MenuButton clickedButton = menuRenderer.getHelpButtonAt(mouseX, mouseY);
|
||||
if (clickedButton != null) {
|
||||
String buttonText = clickedButton.getText(); // Используйте геттер
|
||||
|
||||
if (buttonText.contains("НАЗАД")) {
|
||||
gameState = GameState.MAIN_MENU;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAboutInput(float mouseX, float mouseY, boolean isClicked) {
|
||||
if (isClicked) {
|
||||
// Простая проверка на кнопку "Назад"
|
||||
if (mouseX >= 50 && mouseX <= 250 && mouseY >= 50 && mouseY <= 110) {
|
||||
gameState = GameState.MAIN_MENU;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startNewGame() {
|
||||
// Очищаем всё и начинаем новую игру на Земле
|
||||
buildings.clear();
|
||||
citizens.clear();
|
||||
jokeBubbles.clear();
|
||||
currentBuilding = null;
|
||||
currentProblem = null;
|
||||
selectedBuildingType = 0;
|
||||
inputText.setLength(0);
|
||||
isTyping = false;
|
||||
|
||||
currentPlanet = Planet.EARTH;
|
||||
isSwitchingPlanets = false;
|
||||
|
||||
messageText = "Добро пожаловать на Землю! Выберите здание и кликните на поле.";
|
||||
messageColor = Color.GREEN;
|
||||
|
||||
gameState = GameState.PLAYING;
|
||||
updateUI();
|
||||
}
|
||||
|
||||
private void startNewGameOnPlanet(Planet planet) {
|
||||
// Очищаем всё и начинаем новую игру на выбранной планете
|
||||
buildings.clear();
|
||||
citizens.clear();
|
||||
jokeBubbles.clear();
|
||||
currentBuilding = null;
|
||||
currentProblem = null;
|
||||
selectedBuildingType = 0;
|
||||
inputText.setLength(0);
|
||||
isTyping = false;
|
||||
|
||||
currentPlanet = planet;
|
||||
isSwitchingPlanets = false;
|
||||
|
||||
messageText = "Добро пожаловать на " + planet.getName() + "! Выберите здание и кликните на поле.";
|
||||
messageColor = Color.GREEN;
|
||||
|
||||
gameState = GameState.PLAYING;
|
||||
updateUI();
|
||||
}
|
||||
|
||||
private void update() {
|
||||
float deltaTime = Gdx.graphics.getDeltaTime();
|
||||
time += deltaTime;
|
||||
|
||||
// Обновляем меню
|
||||
menuRenderer.update(deltaTime);
|
||||
|
||||
// Обработка плавной смены планет
|
||||
if (isSwitchingPlanets) {
|
||||
planetSwitchTimer += deltaTime;
|
||||
if (planetSwitchTimer >= 1.0f) {
|
||||
currentPlanet = targetPlanet;
|
||||
isSwitchingPlanets = false;
|
||||
setMessageText("Добро пожаловать на " + currentPlanet.getName() + "! 🌍");
|
||||
}
|
||||
}
|
||||
|
||||
if (gameState == GameState.PLAYING) {
|
||||
for (Building b : buildings) {
|
||||
b.update(deltaTime);
|
||||
}
|
||||
if (currentBuilding != null) {
|
||||
currentBuilding.update(deltaTime);
|
||||
}
|
||||
|
||||
// Обновляем жителей
|
||||
for (Citizen citizen : citizens) {
|
||||
citizen.update(deltaTime);
|
||||
}
|
||||
|
||||
// Обновляем пузыри с шутками
|
||||
for (int i = jokeBubbles.size - 1; i >= 0; i--) {
|
||||
JokeBubble bubble = jokeBubbles.get(i);
|
||||
bubble.update(deltaTime);
|
||||
if (bubble.isExpired()) {
|
||||
jokeBubbles.removeIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем таймер шутки
|
||||
if (showWrongAnswerJoke) {
|
||||
jokeTimer += deltaTime;
|
||||
if (jokeTimer > 3.0f) {
|
||||
showWrongAnswerJoke = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkAnswer() {
|
||||
AnswerChecker.checkAnswer(this);
|
||||
}
|
||||
|
||||
public void startPlanetSwitch(Planet newPlanet) {
|
||||
if (currentPlanet == newPlanet || isSwitchingPlanets) return;
|
||||
|
||||
isSwitchingPlanets = true;
|
||||
targetPlanet = newPlanet;
|
||||
planetSwitchTimer = 0;
|
||||
|
||||
// Очищаем город при смене планеты
|
||||
buildings.clear();
|
||||
citizens.clear();
|
||||
jokeBubbles.clear();
|
||||
currentBuilding = null;
|
||||
currentProblem = null;
|
||||
selectedBuildingType = 0;
|
||||
|
||||
setMessageText("Запускаем космический корабль на " + newPlanet.getName() + "! 🚀");
|
||||
setMessageColor(Color.YELLOW);
|
||||
updateUI();
|
||||
}
|
||||
|
||||
public void updateUI() {
|
||||
UIUpdater.updateUI(this);
|
||||
}
|
||||
|
||||
private void renderMainMenu() {
|
||||
float mouseX = Gdx.input.getX();
|
||||
float mouseY = HEIGHT - Gdx.input.getY();
|
||||
menuRenderer.renderMainMenu(mouseX, mouseY);
|
||||
}
|
||||
|
||||
private void renderPlanetSelect() {
|
||||
float mouseX = Gdx.input.getX();
|
||||
float mouseY = HEIGHT - Gdx.input.getY();
|
||||
menuRenderer.renderPlanetSelect(mouseX, mouseY);
|
||||
}
|
||||
|
||||
private void renderHelp() {
|
||||
float mouseX = Gdx.input.getX();
|
||||
float mouseY = HEIGHT - Gdx.input.getY();
|
||||
menuRenderer.renderHelp(mouseX, mouseY);
|
||||
}
|
||||
|
||||
private void renderAbout() {
|
||||
float mouseX = Gdx.input.getX();
|
||||
float mouseY = HEIGHT - Gdx.input.getY();
|
||||
menuRenderer.renderAbout(mouseX, mouseY);
|
||||
}
|
||||
|
||||
private void renderGame() {
|
||||
renderBackground();
|
||||
renderBuildings();
|
||||
renderCitizens();
|
||||
renderJokeBubbles();
|
||||
renderBuildingNames();
|
||||
renderPlanetTransition();
|
||||
renderUI();
|
||||
}
|
||||
|
||||
private void renderBackground() {
|
||||
batch.begin();
|
||||
|
||||
Color bgColor;
|
||||
if (isSwitchingPlanets) {
|
||||
// Плавный переход между цветами
|
||||
Color fromColor = currentPlanet.getColor();
|
||||
Color toColor = targetPlanet.getColor();
|
||||
float progress = Math.min(planetSwitchTimer * 2, 1.0f);
|
||||
|
||||
bgColor = new Color(
|
||||
fromColor.r + (toColor.r - fromColor.r) * progress,
|
||||
fromColor.g + (toColor.g - fromColor.g) * progress,
|
||||
fromColor.b + (toColor.b - fromColor.b) * progress,
|
||||
1
|
||||
);
|
||||
} else {
|
||||
bgColor = currentPlanet.getColor();
|
||||
}
|
||||
|
||||
if (backgroundTexture != null) {
|
||||
batch.setColor(bgColor);
|
||||
batch.draw(backgroundTexture, 0, UI_INPUT_HEIGHT, WIDTH, HEIGHT - UI_INPUT_HEIGHT);
|
||||
batch.setColor(Color.WHITE);
|
||||
} else {
|
||||
batch.setColor(bgColor);
|
||||
batch.draw(whitePixel, 0, UI_INPUT_HEIGHT, WIDTH, HEIGHT - UI_INPUT_HEIGHT);
|
||||
batch.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
batch.end();
|
||||
}
|
||||
|
||||
private void renderBuildings() {
|
||||
buildingRenderer.renderBuildings(buildings, currentBuilding, time, currentPlanet);
|
||||
}
|
||||
|
||||
private void renderCitizens() {
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
|
||||
for (Citizen citizen : citizens) {
|
||||
citizen.draw(shapeRenderer, time);
|
||||
}
|
||||
shapeRenderer.end();
|
||||
}
|
||||
|
||||
private void renderJokeBubbles() {
|
||||
for (JokeBubble bubble : jokeBubbles) {
|
||||
bubble.draw(batch, shapeRenderer, font, glyphLayout, whitePixel);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderBuildingNames() {
|
||||
buildingRenderer.renderBuildingNames(buildings, currentBuilding);
|
||||
}
|
||||
|
||||
private void renderPlanetTransition() {
|
||||
if (!isSwitchingPlanets) return;
|
||||
|
||||
batch.begin();
|
||||
|
||||
// Затемнение экрана
|
||||
float alpha = Math.min(planetSwitchTimer * 2, 1.0f);
|
||||
batch.setColor(0, 0, 0, alpha * 0.7f);
|
||||
batch.draw(whitePixel, 0, 0, WIDTH, HEIGHT);
|
||||
|
||||
// Текст перехода
|
||||
font.setColor(1, 1, 1, alpha);
|
||||
font.getData().setScale(1.5f);
|
||||
|
||||
String transitionText;
|
||||
if (planetSwitchTimer < 0.5f) {
|
||||
transitionText = "Покидаем " + currentPlanet.getName() + "...";
|
||||
} else {
|
||||
transitionText = "Прибываем на " + targetPlanet.getName() + "!";
|
||||
}
|
||||
|
||||
glyphLayout.setText(font, transitionText);
|
||||
font.draw(batch, transitionText,
|
||||
WIDTH/2 - glyphLayout.width/2,
|
||||
HEIGHT/2 + 50);
|
||||
|
||||
font.getData().setScale(1.0f);
|
||||
batch.end();
|
||||
}
|
||||
|
||||
private void renderUI() {
|
||||
uiRenderer.renderUI(selectedBuildingType, problemText, messageText, messageColor,
|
||||
isTyping, currentProblem, inputText.toString(), showWrongAnswerJoke,
|
||||
wrongAnswerJoke, time, currentBuilding, currentPlanet, isSwitchingPlanets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
viewport.update(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
batch.dispose();
|
||||
shapeRenderer.dispose();
|
||||
font.dispose();
|
||||
if (backgroundTexture != null) {
|
||||
backgroundTexture.dispose();
|
||||
}
|
||||
if (whitePixel != null) {
|
||||
whitePixel.dispose();
|
||||
}
|
||||
menuRenderer.dispose();
|
||||
}
|
||||
|
||||
// Геттеры и сеттеры
|
||||
public int getWIDTH() { return WIDTH; }
|
||||
public int getHEIGHT() { return HEIGHT; }
|
||||
public int getUI_INPUT_HEIGHT() { return UI_INPUT_HEIGHT; }
|
||||
public int getSelectedBuildingType() { return selectedBuildingType; }
|
||||
public void setSelectedBuildingType(int selectedBuildingType) { this.selectedBuildingType = selectedBuildingType; }
|
||||
public StringBuilder getInputText() { return inputText; }
|
||||
public boolean isTyping() { return isTyping; }
|
||||
public void setTyping(boolean typing) { isTyping = typing; }
|
||||
public String getMessageText() { return messageText; }
|
||||
public void setMessageText(String messageText) { this.messageText = messageText; }
|
||||
public Color getMessageColor() { return messageColor; }
|
||||
public void setMessageColor(Color messageColor) { this.messageColor = messageColor; }
|
||||
public String getProblemText() { return problemText; }
|
||||
public void setProblemText(String problemText) { this.problemText = problemText; }
|
||||
public Array<Building> getBuildings() { return buildings; }
|
||||
public Building getCurrentBuilding() { return currentBuilding; }
|
||||
public void setCurrentBuilding(Building currentBuilding) { this.currentBuilding = currentBuilding; }
|
||||
public MathProblem getCurrentProblem() { return currentProblem; }
|
||||
public void setCurrentProblem(MathProblem currentProblem) { this.currentProblem = currentProblem; }
|
||||
public Random getRandom() { return random; }
|
||||
public Array<Citizen> getCitizens() { return citizens; }
|
||||
public Array<JokeBubble> getJokeBubbles() { return jokeBubbles; }
|
||||
public boolean isShowWrongAnswerJoke() { return showWrongAnswerJoke; }
|
||||
public void setShowWrongAnswerJoke(boolean showWrongAnswerJoke) { this.showWrongAnswerJoke = showWrongAnswerJoke; }
|
||||
public String getWrongAnswerJoke() { return wrongAnswerJoke; }
|
||||
public void setWrongAnswerJoke(String wrongAnswerJoke) { this.wrongAnswerJoke = wrongAnswerJoke; }
|
||||
public float getJokeTimer() { return jokeTimer; }
|
||||
public void setJokeTimer(float jokeTimer) { this.jokeTimer = jokeTimer; }
|
||||
public Texture getWhitePixel() { return whitePixel; }
|
||||
public BitmapFont getFont() { return font; }
|
||||
public GlyphLayout getGlyphLayout() { return glyphLayout; }
|
||||
public ShapeRenderer getShapeRenderer() { return shapeRenderer; }
|
||||
public SpriteBatch getBatch() { return batch; }
|
||||
public float getTime() { return time; }
|
||||
public Planet getCurrentPlanet() { return currentPlanet; }
|
||||
public void setCurrentPlanet(Planet planet) { this.currentPlanet = planet; }
|
||||
public boolean isSwitchingPlanets() { return isSwitchingPlanets; }
|
||||
public Planet getTargetPlanet() { return targetPlanet; }
|
||||
public float getPlanetSwitchTimer() { return planetSwitchTimer; }
|
||||
public GameState getGameState() { return gameState; }
|
||||
public void setGameState(GameState state) { this.gameState = state; }
|
||||
}
|
||||
249
core/src/main/java/com/mygdx/game/AnswerChecker.java
Normal file
249
core/src/main/java/com/mygdx/game/AnswerChecker.java
Normal file
@@ -0,0 +1,249 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
|
||||
public class AnswerChecker {
|
||||
private static final String[][] FUNNY_COMMENTS_BY_PLANET = {
|
||||
// Земля
|
||||
{
|
||||
"Вау! Такое здание видел только в мультиках!",
|
||||
"Архитектор сошел с ума от радости!",
|
||||
"Город стал похож на мультфильм!",
|
||||
"Это самое безумное здание в городе!",
|
||||
"Жители в восторге от этой абсурдности!",
|
||||
"Эй, это похоже на город из моих снов!",
|
||||
"Такое здание украсит любой мультфильм!"
|
||||
},
|
||||
// Марс
|
||||
{
|
||||
"Отлично! Марсианская колония растёт! 🚀",
|
||||
"На Марсе теперь есть своё безумие!",
|
||||
"Эти здания переживут любую пылевую бурю!",
|
||||
"Марсиане будут в восторге! 👽",
|
||||
"Похоже, мы колонизируем Марс!",
|
||||
"Красная планета стала разноцветнее!",
|
||||
"Это здание выглядит инопланетно круто!"
|
||||
},
|
||||
// Венера
|
||||
{
|
||||
"Горячо! Венерианский шедевр готов! 🔥",
|
||||
"Здание плавится от собственной красоты!",
|
||||
"Венера стала ещё ярче! 🌟",
|
||||
"Это здание сияет как сама Венера!",
|
||||
"Похоже, мы выживаем на Венере!",
|
||||
"Такая красота плавит сердце!",
|
||||
"Золотой век венерианской архитектуры!"
|
||||
}
|
||||
};
|
||||
|
||||
private static final String[][] WRONG_ANSWER_JOKES_BY_PLANET = {
|
||||
// Земля
|
||||
{
|
||||
"Твоя математика кривее моих зданий!",
|
||||
"Даже мультяшный архитектор считает лучше!",
|
||||
"Ты что, в мультиках учился математике?",
|
||||
"Ошибка! Попробуй посчитать на пальцах ног!",
|
||||
"Неправильно! Давай еще разочек, как в мультике!",
|
||||
"Бывает! Даже мультяшные гении ошибаются!",
|
||||
"Ой, кажется, ты перепутал с мультипликацией!",
|
||||
"Неверно! Но зато здание выглядит смешнее!"
|
||||
},
|
||||
// Марс
|
||||
{
|
||||
"Неверно! Марсиане считают лучше! 👽",
|
||||
"Ошибка в расчётах! Пылевая буря съела цифры!",
|
||||
"Твоя математика не переживёт марсианскую зиму!",
|
||||
"Неудача! Даже марсоход считает точнее!",
|
||||
"Неправильно! Попробуй считать в скафандре!",
|
||||
"Ошибка! Кислородное голодание сказывается?",
|
||||
"Марсианские калькуляторы не одобряют!",
|
||||
"Неверно! Может, радиация помешала?"
|
||||
},
|
||||
// Венера
|
||||
{
|
||||
"Горячая ошибка! 🔥 Попробуй ещё!",
|
||||
"Неверно! Даже венерианская жара не оправдывает!",
|
||||
"Ошибка! Кислотные облака затуманили разум?",
|
||||
"Неправильно! Слишком жарко для точных расчётов?",
|
||||
"Провал! Венерианские калькуляторы плавятся!",
|
||||
"Неудача! Давление в 90 атмосфер давит на мозги?",
|
||||
"Ошибка! Попробуй считать в теплозащитном костюме!",
|
||||
"Неверно! Золотое сечение не спасло!"
|
||||
}
|
||||
};
|
||||
|
||||
public static void checkAnswer(AbsurdCityBuilder1 game) {
|
||||
if (game.getCurrentBuilding() == null || game.getInputText().length() == 0) {
|
||||
game.setMessageText("Введите ответ!");
|
||||
game.setMessageColor(Color.RED);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int userAnswer = Integer.parseInt(game.getInputText().toString());
|
||||
Planet currentPlanet = game.getCurrentPlanet();
|
||||
int planetIndex = currentPlanet.ordinal();
|
||||
|
||||
if (userAnswer == game.getCurrentProblem().getAnswer()) {
|
||||
// Правильный ответ
|
||||
game.getCurrentBuilding().addBlock();
|
||||
|
||||
String[] planetComments = FUNNY_COMMENTS_BY_PLANET[planetIndex];
|
||||
String successMessage = "Отлично! Блок построен!";
|
||||
|
||||
if (game.getCurrentBuilding().isComplete()) {
|
||||
successMessage = "Успех! " + planetComments[game.getRandom().nextInt(planetComments.length)];
|
||||
game.getBuildings().add(game.getCurrentBuilding());
|
||||
|
||||
// Создаем жителей при завершении здания
|
||||
game.getCurrentBuilding().createCitizensForBuilding(game.getCitizens(), game.getRandom());
|
||||
|
||||
// Проверяем разблокировку планет
|
||||
checkPlanetUnlock(game);
|
||||
|
||||
game.setCurrentBuilding(null);
|
||||
game.setCurrentProblem(null);
|
||||
game.setTyping(false);
|
||||
} else {
|
||||
game.setCurrentProblem(MathProblem.generateProblem(game.getBuildings().size, game.getRandom()));
|
||||
}
|
||||
|
||||
game.setMessageText(successMessage);
|
||||
game.setMessageColor(Color.GREEN);
|
||||
|
||||
} else {
|
||||
// Неправильный ответ
|
||||
game.getCurrentBuilding().removeBlock();
|
||||
|
||||
String[] planetJokes = WRONG_ANSWER_JOKES_BY_PLANET[planetIndex];
|
||||
String joke = planetJokes[game.getRandom().nextInt(planetJokes.length)];
|
||||
game.setWrongAnswerJoke(joke);
|
||||
game.setShowWrongAnswerJoke(true);
|
||||
game.setJokeTimer(0);
|
||||
|
||||
// Создаем пузырь с шуткой
|
||||
if (game.getCitizens().size > 0) {
|
||||
Citizen randomCitizen = game.getCitizens().get(game.getRandom().nextInt(game.getCitizens().size));
|
||||
game.getJokeBubbles().add(new JokeBubble(joke, randomCitizen.x, randomCitizen.y + 60, game.getRandom()));
|
||||
}
|
||||
|
||||
String message;
|
||||
if (game.getCurrentBuilding().constructionProgress == 0) {
|
||||
message = "Здание разрушено до основания! " + joke;
|
||||
game.setCurrentBuilding(null);
|
||||
game.setCurrentProblem(null);
|
||||
game.setTyping(false);
|
||||
} else {
|
||||
message = "Неверно! Блок разрушен! " + joke;
|
||||
game.setCurrentProblem(MathProblem.generateProblem(game.getBuildings().size, game.getRandom()));
|
||||
}
|
||||
|
||||
game.setMessageText(message);
|
||||
game.setMessageColor(Color.RED);
|
||||
}
|
||||
|
||||
game.updateUI();
|
||||
game.getInputText().setLength(0);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
// Обработка некорректного ввода
|
||||
Planet currentPlanet = game.getCurrentPlanet();
|
||||
String errorMessage;
|
||||
|
||||
switch (currentPlanet) {
|
||||
case MARS:
|
||||
errorMessage = "Марсиане не понимают такие цифры! Введите целое число!";
|
||||
break;
|
||||
case VENUS:
|
||||
errorMessage = "Слишком жарко для таких символов! Введите целое число!";
|
||||
break;
|
||||
default:
|
||||
errorMessage = "Введите целое число!";
|
||||
}
|
||||
|
||||
game.setMessageText(errorMessage);
|
||||
game.setMessageColor(Color.RED);
|
||||
game.getInputText().setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkPlanetUnlock(AbsurdCityBuilder1 game) {
|
||||
Planet currentPlanet = game.getCurrentPlanet();
|
||||
int buildingsCount = game.getBuildings().size;
|
||||
|
||||
// Проверяем условия для разблокировки Марса
|
||||
if (currentPlanet == Planet.EARTH && buildingsCount >= 3) {
|
||||
// Марс уже разблокирован по умолчанию в нашей реализации
|
||||
// Но можно добавить специальное сообщение
|
||||
if (buildingsCount == 3) {
|
||||
game.setMessageText(game.getMessageText() + " 🚀 Марс доступен! Нажмите ↑ для полёта!");
|
||||
game.setMessageColor(Color.CYAN);
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем условия для разблокировки Венеры
|
||||
if (currentPlanet == Planet.MARS && buildingsCount >= 6) {
|
||||
// Венера уже разблокирована
|
||||
if (buildingsCount == 6) {
|
||||
game.setMessageText(game.getMessageText() + " 🔥 Венера доступна! Нажмите ↑ для полёта!");
|
||||
game.setMessageColor(Color.ORANGE);
|
||||
}
|
||||
}
|
||||
|
||||
// Бонус за много построек
|
||||
if (buildingsCount % 5 == 0) {
|
||||
String bonusMessage = getBonusMessage(currentPlanet, buildingsCount);
|
||||
game.setMessageText(game.getMessageText() + " " + bonusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getBonusMessage(Planet planet, int buildingsCount) {
|
||||
switch (planet) {
|
||||
case EARTH:
|
||||
return "🎉 Вы построили " + buildingsCount + " зданий на Земле!";
|
||||
case MARS:
|
||||
return "👽 Марсианская колония из " + buildingsCount + " зданий!";
|
||||
case VENUS:
|
||||
return "🌟 Венерианский мегаполис из " + buildingsCount + " зданий!";
|
||||
default:
|
||||
return "🏆 Достижение: " + buildingsCount + " зданий!";
|
||||
}
|
||||
}
|
||||
|
||||
// Метод для получения подсказки (опционально)
|
||||
public static String getHint(MathProblem problem, Planet planet) {
|
||||
int answer = problem.getAnswer();
|
||||
String question = problem.getQuestion();
|
||||
|
||||
switch (planet) {
|
||||
case MARS:
|
||||
if (question.contains("+")) {
|
||||
return "Подсказка: складывай как марсиане - от красного к красному!";
|
||||
} else if (question.contains("-")) {
|
||||
return "Подсказка: вычитай как улетающую ракету!";
|
||||
} else if (question.contains("×")) {
|
||||
return "Подсказка: умножай на количество марсоходов!";
|
||||
}
|
||||
break;
|
||||
case VENUS:
|
||||
if (question.contains("+")) {
|
||||
return "Подсказка: складывай жар как на Венере!";
|
||||
} else if (question.contains("-")) {
|
||||
return "Подсказка: вычитай облака кислоты!";
|
||||
} else if (question.contains("×")) {
|
||||
return "Подсказка: умножай как давление на Венере!";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (question.contains("+")) {
|
||||
return "Подсказка: представь, что складываешь мультяшных зверюшек!";
|
||||
} else if (question.contains("-")) {
|
||||
return "Подсказка: убери лишние мультяшные детали!";
|
||||
} else if (question.contains("×")) {
|
||||
return "Подсказка: умножай как в мультике - всё становится больше!";
|
||||
}
|
||||
}
|
||||
|
||||
return "Подсказка: внимательно посчитай!";
|
||||
}
|
||||
}
|
||||
441
core/src/main/java/com/mygdx/game/Building.java
Normal file
441
core/src/main/java/com/mygdx/game/Building.java
Normal file
@@ -0,0 +1,441 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import java.util.Random;
|
||||
|
||||
public class Building {
|
||||
// Названия зданий по планетам
|
||||
public static final String[][] BUILDING_TYPES_BY_PLANET = {
|
||||
// Земля (существующие здания)
|
||||
{
|
||||
"✨ Уютный Домик ✨",
|
||||
"🏥 Детская Больница 🏥",
|
||||
"🎒 Весёлая Школа 🎒",
|
||||
"🎪 Игровая Площадка 🎪",
|
||||
"💰 Надёжный Банк 💰",
|
||||
"💊 Здоровая Аптека 💊",
|
||||
"🎭 Волшебный Театр 🎭",
|
||||
"🎬 КиноМир 🎬"
|
||||
},
|
||||
// Марс (красные, технологичные)
|
||||
{
|
||||
"🚀 Марсианская База 🚀",
|
||||
"🔴 Красная Лаборатория 🔴",
|
||||
"🛰️ Космопорт 🛰️",
|
||||
"⚡ Энергокупол ⚡",
|
||||
"💧 Водородный Завод 💧",
|
||||
"🌌 Обсерватория 🌌",
|
||||
"🤖 Робо-Фабрика 🤖",
|
||||
"🧪 Биокупол 🧪"
|
||||
},
|
||||
// Венера (желтые, вулканические)
|
||||
{
|
||||
"🌋 Вулканический Дом 🌋",
|
||||
"🔥 Термальная Станция 🔥",
|
||||
"🌅 Золотой Дворец 🌅",
|
||||
"☁️ Облачный Город ☁️",
|
||||
"💎 Кристальная Шахта 💎",
|
||||
"🌡️ Теплица 🌡️",
|
||||
"🌀 Вихревой Генератор 🌀",
|
||||
"✨ Сияющая Башня ✨"
|
||||
}
|
||||
};
|
||||
|
||||
// Яркие цвета для разных планет
|
||||
public static final Color[][][] BUILDING_COLOR_THEMES_BY_PLANET = {
|
||||
// 0. Земля - тёплые цвета
|
||||
{
|
||||
// Дома - тёплые цвета
|
||||
{
|
||||
new Color(1.0f, 0.85f, 0.7f, 1), // Персиковый
|
||||
new Color(0.95f, 0.9f, 0.75f, 1), // Светло-бежевый
|
||||
new Color(0.9f, 0.8f, 0.85f, 1) // Розоватый
|
||||
},
|
||||
// Больницы - чистые светлые цвета
|
||||
{
|
||||
new Color(1.0f, 1.0f, 1.0f, 1), // Белоснежный
|
||||
new Color(0.98f, 0.98f, 1.0f, 1), // Голубоватый
|
||||
new Color(0.96f, 1.0f, 0.98f, 1) // Мятный
|
||||
},
|
||||
// Школы - яркие весёлые цвета
|
||||
{
|
||||
new Color(1.0f, 0.95f, 0.8f, 1), // Лимонный
|
||||
new Color(0.85f, 0.95f, 1.0f, 1), // Небесно-голубой
|
||||
new Color(0.95f, 0.85f, 1.0f, 1) // Лавандовый
|
||||
},
|
||||
// Игровые площадки - яркие игровые цвета
|
||||
{
|
||||
new Color(1.0f, 0.9f, 0.8f, 1), // Абрикосовый
|
||||
new Color(0.9f, 1.0f, 0.9f, 1), // Салатовый
|
||||
new Color(0.9f, 0.9f, 1.0f, 1) // Сиреневый
|
||||
},
|
||||
// Банки - солидные цвета
|
||||
{
|
||||
new Color(0.95f, 0.95f, 0.9f, 1), // Слоновая кость
|
||||
new Color(0.9f, 0.92f, 0.85f, 1), // Бежевый
|
||||
new Color(0.85f, 0.89f, 0.8f, 1) // Оливковый
|
||||
},
|
||||
// Аптеки - медицинские цвета
|
||||
{
|
||||
new Color(1.0f, 1.0f, 1.0f, 1), // Белый
|
||||
new Color(0.98f, 1.0f, 0.98f, 1), // Светло-зелёный
|
||||
new Color(0.96f, 0.98f, 1.0f, 1) // Светло-голубой
|
||||
},
|
||||
// Театры - благородные цвета
|
||||
{
|
||||
new Color(0.95f, 0.9f, 0.95f, 1), // Сиреневый
|
||||
new Color(0.9f, 0.95f, 1.0f, 1), // Лазурный
|
||||
new Color(1.0f, 0.95f, 0.9f, 1) // Кремовый
|
||||
},
|
||||
// Кинотеатры - тёмные с неоном
|
||||
{
|
||||
new Color(0.2f, 0.2f, 0.3f, 1), // Тёмно-синий
|
||||
new Color(0.3f, 0.2f, 0.4f, 1), // Фиолетовый
|
||||
new Color(0.4f, 0.3f, 0.5f, 1) // Пурпурный
|
||||
}
|
||||
},
|
||||
// 1. Марс - красные, оранжевые, коричневые
|
||||
{
|
||||
// Марсианская База
|
||||
{
|
||||
new Color(0.8f, 0.3f, 0.2f, 1), // Красный марсианский
|
||||
new Color(0.9f, 0.5f, 0.3f, 1), // Оранжевый
|
||||
new Color(0.7f, 0.4f, 0.3f, 1) // Коричневый
|
||||
},
|
||||
// Красная Лаборатория
|
||||
{
|
||||
new Color(0.9f, 0.4f, 0.4f, 1),
|
||||
new Color(1.0f, 0.6f, 0.5f, 1),
|
||||
new Color(0.8f, 0.5f, 0.5f, 1)
|
||||
},
|
||||
// Космопорт
|
||||
{
|
||||
new Color(0.7f, 0.5f, 0.4f, 1),
|
||||
new Color(0.8f, 0.6f, 0.5f, 1),
|
||||
new Color(0.6f, 0.4f, 0.3f, 1)
|
||||
},
|
||||
// Энергокупол
|
||||
{
|
||||
new Color(0.9f, 0.6f, 0.3f, 1),
|
||||
new Color(1.0f, 0.7f, 0.4f, 1),
|
||||
new Color(0.8f, 0.5f, 0.2f, 1)
|
||||
},
|
||||
// Водородный Завод
|
||||
{
|
||||
new Color(0.6f, 0.7f, 0.8f, 1),
|
||||
new Color(0.7f, 0.8f, 0.9f, 1),
|
||||
new Color(0.5f, 0.6f, 0.7f, 1)
|
||||
},
|
||||
// Обсерватория
|
||||
{
|
||||
new Color(0.3f, 0.4f, 0.6f, 1),
|
||||
new Color(0.4f, 0.5f, 0.7f, 1),
|
||||
new Color(0.2f, 0.3f, 0.5f, 1)
|
||||
},
|
||||
// Робо-Фабрика
|
||||
{
|
||||
new Color(0.5f, 0.5f, 0.5f, 1),
|
||||
new Color(0.6f, 0.6f, 0.6f, 1),
|
||||
new Color(0.4f, 0.4f, 0.4f, 1)
|
||||
},
|
||||
// Биокупол
|
||||
{
|
||||
new Color(0.4f, 0.7f, 0.4f, 1),
|
||||
new Color(0.5f, 0.8f, 0.5f, 1),
|
||||
new Color(0.3f, 0.6f, 0.3f, 1)
|
||||
}
|
||||
},
|
||||
// 2. Венера - желтые, золотые, оранжевые
|
||||
{
|
||||
// Вулканический Дом
|
||||
{
|
||||
new Color(1.0f, 0.7f, 0.3f, 1), // Золотистый
|
||||
new Color(1.0f, 0.8f, 0.4f, 1), // Желтый
|
||||
new Color(0.9f, 0.6f, 0.2f, 1) // Оранжевый
|
||||
},
|
||||
// Термальная Станция
|
||||
{
|
||||
new Color(1.0f, 0.6f, 0.2f, 1),
|
||||
new Color(1.0f, 0.7f, 0.3f, 1),
|
||||
new Color(0.9f, 0.5f, 0.1f, 1)
|
||||
},
|
||||
// Золотой Дворец
|
||||
{
|
||||
new Color(1.0f, 0.9f, 0.3f, 1),
|
||||
new Color(1.0f, 1.0f, 0.5f, 1),
|
||||
new Color(0.9f, 0.8f, 0.2f, 1)
|
||||
},
|
||||
// Облачный Город
|
||||
{
|
||||
new Color(1.0f, 0.95f, 0.8f, 1),
|
||||
new Color(1.0f, 1.0f, 0.9f, 1),
|
||||
new Color(0.95f, 0.9f, 0.7f, 1)
|
||||
},
|
||||
// Кристальная Шахта
|
||||
{
|
||||
new Color(0.8f, 0.9f, 1.0f, 1),
|
||||
new Color(0.9f, 1.0f, 1.0f, 1),
|
||||
new Color(0.7f, 0.8f, 0.9f, 1)
|
||||
},
|
||||
// Теплица
|
||||
{
|
||||
new Color(0.7f, 0.9f, 0.6f, 1),
|
||||
new Color(0.8f, 1.0f, 0.7f, 1),
|
||||
new Color(0.6f, 0.8f, 0.5f, 1)
|
||||
},
|
||||
// Вихревой Генератор
|
||||
{
|
||||
new Color(0.9f, 0.8f, 0.5f, 1),
|
||||
new Color(1.0f, 0.9f, 0.6f, 1),
|
||||
new Color(0.8f, 0.7f, 0.4f, 1)
|
||||
},
|
||||
// Сияющая Башня
|
||||
{
|
||||
new Color(1.0f, 0.95f, 0.7f, 1),
|
||||
new Color(1.0f, 1.0f, 0.8f, 1),
|
||||
new Color(0.95f, 0.9f, 0.6f, 1)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Крыши в мультяшных цветах по планетам
|
||||
public static final Color[][][] ROOF_COLORS_BY_PLANET = {
|
||||
// Земля
|
||||
{
|
||||
{ new Color(0.9f, 0.3f, 0.2f, 1), new Color(0.7f, 0.4f, 0.2f, 1) }, // Дома
|
||||
{ new Color(1.0f, 0.8f, 0.8f, 1), new Color(0.9f, 0.7f, 0.7f, 1) }, // Больницы
|
||||
{ new Color(0.4f, 0.7f, 1.0f, 1), new Color(0.3f, 0.6f, 0.9f, 1) }, // Школы
|
||||
{ new Color(1.0f, 0.8f, 0.4f, 1), new Color(0.9f, 0.5f, 0.9f, 1) }, // Площадки
|
||||
{ new Color(1.0f, 0.9f, 0.3f, 1), new Color(0.9f, 0.8f, 0.2f, 1) }, // Банки
|
||||
{ new Color(0.4f, 0.9f, 0.5f, 1), new Color(0.3f, 0.8f, 0.4f, 1) }, // Аптеки
|
||||
{ new Color(0.8f, 0.4f, 1.0f, 1), new Color(0.7f, 0.3f, 0.9f, 1) }, // Театры
|
||||
{ new Color(0.3f, 0.3f, 0.4f, 1), new Color(0.4f, 0.3f, 0.5f, 1) } // Кинотеатры
|
||||
},
|
||||
// Марс
|
||||
{
|
||||
{ new Color(0.7f, 0.2f, 0.1f, 1), new Color(0.6f, 0.1f, 0.0f, 1) }, // Марсианская База
|
||||
{ new Color(0.8f, 0.3f, 0.2f, 1), new Color(0.7f, 0.2f, 0.1f, 1) }, // Красная Лаборатория
|
||||
{ new Color(0.5f, 0.4f, 0.3f, 1), new Color(0.4f, 0.3f, 0.2f, 1) }, // Космопорт
|
||||
{ new Color(0.8f, 0.5f, 0.2f, 1), new Color(0.7f, 0.4f, 0.1f, 1) }, // Энергокупол
|
||||
{ new Color(0.4f, 0.5f, 0.7f, 1), new Color(0.3f, 0.4f, 0.6f, 1) }, // Водородный Завод
|
||||
{ new Color(0.2f, 0.3f, 0.5f, 1), new Color(0.1f, 0.2f, 0.4f, 1) }, // Обсерватория
|
||||
{ new Color(0.4f, 0.4f, 0.4f, 1), new Color(0.3f, 0.3f, 0.3f, 1) }, // Робо-Фабрика
|
||||
{ new Color(0.3f, 0.6f, 0.3f, 1), new Color(0.2f, 0.5f, 0.2f, 1) } // Биокупол
|
||||
},
|
||||
// Венера
|
||||
{
|
||||
{ new Color(0.8f, 0.4f, 0.1f, 1), new Color(0.7f, 0.3f, 0.0f, 1) }, // Вулканический Дом
|
||||
{ new Color(0.9f, 0.5f, 0.1f, 1), new Color(0.8f, 0.4f, 0.0f, 1) }, // Термальная Станция
|
||||
{ new Color(1.0f, 0.8f, 0.1f, 1), new Color(0.9f, 0.7f, 0.0f, 1) }, // Золотой Дворец
|
||||
{ new Color(1.0f, 1.0f, 0.8f, 1), new Color(0.9f, 0.9f, 0.7f, 1) }, // Облачный Город
|
||||
{ new Color(0.7f, 0.8f, 0.9f, 1), new Color(0.6f, 0.7f, 0.8f, 1) }, // Кристальная Шахта
|
||||
{ new Color(0.6f, 0.8f, 0.5f, 1), new Color(0.5f, 0.7f, 0.4f, 1) }, // Теплица
|
||||
{ new Color(0.8f, 0.7f, 0.4f, 1), new Color(0.7f, 0.6f, 0.3f, 1) }, // Вихревой Генератор
|
||||
{ new Color(0.95f, 0.9f, 0.6f, 1), new Color(0.85f, 0.8f, 0.5f, 1) } // Сияющая Башня
|
||||
}
|
||||
};
|
||||
|
||||
// Коэффициенты масштабирования для разных планет
|
||||
public static final float[][] SIZE_SCALE_FACTORS_BY_PLANET = {
|
||||
// Земля
|
||||
{1.0f, 0.75f, 0.8f, 0.85f, 0.7f, 0.65f, 0.8f, 0.85f},
|
||||
// Марс (компактнее)
|
||||
{0.9f, 0.7f, 0.8f, 0.75f, 0.65f, 0.6f, 0.7f, 0.75f},
|
||||
// Венера (выше)
|
||||
{1.1f, 1.0f, 1.05f, 1.0f, 0.9f, 0.85f, 1.0f, 1.05f}
|
||||
};
|
||||
|
||||
// Цвета для деталей по планетам
|
||||
public static final Color[][] DETAIL_COLORS_BY_PLANET = {
|
||||
// Земля
|
||||
{
|
||||
new Color(1.0f, 0.9f, 0.2f, 1), // Золотой
|
||||
new Color(1.0f, 0.5f, 0.5f, 1), // Коралловый
|
||||
new Color(0.5f, 0.8f, 1.0f, 1), // Голубой
|
||||
new Color(0.8f, 1.0f, 0.5f, 1), // Лаймовый
|
||||
new Color(1.0f, 0.7f, 1.0f, 1) // Розовый
|
||||
},
|
||||
// Марс
|
||||
{
|
||||
new Color(1.0f, 0.6f, 0.2f, 1), // Оранжевый
|
||||
new Color(0.8f, 0.3f, 0.2f, 1), // Красный
|
||||
new Color(0.9f, 0.8f, 0.4f, 1), // Песочный
|
||||
new Color(0.7f, 0.8f, 0.9f, 1), // Стальной
|
||||
new Color(0.4f, 0.7f, 0.4f, 1) // Зеленый марсианский
|
||||
},
|
||||
// Венера
|
||||
{
|
||||
new Color(1.0f, 0.9f, 0.3f, 1), // Золотой
|
||||
new Color(1.0f, 0.7f, 0.2f, 1), // Янтарный
|
||||
new Color(1.0f, 1.0f, 0.8f, 1), // Светло-желтый
|
||||
new Color(0.9f, 0.6f, 0.1f, 1), // Темно-оранжевый
|
||||
new Color(0.8f, 0.9f, 1.0f, 1) // Кристальный
|
||||
}
|
||||
};
|
||||
|
||||
// Цвета для названий по планетам
|
||||
public static final Color[][] GLOWING_NAME_COLORS_BY_PLANET = {
|
||||
// Земля
|
||||
{
|
||||
new Color(0.3f, 0.7f, 1.0f, 1), // Ярко-синий
|
||||
new Color(1.0f, 0.4f, 0.4f, 1), // Ярко-красный
|
||||
new Color(0.3f, 0.9f, 0.3f, 1), // Ярко-зелёный
|
||||
new Color(1.0f, 0.7f, 0.2f, 1), // Оранжевый
|
||||
new Color(0.8f, 0.4f, 1.0f, 1) // Фиолетовый
|
||||
},
|
||||
// Марс
|
||||
{
|
||||
new Color(1.0f, 0.5f, 0.3f, 1), // Оранжево-красный
|
||||
new Color(0.8f, 0.3f, 0.2f, 1), // Марсианский красный
|
||||
new Color(0.9f, 0.7f, 0.4f, 1), // Песочный
|
||||
new Color(0.6f, 0.8f, 0.9f, 1), // Голубой стальной
|
||||
new Color(0.4f, 0.6f, 0.3f, 1) // Оливковый
|
||||
},
|
||||
// Венера
|
||||
{
|
||||
new Color(1.0f, 0.9f, 0.3f, 1), // Золотой
|
||||
new Color(1.0f, 0.7f, 0.2f, 1), // Янтарный
|
||||
new Color(1.0f, 1.0f, 0.6f, 1), // Ярко-желтый
|
||||
new Color(0.9f, 0.5f, 0.1f, 1), // Теплый оранжевый
|
||||
new Color(1.0f, 0.95f, 0.8f, 1) // Светло-золотой
|
||||
}
|
||||
};
|
||||
|
||||
String type;
|
||||
float x;
|
||||
float y;
|
||||
float width;
|
||||
float height;
|
||||
Color[] colors;
|
||||
Color roofColor;
|
||||
Color detailColor;
|
||||
int constructionProgress;
|
||||
boolean isOverlapping;
|
||||
float[] cloudOffsets;
|
||||
int colorThemeIndex;
|
||||
boolean showName;
|
||||
float namePulse;
|
||||
Color nameColor;
|
||||
float nameYOffset;
|
||||
float wobbleOffset;
|
||||
float wobbleSpeed;
|
||||
float animationTimer;
|
||||
float animationSpeed;
|
||||
int buildingTypeIndex;
|
||||
float sizeScale;
|
||||
Random random;
|
||||
Planet planet;
|
||||
int planetIndex;
|
||||
|
||||
public Building(String type, float x, float y, float width, float height, Random random, Planet planet) {
|
||||
this.type = type;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.random = random;
|
||||
this.planet = planet;
|
||||
this.planetIndex = planet.ordinal();
|
||||
|
||||
this.buildingTypeIndex = findBuildingTypeIndex(type, planet);
|
||||
this.sizeScale = SIZE_SCALE_FACTORS_BY_PLANET[planetIndex][buildingTypeIndex];
|
||||
this.colorThemeIndex = random.nextInt(3);
|
||||
this.colors = BUILDING_COLOR_THEMES_BY_PLANET[planetIndex][buildingTypeIndex];
|
||||
this.roofColor = ROOF_COLORS_BY_PLANET[planetIndex][buildingTypeIndex][random.nextInt(2)];
|
||||
|
||||
Color[] planetDetailColors = DETAIL_COLORS_BY_PLANET[planetIndex];
|
||||
this.detailColor = planetDetailColors[random.nextInt(planetDetailColors.length)];
|
||||
|
||||
Color[] planetNameColors = GLOWING_NAME_COLORS_BY_PLANET[planetIndex];
|
||||
this.nameColor = planetNameColors[random.nextInt(planetNameColors.length)];
|
||||
|
||||
this.constructionProgress = 0;
|
||||
this.isOverlapping = false;
|
||||
this.showName = false;
|
||||
this.namePulse = random.nextFloat() * 100;
|
||||
this.nameYOffset = 0;
|
||||
this.wobbleOffset = random.nextFloat() * 100;
|
||||
this.wobbleSpeed = 0.3f + random.nextFloat() * 0.7f;
|
||||
this.animationTimer = random.nextFloat() * 100;
|
||||
this.animationSpeed = 0.5f + random.nextFloat() * 1.0f;
|
||||
this.cloudOffsets = new float[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
cloudOffsets[i] = random.nextFloat() * 100;
|
||||
}
|
||||
}
|
||||
|
||||
private int findBuildingTypeIndex(String type, Planet planet) {
|
||||
String[] planetBuildings = BUILDING_TYPES_BY_PLANET[planet.ordinal()];
|
||||
for (int i = 0; i < planetBuildings.length; i++) {
|
||||
if (planetBuildings[i].equals(type)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void addBlock() {
|
||||
if (constructionProgress < 3) constructionProgress++;
|
||||
if (isComplete()) {
|
||||
showName = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeBlock() {
|
||||
if (constructionProgress > 0) constructionProgress--;
|
||||
if (!isComplete()) {
|
||||
showName = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isComplete() { return constructionProgress >= 3; }
|
||||
public float getCurrentHeight() { return (height * constructionProgress) / 3.0f; }
|
||||
public Rectangle getBounds() { return new Rectangle(x, y, width, getCurrentHeight()); }
|
||||
public Planet getPlanet() { return planet; }
|
||||
|
||||
public void update(float deltaTime) {
|
||||
animationTimer += deltaTime * animationSpeed;
|
||||
|
||||
if (showName) {
|
||||
namePulse += deltaTime * 2;
|
||||
nameYOffset = (float)Math.sin(namePulse * 0.5f) * 3;
|
||||
}
|
||||
|
||||
if (isComplete()) {
|
||||
wobbleOffset += deltaTime * wobbleSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
public float getWobbleX() {
|
||||
if (!isComplete()) return 0;
|
||||
return (float)Math.sin(wobbleOffset) * 2;
|
||||
}
|
||||
|
||||
public float getWobbleY() {
|
||||
if (!isComplete()) return 0;
|
||||
return (float)Math.cos(wobbleOffset * 1.5f) * 1.5f;
|
||||
}
|
||||
|
||||
public void createCitizensForBuilding(Array<Citizen> citizens, Random random) {
|
||||
int citizenCount = 2 + random.nextInt(3);
|
||||
|
||||
for (int i = 0; i < citizenCount; i++) {
|
||||
float citizenX = x + random.nextFloat() * width;
|
||||
float citizenY = y - 40;
|
||||
Color clothesColor = DETAIL_COLORS_BY_PLANET[planetIndex][random.nextInt(DETAIL_COLORS_BY_PLANET[planetIndex].length)];
|
||||
|
||||
Citizen citizen = new Citizen(citizenX, citizenY, clothesColor, this, random, planet);
|
||||
citizens.add(citizen);
|
||||
}
|
||||
}
|
||||
|
||||
public float getSizeScale() {
|
||||
return sizeScale;
|
||||
}
|
||||
|
||||
public Color getDetailColor() {
|
||||
return detailColor;
|
||||
}
|
||||
}
|
||||
112
core/src/main/java/com/mygdx/game/BuildingPlacer.java
Normal file
112
core/src/main/java/com/mygdx/game/BuildingPlacer.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
|
||||
public class BuildingPlacer {
|
||||
public static void startNewBuildingAt(AbsurdCityBuilder1 game, float worldX, float worldY) {
|
||||
Planet planet = game.getCurrentPlanet();
|
||||
String[] planetBuildings = Building.BUILDING_TYPES_BY_PLANET[planet.ordinal()];
|
||||
String selectedType = planetBuildings[game.getSelectedBuildingType()];
|
||||
|
||||
float width, height;
|
||||
|
||||
// Разные размеры для разных планет
|
||||
switch (planet) {
|
||||
case EARTH:
|
||||
switch (game.getSelectedBuildingType()) {
|
||||
case 0: width = 180; height = 200; break; // Уютный Домик
|
||||
case 1: width = 160; height = 180; break; // Детская Больница
|
||||
case 2: width = 190; height = 170; break; // Весёлая Школа
|
||||
case 3: width = 200; height = 160; break; // Игровая Площадка
|
||||
case 4: width = 140; height = 180; break; // Надёжный Банк
|
||||
case 5: width = 130; height = 160; break; // Здоровая Аптека
|
||||
case 6: width = 190; height = 200; break; // Волшебный Театр
|
||||
case 7: width = 180; height = 170; break; // КиноМир
|
||||
default: width = 180; height = 200; break;
|
||||
}
|
||||
break;
|
||||
case MARS:
|
||||
// Марсианские здания (компактнее)
|
||||
switch (game.getSelectedBuildingType()) {
|
||||
case 0: width = 150; height = 180; break; // Марсианская База
|
||||
case 1: width = 140; height = 160; break; // Красная Лаборатория
|
||||
case 2: width = 170; height = 150; break; // Космопорт
|
||||
case 3: width = 160; height = 170; break; // Энергокупол
|
||||
case 4: width = 130; height = 160; break; // Водородный Завод
|
||||
case 5: width = 120; height = 150; break; // Обсерватория
|
||||
case 6: width = 140; height = 140; break; // Робо-Фабрика
|
||||
case 7: width = 150; height = 160; break; // Биокупол
|
||||
default: width = 150; height = 160; break;
|
||||
}
|
||||
break;
|
||||
case VENUS:
|
||||
// Венерианские здания (выше)
|
||||
switch (game.getSelectedBuildingType()) {
|
||||
case 0: width = 130; height = 200; break; // Вулканический Дом
|
||||
case 1: width = 160; height = 190; break; // Термальная Станция
|
||||
case 2: width = 180; height = 210; break; // Золотой Дворец
|
||||
case 3: width = 170; height = 180; break; // Облачный Город
|
||||
case 4: width = 140; height = 170; break; // Кристальная Шахта
|
||||
case 5: width = 120; height = 160; break; // Теплица
|
||||
case 6: width = 150; height = 190; break; // Вихревой Генератор
|
||||
case 7: width = 160; height = 210; break; // Сияющая Башня
|
||||
default: width = 150; height = 190; break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
width = 180; height = 200; break;
|
||||
}
|
||||
|
||||
float x = worldX;
|
||||
float y = worldY;
|
||||
|
||||
if (x < 10) x = 10;
|
||||
if (x + width > game.getWIDTH() - 10) x = game.getWIDTH() - width - 10;
|
||||
if (y + height > game.getHEIGHT()) y = game.getHEIGHT() - height;
|
||||
if (y < game.getUI_INPUT_HEIGHT() + 10) y = game.getUI_INPUT_HEIGHT() + 10;
|
||||
|
||||
Building tempBuilding = new Building(selectedType, x, y, width, height, game.getRandom(), planet);
|
||||
tempBuilding.isOverlapping = checkForOverlaps(tempBuilding, game.getBuildings());
|
||||
game.setCurrentBuilding(tempBuilding);
|
||||
game.setCurrentProblem(MathProblem.generateProblem(game.getBuildings().size, game.getRandom()));
|
||||
|
||||
game.updateUI();
|
||||
|
||||
game.setMessageText(tempBuilding.isOverlapping ?
|
||||
"🎨 Здание пересекается с существующими! Это добавляет уникальности! 🎨" :
|
||||
"🌟 Отличное место для строительства! Введите ответ: 🌟");
|
||||
game.setMessageColor(tempBuilding.isOverlapping ? com.badlogic.gdx.graphics.Color.ORANGE : com.badlogic.gdx.graphics.Color.GREEN);
|
||||
|
||||
game.setTyping(true);
|
||||
game.getInputText().setLength(0);
|
||||
}
|
||||
|
||||
public static void handleBuildingClick(AbsurdCityBuilder1 game, float worldX, float worldY) {
|
||||
if (game.getCurrentBuilding() != null) {
|
||||
Rectangle buildingBounds = game.getCurrentBuilding().getBounds();
|
||||
if (buildingBounds.contains(worldX, worldY)) {
|
||||
game.setMessageText("🎯 Кликните вне здания для нового строительства. Ctrl+Z или Delete для удаления. 🎯");
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.CYAN);
|
||||
} else {
|
||||
if (!game.isTyping()) {
|
||||
startNewBuildingAt(game, worldX, worldY);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startNewBuildingAt(game, worldX, worldY);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkForOverlaps(Building building, com.badlogic.gdx.utils.Array<Building> buildings) {
|
||||
for (Building existing : buildings) {
|
||||
if (isOverlapping(building.x, building.width, existing.x, existing.width)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isOverlapping(float x1, float width1, float x2, float width2) {
|
||||
return x1 < x2 + width2 && x1 + width1 > x2;
|
||||
}
|
||||
}
|
||||
1302
core/src/main/java/com/mygdx/game/BuildingRenderer.java
Normal file
1302
core/src/main/java/com/mygdx/game/BuildingRenderer.java
Normal file
File diff suppressed because it is too large
Load Diff
203
core/src/main/java/com/mygdx/game/Citizen.java
Normal file
203
core/src/main/java/com/mygdx/game/Citizen.java
Normal file
@@ -0,0 +1,203 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import java.util.Random;
|
||||
|
||||
public class Citizen {
|
||||
float x, y;
|
||||
float targetX;
|
||||
float speed;
|
||||
Color clothesColor;
|
||||
float walkTimer;
|
||||
Building homeBuilding;
|
||||
float bobOffset;
|
||||
float bobSpeed;
|
||||
boolean isMoving;
|
||||
float size;
|
||||
float emotionTimer;
|
||||
boolean isHappy;
|
||||
Random random;
|
||||
float headSize;
|
||||
Planet planet;
|
||||
|
||||
public Citizen(float x, float y, Color clothesColor, Building homeBuilding, Random random, Planet planet) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.targetX = x + (random.nextFloat() - 0.5f) * 300;
|
||||
this.speed = 40 + random.nextFloat() * 60;
|
||||
this.clothesColor = clothesColor;
|
||||
this.walkTimer = random.nextFloat() * 100;
|
||||
this.homeBuilding = homeBuilding;
|
||||
this.bobOffset = random.nextFloat() * 100;
|
||||
this.bobSpeed = 1 + random.nextFloat() * 2;
|
||||
this.isMoving = random.nextBoolean();
|
||||
this.size = 0.9f + random.nextFloat() * 0.3f;
|
||||
this.headSize = 12 * size;
|
||||
this.emotionTimer = random.nextFloat() * 5;
|
||||
this.isHappy = random.nextBoolean();
|
||||
this.random = random;
|
||||
this.planet = planet;
|
||||
}
|
||||
|
||||
public void update(float deltaTime) {
|
||||
walkTimer += deltaTime;
|
||||
bobOffset += deltaTime * bobSpeed;
|
||||
emotionTimer += deltaTime;
|
||||
|
||||
if (emotionTimer > 3) {
|
||||
isHappy = !isHappy;
|
||||
emotionTimer = 0;
|
||||
}
|
||||
|
||||
if (isMoving) {
|
||||
float direction = targetX > x ? 1 : -1;
|
||||
x += direction * speed * deltaTime;
|
||||
|
||||
if (Math.abs(x - targetX) < 10) {
|
||||
targetX = homeBuilding.x + (random.nextFloat() - 0.5f) * homeBuilding.width;
|
||||
isMoving = random.nextBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
if (random.nextFloat() < 0.005f) {
|
||||
isMoving = !isMoving;
|
||||
if (isMoving) {
|
||||
targetX = homeBuilding.x + (random.nextFloat() - 0.5f) * homeBuilding.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(ShapeRenderer shapeRenderer, float time) {
|
||||
float currentY = y + (float)Math.sin(bobOffset) * 5;
|
||||
float scale = size;
|
||||
|
||||
// Разный цвет кожи для разных планет
|
||||
Color skinColor;
|
||||
switch (planet) {
|
||||
case EARTH:
|
||||
skinColor = new Color(1.0f, 0.92f, 0.82f, 1);
|
||||
break;
|
||||
case MARS:
|
||||
skinColor = new Color(0.95f, 0.7f, 0.6f, 1); // Красноватый
|
||||
break;
|
||||
case VENUS:
|
||||
skinColor = new Color(1.0f, 0.85f, 0.7f, 1); // Золотистый
|
||||
break;
|
||||
default:
|
||||
skinColor = new Color(1.0f, 0.92f, 0.82f, 1);
|
||||
}
|
||||
|
||||
// Голова
|
||||
shapeRenderer.setColor(skinColor);
|
||||
shapeRenderer.circle(x, currentY + 25 * scale, headSize);
|
||||
|
||||
// Разные прически для разных планет
|
||||
shapeRenderer.setColor(getHairColor());
|
||||
switch (planet) {
|
||||
case EARTH:
|
||||
shapeRenderer.rect(x - headSize * 0.7f, currentY + 25 * scale + headSize * 0.5f,
|
||||
headSize * 1.4f, headSize * 0.5f);
|
||||
break;
|
||||
case MARS:
|
||||
// Антенны вместо волос
|
||||
shapeRenderer.setColor(Color.GRAY);
|
||||
shapeRenderer.rectLine(x, currentY + 25 * scale + headSize,
|
||||
x, currentY + 25 * scale + headSize + 15 * scale,
|
||||
3 * scale);
|
||||
shapeRenderer.circle(x, currentY + 25 * scale + headSize + 15 * scale, 5 * scale);
|
||||
break;
|
||||
case VENUS:
|
||||
// Кристаллическая "прическа"
|
||||
shapeRenderer.setColor(new Color(1.0f, 0.9f, 0.3f, 1));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float crystalX = x - headSize * 0.5f + i * headSize * 0.5f;
|
||||
shapeRenderer.triangle(crystalX - 3 * scale, currentY + 25 * scale + headSize * 0.5f,
|
||||
crystalX + 3 * scale, currentY + 25 * scale + headSize * 0.5f,
|
||||
crystalX, currentY + 25 * scale + headSize * 0.5f + 10 * scale);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Тело
|
||||
shapeRenderer.setColor(clothesColor);
|
||||
shapeRenderer.rect(x - 10 * scale, currentY, 20 * scale, 25 * scale);
|
||||
|
||||
// Глаза
|
||||
shapeRenderer.setColor(Color.WHITE);
|
||||
shapeRenderer.circle(x - headSize * 0.3f, currentY + 25 * scale + headSize * 0.2f, headSize * 0.25f);
|
||||
shapeRenderer.circle(x + headSize * 0.3f, currentY + 25 * scale + headSize * 0.2f, headSize * 0.25f);
|
||||
|
||||
// Зрачки
|
||||
shapeRenderer.setColor(getEyeColor());
|
||||
shapeRenderer.circle(x - headSize * 0.3f, currentY + 25 * scale + headSize * 0.2f, headSize * 0.1f);
|
||||
shapeRenderer.circle(x + headSize * 0.3f, currentY + 25 * scale + headSize * 0.2f, headSize * 0.1f);
|
||||
|
||||
// Блеск в глазах
|
||||
shapeRenderer.setColor(Color.WHITE);
|
||||
shapeRenderer.circle(x - headSize * 0.35f, currentY + 25 * scale + headSize * 0.25f, headSize * 0.05f);
|
||||
shapeRenderer.circle(x + headSize * 0.25f, currentY + 25 * scale + headSize * 0.25f, headSize * 0.05f);
|
||||
|
||||
// Рот
|
||||
shapeRenderer.setColor(new Color(0.8f, 0.3f, 0.4f, 1));
|
||||
if (isHappy) {
|
||||
shapeRenderer.arc(x, currentY + 25 * scale, headSize * 0.4f, 180, 180, 20);
|
||||
} else {
|
||||
shapeRenderer.rectLine(x - headSize * 0.4f, currentY + 25 * scale,
|
||||
x + headSize * 0.4f, currentY + 25 * scale,
|
||||
headSize * 0.08f);
|
||||
}
|
||||
|
||||
// Руки
|
||||
shapeRenderer.setColor(skinColor);
|
||||
float armOffset = isMoving ? (float)Math.sin(walkTimer * 10) * 10 * scale : 0;
|
||||
shapeRenderer.rectLine(x - 10 * scale, currentY + 15 * scale,
|
||||
x - 20 * scale, currentY + 5 * scale - armOffset,
|
||||
headSize * 0.2f);
|
||||
shapeRenderer.rectLine(x + 10 * scale, currentY + 15 * scale,
|
||||
x + 20 * scale, currentY + 5 * scale + armOffset,
|
||||
headSize * 0.2f);
|
||||
|
||||
// Ноги
|
||||
shapeRenderer.setColor(new Color(0.3f, 0.2f, 0.1f, 1));
|
||||
float legOffset = isMoving ? (float)Math.sin(walkTimer * 10 + 3.14f) * 8 * scale : 0;
|
||||
shapeRenderer.rectLine(x - 5 * scale, currentY,
|
||||
x - 10 * scale, currentY - 15 * scale + legOffset,
|
||||
headSize * 0.25f);
|
||||
shapeRenderer.rectLine(x + 5 * scale, currentY,
|
||||
x + 10 * scale, currentY - 15 * scale - legOffset,
|
||||
headSize * 0.25f);
|
||||
|
||||
// Обувь
|
||||
shapeRenderer.setColor(Color.BLACK);
|
||||
shapeRenderer.rect(x - 12 * scale, currentY - 18 * scale + legOffset,
|
||||
headSize * 0.4f, headSize * 0.2f);
|
||||
shapeRenderer.rect(x + 8 * scale, currentY - 18 * scale - legOffset,
|
||||
headSize * 0.4f, headSize * 0.2f);
|
||||
|
||||
// Щёки
|
||||
if (isHappy) {
|
||||
shapeRenderer.setColor(new Color(1.0f, 0.7f, 0.7f, 0.5f));
|
||||
shapeRenderer.circle(x - headSize * 0.5f, currentY + 25 * scale, headSize * 0.15f);
|
||||
shapeRenderer.circle(x + headSize * 0.5f, currentY + 25 * scale, headSize * 0.15f);
|
||||
}
|
||||
}
|
||||
|
||||
private Color getHairColor() {
|
||||
switch (planet) {
|
||||
case EARTH: return new Color(0.2f, 0.15f, 0.1f, 1);
|
||||
case MARS: return new Color(0.7f, 0.3f, 0.2f, 1);
|
||||
case VENUS: return new Color(1.0f, 0.8f, 0.3f, 1);
|
||||
default: return new Color(0.2f, 0.15f, 0.1f, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private Color getEyeColor() {
|
||||
switch (planet) {
|
||||
case EARTH: return new Color(0.1f, 0.1f, 0.3f, 1);
|
||||
case MARS: return new Color(0.3f, 0.1f, 0.1f, 1);
|
||||
case VENUS: return new Color(0.3f, 0.2f, 0.1f, 1);
|
||||
default: return new Color(0.1f, 0.1f, 0.3f, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
core/src/main/java/com/mygdx/game/GameAssets.java
Normal file
40
core/src/main/java/com/mygdx/game/GameAssets.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
|
||||
|
||||
public class GameAssets {
|
||||
private static BitmapFont font;
|
||||
|
||||
public static void createFonts() {
|
||||
try {
|
||||
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("DejaVuSans.ttf"));
|
||||
FreeTypeFontParameter parameter = new FreeTypeFontParameter();
|
||||
parameter.size = 18;
|
||||
parameter.characters = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?\"'()[]{}<>:;@#$%^&*+-=×–÷/_\\|~`✦✧★☆";
|
||||
font = generator.generateFont(parameter);
|
||||
generator.dispose();
|
||||
} catch (Exception e) {
|
||||
font = new BitmapFont();
|
||||
font.getData().setScale(1.1f);
|
||||
}
|
||||
}
|
||||
|
||||
public static BitmapFont getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
public static Texture createWhitePixel() {
|
||||
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
|
||||
pixmap.setColor(Color.WHITE);
|
||||
pixmap.fill();
|
||||
Texture whitePixel = new Texture(pixmap);
|
||||
pixmap.dispose();
|
||||
return whitePixel;
|
||||
}
|
||||
}
|
||||
9
core/src/main/java/com/mygdx/game/GameState.java
Normal file
9
core/src/main/java/com/mygdx/game/GameState.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
public enum GameState {
|
||||
MAIN_MENU, // Главное меню
|
||||
PLAYING, // Игровой процесс
|
||||
PLANET_SELECT, // Выбор планеты
|
||||
HELP, // Помощь/инструкции
|
||||
ABOUT // Об игре
|
||||
}
|
||||
152
core/src/main/java/com/mygdx/game/InputHandler.java
Normal file
152
core/src/main/java/com/mygdx/game/InputHandler.java
Normal file
@@ -0,0 +1,152 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
|
||||
public class InputHandler {
|
||||
public static void handleInput(AbsurdCityBuilder1 game) {
|
||||
// Проверяем, что мы в игровом режиме
|
||||
if (game.getGameState() != GameState.PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Смена типа здания
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.LEFT)) {
|
||||
if (!game.isTyping() && !game.isSwitchingPlanets()) {
|
||||
int buildingCount = Building.BUILDING_TYPES_BY_PLANET[game.getCurrentPlanet().ordinal()].length;
|
||||
int newType = (game.getSelectedBuildingType() - 1 + buildingCount) % buildingCount;
|
||||
game.setSelectedBuildingType(newType);
|
||||
game.updateUI();
|
||||
|
||||
game.setMessageText("Выбран: " +
|
||||
Building.BUILDING_TYPES_BY_PLANET[game.getCurrentPlanet().ordinal()][newType]);
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.CYAN);
|
||||
}
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.RIGHT)) {
|
||||
if (!game.isTyping() && !game.isSwitchingPlanets()) {
|
||||
int buildingCount = Building.BUILDING_TYPES_BY_PLANET[game.getCurrentPlanet().ordinal()].length;
|
||||
int newType = (game.getSelectedBuildingType() + 1) % buildingCount;
|
||||
game.setSelectedBuildingType(newType);
|
||||
game.updateUI();
|
||||
|
||||
game.setMessageText("Выбран: " +
|
||||
Building.BUILDING_TYPES_BY_PLANET[game.getCurrentPlanet().ordinal()][newType]);
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.CYAN);
|
||||
}
|
||||
}
|
||||
|
||||
// Смена планеты
|
||||
if (!game.isTyping() && !game.isSwitchingPlanets()) {
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.UP)) {
|
||||
Planet nextPlanet = game.getCurrentPlanet().next();
|
||||
game.startPlanetSwitch(nextPlanet);
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.DOWN)) {
|
||||
Planet prevPlanet = game.getCurrentPlanet().previous();
|
||||
game.startPlanetSwitch(prevPlanet);
|
||||
}
|
||||
|
||||
// Быстрые клавиши для планет
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.NUM_1)) {
|
||||
game.startPlanetSwitch(Planet.EARTH);
|
||||
}
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.NUM_2)) {
|
||||
game.startPlanetSwitch(Planet.MARS);
|
||||
}
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.NUM_3)) {
|
||||
game.startPlanetSwitch(Planet.VENUS);
|
||||
}
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.FORWARD_DEL) ||
|
||||
Gdx.input.isKeyJustPressed(Input.Keys.DEL) ||
|
||||
(Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) && Gdx.input.isKeyJustPressed(Input.Keys.Z)) ||
|
||||
(Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT) && Gdx.input.isKeyJustPressed(Input.Keys.Z))) {
|
||||
|
||||
if (!game.isTyping() && !game.isSwitchingPlanets()) {
|
||||
if (game.getCurrentBuilding() != null) {
|
||||
game.setCurrentBuilding(null);
|
||||
game.setCurrentProblem(null);
|
||||
game.setTyping(false);
|
||||
game.getInputText().setLength(0);
|
||||
game.setMessageText("Строительство отменено. Выберите новое место.");
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.YELLOW);
|
||||
game.updateUI();
|
||||
} else if (game.getBuildings().size > 0) {
|
||||
game.getBuildings().removeIndex(game.getBuildings().size - 1);
|
||||
game.setMessageText("Последнее здание удалено.");
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.ORANGE);
|
||||
} else {
|
||||
game.setMessageText("Нет зданий для удаления.");
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.YELLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Gdx.input.justTouched()) {
|
||||
if (!game.isSwitchingPlanets()) {
|
||||
float touchX = Gdx.input.getX();
|
||||
float touchY = Gdx.input.getY();
|
||||
|
||||
float worldX = touchX * (game.getWIDTH() / (float)Gdx.graphics.getWidth());
|
||||
float worldY = game.getHEIGHT() - touchY * (game.getHEIGHT() / (float)Gdx.graphics.getHeight());
|
||||
|
||||
if (worldY > game.getUI_INPUT_HEIGHT()) {
|
||||
BuildingPlacer.handleBuildingClick(game, worldX, worldY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (game.isTyping() && game.getCurrentBuilding() != null && !game.isSwitchingPlanets()) {
|
||||
for (int key = Input.Keys.NUM_0; key <= Input.Keys.NUM_9; key++) {
|
||||
if (Gdx.input.isKeyJustPressed(key)) {
|
||||
game.getInputText().append(Input.Keys.toString(key).charAt(Input.Keys.toString(key).length() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
for (int key = Input.Keys.NUMPAD_0; key <= Input.Keys.NUMPAD_9; key++) {
|
||||
if (Gdx.input.isKeyJustPressed(key)) {
|
||||
char numChar = (char)('0' + (key - Input.Keys.NUMPAD_0));
|
||||
game.getInputText().append(numChar);
|
||||
}
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.MINUS) || Gdx.input.isKeyJustPressed(Input.Keys.NUMPAD_SUBTRACT)) {
|
||||
if (game.getInputText().length() == 0) {
|
||||
game.getInputText().append('-');
|
||||
}
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.BACKSPACE)) {
|
||||
if (!Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) &&
|
||||
!Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)) {
|
||||
|
||||
if (game.isTyping() && game.getInputText().length() > 0) {
|
||||
game.getInputText().deleteCharAt(game.getInputText().length() - 1);
|
||||
} else if (!game.isTyping() && game.getCurrentBuilding() != null && game.getCurrentBuilding().constructionProgress > 0) {
|
||||
game.getCurrentBuilding().removeBlock();
|
||||
game.setMessageText("Блок удален! Текущий прогресс: " + game.getCurrentBuilding().constructionProgress + "/3");
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.YELLOW);
|
||||
game.updateUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.ENTER)) {
|
||||
game.checkAnswer();
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)) {
|
||||
if (game.isTyping()) {
|
||||
game.setTyping(false);
|
||||
game.getInputText().setLength(0);
|
||||
game.setMessageText("Ввод отменен. Можно продолжить строительство.");
|
||||
game.setMessageColor(com.badlogic.gdx.graphics.Color.YELLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
87
core/src/main/java/com/mygdx/game/JokeBubble.java
Normal file
87
core/src/main/java/com/mygdx/game/JokeBubble.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import java.util.Random;
|
||||
|
||||
public class JokeBubble {
|
||||
String text;
|
||||
float x, y;
|
||||
float timer;
|
||||
Color bubbleColor;
|
||||
float floatOffset;
|
||||
float scale;
|
||||
Random random;
|
||||
|
||||
public JokeBubble(String text, float x, float y, Random random) {
|
||||
this.text = text;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.timer = 0;
|
||||
this.random = random;
|
||||
this.bubbleColor = new Color(
|
||||
random.nextFloat() * 0.3f + 0.7f,
|
||||
random.nextFloat() * 0.3f + 0.7f,
|
||||
random.nextFloat() * 0.3f + 0.7f,
|
||||
0.9f
|
||||
);
|
||||
this.floatOffset = random.nextFloat() * 100;
|
||||
this.scale = 0.9f + random.nextFloat() * 0.2f;
|
||||
}
|
||||
|
||||
public void update(float deltaTime) {
|
||||
timer += deltaTime;
|
||||
floatOffset += deltaTime * 2;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return timer > 3.0f;
|
||||
}
|
||||
|
||||
public void draw(SpriteBatch batch, ShapeRenderer shapeRenderer, BitmapFont font,
|
||||
GlyphLayout glyphLayout, Texture whitePixel) {
|
||||
batch.begin();
|
||||
|
||||
float currentY = y + (float)Math.sin(floatOffset) * 8;
|
||||
|
||||
// Пузырь
|
||||
font.getData().setScale(0.8f * scale);
|
||||
glyphLayout.setText(font, text);
|
||||
float bubbleWidth = glyphLayout.width + 25;
|
||||
float bubbleHeight = glyphLayout.height + 20;
|
||||
|
||||
// Рисуем пузырь с закругленными краями
|
||||
batch.setColor(bubbleColor);
|
||||
|
||||
// Основная часть пузыря
|
||||
batch.draw(whitePixel, x - bubbleWidth/2, currentY, bubbleWidth, bubbleHeight);
|
||||
|
||||
// Закругленные углы (эмулируем кругами)
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
|
||||
shapeRenderer.setColor(bubbleColor);
|
||||
shapeRenderer.circle(x - bubbleWidth/2, currentY + bubbleHeight/2, bubbleHeight/2);
|
||||
shapeRenderer.circle(x + bubbleWidth/2, currentY + bubbleHeight/2, bubbleHeight/2);
|
||||
shapeRenderer.end();
|
||||
|
||||
// Текст
|
||||
font.setColor(Color.BLACK);
|
||||
font.draw(batch, text, x - glyphLayout.width/2, currentY + bubbleHeight/2 + glyphLayout.height/2);
|
||||
|
||||
// Хвостик пузыря
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
|
||||
shapeRenderer.setColor(bubbleColor);
|
||||
shapeRenderer.triangle(
|
||||
x - 8, currentY,
|
||||
x + 8, currentY,
|
||||
x, currentY - 15
|
||||
);
|
||||
shapeRenderer.end();
|
||||
|
||||
font.getData().setScale(1.0f);
|
||||
batch.end();
|
||||
}
|
||||
}
|
||||
59
core/src/main/java/com/mygdx/game/MathProblem.java
Normal file
59
core/src/main/java/com/mygdx/game/MathProblem.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class MathProblem {
|
||||
String question;
|
||||
int answer;
|
||||
|
||||
public MathProblem(String question, int answer) {
|
||||
this.question = question;
|
||||
this.answer = answer;
|
||||
}
|
||||
|
||||
public static MathProblem generateProblem(int difficulty, Random random) {
|
||||
int a, b, c;
|
||||
String question;
|
||||
int answer;
|
||||
|
||||
if (difficulty < 2) {
|
||||
a = 1 + random.nextInt(20);
|
||||
b = 1 + random.nextInt(20);
|
||||
if (random.nextBoolean()) {
|
||||
question = a + " + " + b + " = ?";
|
||||
answer = a + b;
|
||||
} else {
|
||||
if (a < b) {
|
||||
int temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
question = a + " - " + b + " = ?";
|
||||
answer = a - b;
|
||||
}
|
||||
} else if (difficulty < 4) {
|
||||
a = 2 + random.nextInt(9);
|
||||
b = 2 + random.nextInt(9);
|
||||
question = a + " × " + b + " = ?";
|
||||
answer = a * b;
|
||||
} else if (difficulty < 6) {
|
||||
a = 1 + random.nextInt(10);
|
||||
b = 1 + random.nextInt(10);
|
||||
c = 2 + random.nextInt(8);
|
||||
question = "(" + a + " + " + b + ") × " + c + " = ?";
|
||||
answer = (a + b) * c;
|
||||
} else {
|
||||
b = 2 + random.nextInt(4);
|
||||
c = 2 + random.nextInt(4);
|
||||
int multiplication = b * c;
|
||||
a = multiplication + random.nextInt(10) + 5;
|
||||
question = a + " - " + b + " × " + c + " = ?";
|
||||
answer = a - multiplication;
|
||||
}
|
||||
|
||||
return new MathProblem(question, answer);
|
||||
}
|
||||
|
||||
public String getQuestion() { return question; }
|
||||
public int getAnswer() { return answer; }
|
||||
}
|
||||
87
core/src/main/java/com/mygdx/game/MenuButton.java
Normal file
87
core/src/main/java/com/mygdx/game/MenuButton.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
|
||||
public class MenuButton {
|
||||
private float x, y, width, height;
|
||||
private String text;
|
||||
private Color normalColor;
|
||||
private Color hoverColor;
|
||||
private Color textColor;
|
||||
private boolean isHovered;
|
||||
private Runnable action;
|
||||
private String icon;
|
||||
|
||||
public MenuButton(float x, float y, float width, float height, String text,
|
||||
Color normalColor, Color hoverColor, Runnable action) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.text = text;
|
||||
this.normalColor = normalColor;
|
||||
this.hoverColor = hoverColor;
|
||||
this.textColor = Color.WHITE;
|
||||
this.isHovered = false;
|
||||
this.action = action;
|
||||
this.icon = "";
|
||||
}
|
||||
|
||||
public MenuButton withIcon(String icon) {
|
||||
this.icon = icon;
|
||||
return this;
|
||||
}
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public MenuButton withTextColor(Color color) {
|
||||
this.textColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void update(float mouseX, float mouseY, boolean isClicked) {
|
||||
isHovered = mouseX >= x && mouseX <= x + width &&
|
||||
mouseY >= y && mouseY <= y + height;
|
||||
|
||||
if (isHovered && isClicked && action != null) {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void render(SpriteBatch batch, BitmapFont font, GlyphLayout layout, Texture whitePixel) {
|
||||
// Рисуем кнопку
|
||||
batch.setColor(isHovered ? hoverColor : normalColor);
|
||||
batch.draw(whitePixel, x, y, width, height);
|
||||
|
||||
// Рамка
|
||||
batch.setColor(new Color(1, 1, 1, 0.3f));
|
||||
batch.draw(whitePixel, x, y, width, 2); // Верх
|
||||
batch.draw(whitePixel, x, y + height - 2, width, 2); // Низ
|
||||
batch.draw(whitePixel, x, y, 2, height); // Левая
|
||||
batch.draw(whitePixel, x + width - 2, y, 2, height); // Правая
|
||||
|
||||
// Текст
|
||||
font.setColor(textColor);
|
||||
if (!icon.isEmpty()) {
|
||||
font.draw(batch, icon + " " + text, x + 20, y + height/2 + 10);
|
||||
} else {
|
||||
layout.setText(font, text);
|
||||
font.draw(batch, text, x + width/2 - layout.width/2, y + height/2 + 10);
|
||||
}
|
||||
|
||||
// Эффект при наведении
|
||||
if (isHovered) {
|
||||
batch.setColor(new Color(1, 1, 1, 0.1f));
|
||||
batch.draw(whitePixel, x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(float px, float py) {
|
||||
return px >= x && px <= x + width && py >= y && py <= y + height;
|
||||
}
|
||||
}
|
||||
447
core/src/main/java/com/mygdx/game/MenuRenderer.java
Normal file
447
core/src/main/java/com/mygdx/game/MenuRenderer.java
Normal file
@@ -0,0 +1,447 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MenuRenderer {
|
||||
private final SpriteBatch batch;
|
||||
private BitmapFont titleFont;
|
||||
private BitmapFont font;
|
||||
private GlyphLayout layout;
|
||||
private Texture whitePixel;
|
||||
private int width, height;
|
||||
|
||||
private List<MenuButton> mainMenuButtons;
|
||||
private List<MenuButton> planetSelectButtons;
|
||||
private List<MenuButton> helpButtons;
|
||||
|
||||
private float titlePulse = 0;
|
||||
private float starTimer = 0;
|
||||
|
||||
public MenuRenderer(SpriteBatch batch, BitmapFont font, GlyphLayout layout,
|
||||
Texture whitePixel, int width, int height) {
|
||||
this.batch = batch;
|
||||
this.font = font;
|
||||
this.layout = layout;
|
||||
this.whitePixel = whitePixel;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
// Создаем увеличенный шрифт для заголовка
|
||||
this.titleFont = new BitmapFont();
|
||||
this.titleFont.getData().setScale(2.5f);
|
||||
|
||||
createMainMenuButtons();
|
||||
createPlanetSelectButtons();
|
||||
createHelpButtons();
|
||||
}
|
||||
|
||||
private void createMainMenuButtons() {
|
||||
mainMenuButtons = new ArrayList<>();
|
||||
float buttonWidth = 400;
|
||||
float buttonHeight = 70;
|
||||
float startY = height/2 - 50;
|
||||
float spacing = 85;
|
||||
|
||||
// Кнопка "Новая игра"
|
||||
mainMenuButtons.add(new MenuButton(
|
||||
width/2 - buttonWidth/2, startY, buttonWidth, buttonHeight,
|
||||
"🚀 НОВАЯ ИГРА",
|
||||
new Color(0.2f, 0.5f, 0.8f, 0.9f),
|
||||
new Color(0.3f, 0.6f, 0.9f, 1f),
|
||||
() -> {}
|
||||
).withTextColor(Color.YELLOW));
|
||||
|
||||
// Кнопка "Выбор планеты"
|
||||
mainMenuButtons.add(new MenuButton(
|
||||
width/2 - buttonWidth/2, startY - spacing, buttonWidth, buttonHeight,
|
||||
"🪐 ВЫБОР ПЛАНЕТЫ",
|
||||
new Color(0.8f, 0.4f, 0.2f, 0.9f),
|
||||
new Color(0.9f, 0.5f, 0.3f, 1f),
|
||||
() -> {}
|
||||
));
|
||||
|
||||
// Кнопка "Помощь"
|
||||
mainMenuButtons.add(new MenuButton(
|
||||
width/2 - buttonWidth/2, startY - spacing * 2, buttonWidth, buttonHeight,
|
||||
"❓ ПОМОЩЬ",
|
||||
new Color(0.2f, 0.7f, 0.3f, 0.9f),
|
||||
new Color(0.3f, 0.8f, 0.4f, 1f),
|
||||
() -> {}
|
||||
));
|
||||
|
||||
// Кнопка "Об игре"
|
||||
mainMenuButtons.add(new MenuButton(
|
||||
width/2 - buttonWidth/2, startY - spacing * 3, buttonWidth, buttonHeight,
|
||||
"ℹ️ ОБ ИГРЕ",
|
||||
new Color(0.7f, 0.2f, 0.7f, 0.9f),
|
||||
new Color(0.8f, 0.3f, 0.8f, 1f),
|
||||
() -> {}
|
||||
));
|
||||
|
||||
// Кнопка "Выход"
|
||||
mainMenuButtons.add(new MenuButton(
|
||||
width/2 - buttonWidth/2, startY - spacing * 4, buttonWidth, buttonHeight,
|
||||
"🚪 ВЫХОД",
|
||||
new Color(0.8f, 0.2f, 0.2f, 0.9f),
|
||||
new Color(0.9f, 0.3f, 0.3f, 1f),
|
||||
() -> System.exit(0)
|
||||
));
|
||||
}
|
||||
|
||||
private void createPlanetSelectButtons() {
|
||||
planetSelectButtons = new ArrayList<>();
|
||||
float buttonWidth = 350;
|
||||
float buttonHeight = 100;
|
||||
float startY = height/2 + 50;
|
||||
float spacing = 120;
|
||||
|
||||
// Земля
|
||||
planetSelectButtons.add(new MenuButton(
|
||||
width/2 - buttonWidth - 20, startY, buttonWidth, buttonHeight,
|
||||
"🌍 ЗЕМЛЯ",
|
||||
new Color(0.3f, 0.6f, 0.9f, 0.9f),
|
||||
new Color(0.4f, 0.7f, 1.0f, 1f),
|
||||
() -> {}
|
||||
).withTextColor(Color.WHITE));
|
||||
|
||||
// Марс
|
||||
planetSelectButtons.add(new MenuButton(
|
||||
width/2 + 20, startY, buttonWidth, buttonHeight,
|
||||
"♂️ МАРС",
|
||||
new Color(0.8f, 0.3f, 0.2f, 0.9f),
|
||||
new Color(0.9f, 0.4f, 0.3f, 1f),
|
||||
() -> {}
|
||||
));
|
||||
|
||||
// Венера
|
||||
planetSelectButtons.add(new MenuButton(
|
||||
width/2 - buttonWidth/2, startY - spacing, buttonWidth, buttonHeight,
|
||||
"♀️ ВЕНЕРА",
|
||||
new Color(1.0f, 0.7f, 0.2f, 0.9f),
|
||||
new Color(1.0f, 0.8f, 0.3f, 1f),
|
||||
() -> {}
|
||||
));
|
||||
|
||||
// Кнопка "Назад"
|
||||
planetSelectButtons.add(new MenuButton(
|
||||
50, 50, 200, 60,
|
||||
"⬅️ НАЗАД",
|
||||
new Color(0.4f, 0.4f, 0.4f, 0.9f),
|
||||
new Color(0.5f, 0.5f, 0.5f, 1f),
|
||||
() -> {}
|
||||
));
|
||||
}
|
||||
|
||||
private void createHelpButtons() {
|
||||
helpButtons = new ArrayList<>();
|
||||
|
||||
// Кнопка "Назад"
|
||||
helpButtons.add(new MenuButton(
|
||||
50, 50, 200, 60,
|
||||
"⬅️ НАЗАД",
|
||||
new Color(0.4f, 0.4f, 0.4f, 0.9f),
|
||||
new Color(0.5f, 0.5f, 0.5f, 1f),
|
||||
() -> {}
|
||||
));
|
||||
}
|
||||
|
||||
public void update(float deltaTime) {
|
||||
titlePulse += deltaTime * 2;
|
||||
starTimer += deltaTime;
|
||||
}
|
||||
|
||||
public void renderMainMenu(float mouseX, float mouseY) {
|
||||
batch.begin();
|
||||
|
||||
// Космический фон
|
||||
renderSpaceBackground();
|
||||
|
||||
// Заголовок
|
||||
renderTitle();
|
||||
|
||||
// Подзаголовок
|
||||
font.setColor(new Color(0.8f, 0.9f, 1.0f, 0.8f));
|
||||
font.getData().setScale(1.2f);
|
||||
String subtitle = "Строй абсурдные города на разных планетах!";
|
||||
layout.setText(font, subtitle);
|
||||
font.draw(batch, subtitle, width/2 - layout.width/2, height - 150);
|
||||
font.getData().setScale(1.0f);
|
||||
|
||||
// Кнопки
|
||||
for (MenuButton button : mainMenuButtons) {
|
||||
button.render(batch, font, layout, whitePixel);
|
||||
}
|
||||
|
||||
// Автор
|
||||
font.setColor(new Color(1, 1, 1, 0.5f));
|
||||
font.getData().setScale(0.8f);
|
||||
font.draw(batch, "© 2024 Absurd City Builder", width - 250, 30);
|
||||
font.getData().setScale(1.0f);
|
||||
|
||||
batch.end();
|
||||
}
|
||||
|
||||
public void renderPlanetSelect(float mouseX, float mouseY) {
|
||||
batch.begin();
|
||||
|
||||
// Космический фон
|
||||
renderSpaceBackground();
|
||||
|
||||
// Заголовок
|
||||
titleFont.setColor(new Color(1, 1, 1, 0.9f));
|
||||
String title = "🪐 ВЫБОР ПЛАНЕТЫ";
|
||||
layout.setText(titleFont, title);
|
||||
titleFont.draw(batch, title, width/2 - layout.width/2, height - 100);
|
||||
|
||||
// Описание
|
||||
font.setColor(new Color(0.8f, 0.9f, 1.0f, 0.8f));
|
||||
font.getData().setScale(1.1f);
|
||||
String desc = "Выберите планету для строительства:";
|
||||
layout.setText(font, desc);
|
||||
font.draw(batch, desc, width/2 - layout.width/2, height - 170);
|
||||
font.getData().setScale(1.0f);
|
||||
|
||||
// Описания планет
|
||||
font.setColor(Color.LIGHT_GRAY);
|
||||
font.getData().setScale(0.9f);
|
||||
|
||||
// Земля
|
||||
String earthText = "Мультяшные здания\nЯркие цвета\nМилые жители";
|
||||
layout.setText(font, earthText);
|
||||
font.draw(batch, earthText, width/2 - 380, height/2 - 50);
|
||||
|
||||
// Марс
|
||||
String marsText = "Технологичные постройки\nКрасный пейзаж\nМарсианские роботы";
|
||||
layout.setText(font, marsText);
|
||||
font.draw(batch, marsText, width/2 + 30, height/2 - 50);
|
||||
|
||||
// Венера
|
||||
String venusText = "Вулканические здания\nРаскаленная атмосфера\nКристаллические формы";
|
||||
layout.setText(font, venusText);
|
||||
font.draw(batch, venusText, width/2 - 175, height/2 - 200);
|
||||
font.getData().setScale(1.0f);
|
||||
|
||||
// Кнопки
|
||||
for (MenuButton button : planetSelectButtons) {
|
||||
button.render(batch, font, layout, whitePixel);
|
||||
}
|
||||
|
||||
batch.end();
|
||||
}
|
||||
|
||||
public void renderHelp(float mouseX, float mouseY) {
|
||||
batch.begin();
|
||||
|
||||
// Фон
|
||||
batch.setColor(new Color(0.1f, 0.1f, 0.2f, 0.95f));
|
||||
batch.draw(whitePixel, 0, 0, width, height);
|
||||
batch.setColor(Color.WHITE);
|
||||
|
||||
// Заголовок
|
||||
titleFont.setColor(Color.YELLOW);
|
||||
String title = "❓ ПОМОЩЬ И УПРАВЛЕНИЕ";
|
||||
layout.setText(titleFont, title);
|
||||
titleFont.draw(batch, title, width/2 - layout.width/2, height - 100);
|
||||
|
||||
// Инструкции
|
||||
font.setColor(Color.WHITE);
|
||||
font.getData().setScale(1.1f);
|
||||
|
||||
float textY = height - 200;
|
||||
float lineHeight = 35;
|
||||
|
||||
String[] instructions = {
|
||||
"🎮 ОСНОВНОЕ УПРАВЛЕНИЕ:",
|
||||
"• ЛКМ - кликнуть на поле для строительства",
|
||||
"• ←/→ - выбрать тип здания",
|
||||
"• Enter - отправить ответ на задачу",
|
||||
"• Backspace - удалить блок/символ",
|
||||
"• Delete/Ctrl+Z - удалить здание",
|
||||
"• ESC - отмена ввода",
|
||||
"",
|
||||
"🪐 УПРАВЛЕНИЕ ПЛАНЕТАМИ:",
|
||||
"• ↑/↓ - переключить планету",
|
||||
"• 1 - Земля, 2 - Марс, 3 - Венера",
|
||||
"",
|
||||
"🎯 КАК ИГРАТЬ:",
|
||||
"1. Выберите тип здания",
|
||||
"2. Кликните на игровом поле",
|
||||
"3. Решите математическую задачу",
|
||||
"4. Постройте 3 блока для завершения",
|
||||
"5. Стройте разные здания на разных планетах!"
|
||||
};
|
||||
|
||||
for (String line : instructions) {
|
||||
if (line.startsWith("🎮") || line.startsWith("🪐") || line.startsWith("🎯")) {
|
||||
font.setColor(Color.CYAN);
|
||||
} else if (line.startsWith("•")) {
|
||||
font.setColor(Color.LIGHT_GRAY);
|
||||
} else {
|
||||
font.setColor(Color.WHITE);
|
||||
}
|
||||
font.draw(batch, line, 100, textY);
|
||||
textY -= lineHeight;
|
||||
}
|
||||
|
||||
font.getData().setScale(1.0f);
|
||||
|
||||
// Кнопки
|
||||
for (MenuButton button : helpButtons) {
|
||||
button.render(batch, font, layout, whitePixel);
|
||||
}
|
||||
|
||||
batch.end();
|
||||
}
|
||||
|
||||
public void renderAbout(float mouseX, float mouseY) {
|
||||
batch.begin();
|
||||
|
||||
// Галактический фон
|
||||
batch.setColor(new Color(0.05f, 0.05f, 0.1f, 1));
|
||||
batch.draw(whitePixel, 0, 0, width, height);
|
||||
|
||||
// Звезды
|
||||
batch.setColor(Color.WHITE);
|
||||
for (int i = 0; i < 50; i++) {
|
||||
float starX = (float)Math.sin(starTimer + i) * width + width/2;
|
||||
float starY = (float)Math.cos(starTimer * 0.5f + i) * height/2 + height/2;
|
||||
float size = 1 + (float)Math.sin(starTimer * 2 + i) * 2;
|
||||
batch.draw(whitePixel, starX, starY, size, size);
|
||||
}
|
||||
|
||||
batch.setColor(Color.WHITE);
|
||||
|
||||
// Заголовок
|
||||
titleFont.setColor(new Color(0.8f, 0.4f, 1.0f, 1));
|
||||
String title = "✨ ОБ ИГРЕ";
|
||||
layout.setText(titleFont, title);
|
||||
titleFont.draw(batch, title, width/2 - layout.width/2, height - 100);
|
||||
|
||||
// Описание игры
|
||||
font.setColor(new Color(0.9f, 0.9f, 1.0f, 0.9f));
|
||||
font.getData().setScale(1.2f);
|
||||
|
||||
String[] aboutText = {
|
||||
"Absurd City Builder - это уникальная игра,",
|
||||
"где вы строите безумные города на разных планетах!",
|
||||
"",
|
||||
"Особенности игры:",
|
||||
"• 3 уникальные планеты с разными зданиями",
|
||||
"• Забавные математические задачи",
|
||||
"• Мультяшная графика и анимации",
|
||||
"• Динамичные жители и шутки",
|
||||
"• Бесконечные возможности для творчества!",
|
||||
"",
|
||||
"Разработано с ❤️ для любителей абсурда и математики.",
|
||||
"",
|
||||
"Версия 1.0"
|
||||
};
|
||||
|
||||
float textY = height - 200;
|
||||
for (String line : aboutText) {
|
||||
layout.setText(font, line);
|
||||
font.draw(batch, line, width/2 - layout.width/2, textY);
|
||||
textY -= 40;
|
||||
}
|
||||
|
||||
font.getData().setScale(1.0f);
|
||||
|
||||
// Кнопка "Назад"
|
||||
MenuButton backButton = new MenuButton(
|
||||
50, 50, 200, 60,
|
||||
"⬅️ НАЗАД",
|
||||
new Color(0.4f, 0.4f, 0.4f, 0.9f),
|
||||
new Color(0.5f, 0.5f, 0.5f, 1f),
|
||||
() -> {}
|
||||
);
|
||||
backButton.render(batch, font, layout, whitePixel);
|
||||
|
||||
batch.end();
|
||||
}
|
||||
|
||||
private void renderSpaceBackground() {
|
||||
// Темный космический фон
|
||||
batch.setColor(new Color(0.05f, 0.05f, 0.1f, 1));
|
||||
batch.draw(whitePixel, 0, 0, width, height);
|
||||
|
||||
// Звезды
|
||||
batch.setColor(Color.WHITE);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
float starX = (i * 37.3f) % width;
|
||||
float starY = (i * 23.7f) % height;
|
||||
float twinkle = 0.5f + 0.5f * (float)Math.sin(starTimer * 3 + i);
|
||||
batch.setColor(new Color(1, 1, 1, twinkle));
|
||||
float size = 1 + (i % 3);
|
||||
batch.draw(whitePixel, starX, starY, size, size);
|
||||
}
|
||||
batch.setColor(Color.WHITE);
|
||||
|
||||
// Планеты на заднем фоне
|
||||
batch.setColor(new Color(0.3f, 0.6f, 0.9f, 0.3f));
|
||||
batch.draw(whitePixel, width - 200, 100, 150, 150);
|
||||
|
||||
batch.setColor(new Color(0.8f, 0.3f, 0.2f, 0.3f));
|
||||
batch.draw(whitePixel, 100, height - 200, 120, 120);
|
||||
|
||||
batch.setColor(new Color(1.0f, 0.7f, 0.2f, 0.3f));
|
||||
batch.draw(whitePixel, width - 150, height - 150, 100, 100);
|
||||
}
|
||||
|
||||
private void renderTitle() {
|
||||
// Пульсирующий заголовок
|
||||
float pulse = 0.8f + 0.2f * (float)Math.sin(titlePulse);
|
||||
titleFont.setColor(new Color(1, pulse, 0.5f, 1));
|
||||
|
||||
String title = "✨ ABSURD CITY BUILDER ✨";
|
||||
layout.setText(titleFont, title);
|
||||
titleFont.draw(batch, title, width/2 - layout.width/2, height - 100);
|
||||
|
||||
// Блестки вокруг заголовка
|
||||
batch.setColor(new Color(1, 1, 0.5f, 0.3f));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float angle = titlePulse + i * 0.785f;
|
||||
float sparkleX = width/2 + (float)Math.cos(angle) * 200;
|
||||
float sparkleY = height - 100 + (float)Math.sin(angle) * 50;
|
||||
float size = 5 + (float)Math.sin(titlePulse * 2 + i) * 3;
|
||||
batch.draw(whitePixel, sparkleX, sparkleY, size, size);
|
||||
}
|
||||
}
|
||||
|
||||
public MenuButton getMainMenuButtonAt(float x, float y) {
|
||||
for (MenuButton button : mainMenuButtons) {
|
||||
if (button.contains(x, y)) {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public MenuButton getPlanetSelectButtonAt(float x, float y) {
|
||||
for (MenuButton button : planetSelectButtons) {
|
||||
if (button.contains(x, y)) {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public MenuButton getHelpButtonAt(float x, float y) {
|
||||
for (MenuButton button : helpButtons) {
|
||||
if (button.contains(x, y)) {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
titleFont.dispose();
|
||||
}
|
||||
}
|
||||
42
core/src/main/java/com/mygdx/game/Planet.java
Normal file
42
core/src/main/java/com/mygdx/game/Planet.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
|
||||
public enum Planet {
|
||||
EARTH("Земля", 0.68f, 0.85f, 0.9f, 1.0f),
|
||||
MARS("Марс", 0.8f, 0.4f, 0.3f, 0.9f),
|
||||
VENUS("Венера", 1.0f, 0.7f, 0.4f, 1.0f);
|
||||
|
||||
private final String name;
|
||||
private final float r, g, b, a;
|
||||
|
||||
Planet(String name, float r, float g, float b, float a) {
|
||||
this.name = name;
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public float getR() { return r; }
|
||||
public float getG() { return g; }
|
||||
public float getB() { return b; }
|
||||
public float getA() { return a; }
|
||||
|
||||
public Color getColor() {
|
||||
return new Color(r, g, b, a);
|
||||
}
|
||||
|
||||
public Planet next() {
|
||||
Planet[] planets = values();
|
||||
int nextIndex = (this.ordinal() + 1) % planets.length;
|
||||
return planets[nextIndex];
|
||||
}
|
||||
|
||||
public Planet previous() {
|
||||
Planet[] planets = values();
|
||||
int prevIndex = (this.ordinal() - 1 + planets.length) % planets.length;
|
||||
return planets[prevIndex];
|
||||
}
|
||||
}
|
||||
254
core/src/main/java/com/mygdx/game/UIRenderer.java
Normal file
254
core/src/main/java/com/mygdx/game/UIRenderer.java
Normal file
@@ -0,0 +1,254 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
|
||||
public class UIRenderer {
|
||||
private SpriteBatch batch;
|
||||
private BitmapFont font;
|
||||
private GlyphLayout glyphLayout;
|
||||
private Texture whitePixel;
|
||||
private int WIDTH;
|
||||
private int HEIGHT;
|
||||
private int UI_INPUT_HEIGHT;
|
||||
|
||||
public UIRenderer(SpriteBatch batch, BitmapFont font, GlyphLayout glyphLayout,
|
||||
Texture whitePixel, int width, int height, int uiInputHeight) {
|
||||
this.batch = batch;
|
||||
this.font = font;
|
||||
this.glyphLayout = glyphLayout;
|
||||
this.whitePixel = whitePixel;
|
||||
this.WIDTH = width;
|
||||
this.HEIGHT = height;
|
||||
this.UI_INPUT_HEIGHT = uiInputHeight;
|
||||
}
|
||||
|
||||
public void renderUI(int selectedBuildingType, String problemText, String messageText, Color messageColor,
|
||||
boolean isTyping, MathProblem currentProblem, String inputText,
|
||||
boolean showWrongAnswerJoke, String wrongAnswerJoke, float time,
|
||||
Building currentBuilding, Planet currentPlanet, boolean isSwitchingPlanets) {
|
||||
batch.begin();
|
||||
|
||||
batch.setColor(0.2f, 0.3f, 0.4f, 0.95f);
|
||||
batch.draw(whitePixel, 0, 0, WIDTH, UI_INPUT_HEIGHT);
|
||||
batch.setColor(Color.WHITE);
|
||||
|
||||
batch.setColor(0.4f, 0.6f, 0.8f, 1);
|
||||
batch.draw(whitePixel, 0, UI_INPUT_HEIGHT, WIDTH, 3);
|
||||
batch.setColor(Color.WHITE);
|
||||
|
||||
font.setColor(Color.WHITE);
|
||||
|
||||
int lineHeight = 28;
|
||||
int currentY = UI_INPUT_HEIGHT - 30;
|
||||
|
||||
// ==================== ЛЕВАЯ КОЛОНКА ====================
|
||||
// Отображение текущей планеты
|
||||
String planetDisplay = "🌍 Планета: " + currentPlanet.getName();
|
||||
if (isSwitchingPlanets) {
|
||||
planetDisplay += " (Перелет...)";
|
||||
}
|
||||
font.draw(batch, planetDisplay, 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
|
||||
// Управление планетой
|
||||
font.setColor(Color.YELLOW);
|
||||
font.draw(batch, "↑/↓ - сменить планету", 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
font.setColor(Color.LIGHT_GRAY);
|
||||
font.draw(batch, "1-Земля, 2-Марс, 3-Венера", 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
|
||||
font.setColor(Color.WHITE);
|
||||
font.draw(batch, "───────────────", 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
|
||||
// Тип здания
|
||||
String[] planetBuildings = Building.BUILDING_TYPES_BY_PLANET[currentPlanet.ordinal()];
|
||||
font.draw(batch, "🏗️ Тип здания: " + planetBuildings[selectedBuildingType], 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
|
||||
// Управление зданиями
|
||||
font.setColor(Color.CYAN);
|
||||
font.draw(batch, "←/→ - выбрать тип здания", 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
|
||||
font.setColor(Color.WHITE);
|
||||
font.draw(batch, "───────────────", 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
|
||||
// Отображение задачи
|
||||
String displayText = problemText;
|
||||
if (problemText.length() > 40) {
|
||||
int splitIndex = problemText.lastIndexOf(" ", 40);
|
||||
if (splitIndex > 0) {
|
||||
String line1 = problemText.substring(0, splitIndex);
|
||||
String line2 = problemText.substring(splitIndex + 1);
|
||||
font.draw(batch, line1, 20, currentY);
|
||||
currentY -= lineHeight;
|
||||
font.draw(batch, line2, 20, currentY);
|
||||
} else {
|
||||
font.draw(batch, displayText, 20, currentY);
|
||||
}
|
||||
} else {
|
||||
font.draw(batch, displayText, 20, currentY);
|
||||
}
|
||||
currentY -= lineHeight;
|
||||
|
||||
// Прогресс строительства
|
||||
if (currentBuilding != null) {
|
||||
font.draw(batch, "📊 Прогресс: " + currentBuilding.constructionProgress + "/3 блоков",
|
||||
20, currentY);
|
||||
} else {
|
||||
font.draw(batch, "📊 Прогресс: 0/3 блоков", 20, currentY);
|
||||
}
|
||||
currentY -= lineHeight;
|
||||
|
||||
// ==================== ПРАВАЯ КОЛОНКА ====================
|
||||
// Сообщения игры
|
||||
font.setColor(messageColor);
|
||||
float messageX = WIDTH - 500;
|
||||
drawWrappedText(messageText, messageX, UI_INPUT_HEIGHT - 40, 480);
|
||||
|
||||
// ==================== ЦЕНТРАЛЬНАЯ ЧАСТЬ ====================
|
||||
if (isTyping && currentProblem != null) {
|
||||
renderInputSection(currentProblem, inputText, time);
|
||||
}
|
||||
|
||||
// Шутка при неправильном ответе
|
||||
if (showWrongAnswerJoke) {
|
||||
renderWrongAnswerJoke(wrongAnswerJoke);
|
||||
}
|
||||
|
||||
// ==================== НИЖНЯЯ ПАНЕЛЬ ====================
|
||||
renderBottomPanel(currentPlanet, isSwitchingPlanets);
|
||||
|
||||
batch.end();
|
||||
}
|
||||
|
||||
private void renderInputSection(MathProblem currentProblem, String inputText, float time) {
|
||||
// Фон для ввода
|
||||
batch.setColor(0.3f, 0.4f, 0.5f, 0.8f);
|
||||
batch.draw(whitePixel, WIDTH/2 - 250, UI_INPUT_HEIGHT - 150, 500, 130);
|
||||
batch.setColor(Color.WHITE);
|
||||
|
||||
// Задача
|
||||
font.setColor(Color.YELLOW);
|
||||
String mathProblem = "🧮 Задача: " + currentProblem.getQuestion();
|
||||
glyphLayout.setText(font, mathProblem);
|
||||
font.draw(batch, mathProblem,
|
||||
WIDTH/2 - glyphLayout.width/2,
|
||||
UI_INPUT_HEIGHT - 60);
|
||||
|
||||
// Поле ввода
|
||||
font.setColor(Color.WHITE);
|
||||
font.draw(batch, "✏️ Введите ответ:", WIDTH/2 - 230, UI_INPUT_HEIGHT - 95);
|
||||
|
||||
// Введенный текст
|
||||
String inputStr = inputText.isEmpty() ? "_" : inputText;
|
||||
font.draw(batch, inputStr, WIDTH/2 - 230, UI_INPUT_HEIGHT - 130);
|
||||
|
||||
// Мигающий курсор
|
||||
if ((int)(time * 2) % 2 == 0 && inputText.isEmpty()) {
|
||||
font.setColor(Color.YELLOW);
|
||||
font.draw(batch, "_", WIDTH/2 - 230, UI_INPUT_HEIGHT - 130);
|
||||
font.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
// Подсказки
|
||||
font.setColor(Color.LIGHT_GRAY);
|
||||
font.getData().setScale(0.7f);
|
||||
font.draw(batch, "⏎ Enter - отправить ответ", WIDTH/2 - 230, UI_INPUT_HEIGHT - 160);
|
||||
font.draw(batch, "⎋ ESC - отмена ввода", WIDTH/2 - 230, UI_INPUT_HEIGHT - 180);
|
||||
font.draw(batch, "⌫ Backspace - удалить символ", WIDTH/2 - 230, UI_INPUT_HEIGHT - 200);
|
||||
font.getData().setScale(1.0f);
|
||||
}
|
||||
|
||||
private void renderWrongAnswerJoke(String wrongAnswerJoke) {
|
||||
// Фон для шутки
|
||||
batch.setColor(1, 0.2f, 0.2f, 0.3f);
|
||||
batch.draw(whitePixel, WIDTH/2 - 300, HEIGHT/2 - 50, 600, 100);
|
||||
batch.setColor(Color.WHITE);
|
||||
|
||||
// Шутка
|
||||
font.setColor(Color.RED);
|
||||
font.getData().setScale(1.3f);
|
||||
glyphLayout.setText(font, wrongAnswerJoke);
|
||||
font.draw(batch, wrongAnswerJoke,
|
||||
WIDTH/2 - glyphLayout.width/2,
|
||||
HEIGHT/2 + 10);
|
||||
font.getData().setScale(1.0f);
|
||||
}
|
||||
|
||||
// ВОТ ТОТ САМЫЙ МЕТОД, КОТОРЫЙ ВЫ СПРАШИВАЛИ:
|
||||
private void renderBottomPanel(Planet planet, boolean isSwitchingPlanets) {
|
||||
font.setColor(Color.LIGHT_GRAY);
|
||||
font.getData().setScale(0.6f);
|
||||
|
||||
// Основные инструкции
|
||||
String instruction = "🖱️ Кликните на поле для строительства";
|
||||
glyphLayout.setText(font, instruction);
|
||||
font.draw(batch, instruction, WIDTH/2 - glyphLayout.width/2, 30);
|
||||
|
||||
// Управление
|
||||
String controls = "🗑️ Delete/Ctrl+Z - удалить здание | ⌫ Backspace - удалить блок | ⎋ ESC - меню";
|
||||
glyphLayout.setText(font, controls);
|
||||
font.draw(batch, controls, WIDTH/2 - glyphLayout.width/2, 15);
|
||||
|
||||
// Индикатор планеты
|
||||
font.setColor(getPlanetColor(planet));
|
||||
font.getData().setScale(0.8f);
|
||||
String planetInfo = getPlanetEmoji(planet) + " " + planet.getName();
|
||||
if (isSwitchingPlanets) {
|
||||
planetInfo += " 🚀";
|
||||
}
|
||||
font.draw(batch, planetInfo, WIDTH - 150, 25);
|
||||
|
||||
font.getData().setScale(1.0f);
|
||||
}
|
||||
|
||||
// Вспомогательные методы для работы с планетами:
|
||||
private Color getPlanetColor(Planet planet) {
|
||||
switch (planet) {
|
||||
case EARTH: return new Color(0.3f, 0.7f, 1.0f, 1);
|
||||
case MARS: return new Color(1.0f, 0.4f, 0.3f, 1);
|
||||
case VENUS: return new Color(1.0f, 0.8f, 0.3f, 1);
|
||||
default: return Color.WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
private String getPlanetEmoji(Planet planet) {
|
||||
switch (planet) {
|
||||
case EARTH: return "🌍";
|
||||
case MARS: return "♂️";
|
||||
case VENUS: return "♀️";
|
||||
default: return "🪐";
|
||||
}
|
||||
}
|
||||
|
||||
private void drawWrappedText(String text, float x, float y, float maxWidth) {
|
||||
String[] words = text.split(" ");
|
||||
StringBuilder line = new StringBuilder();
|
||||
float currentY = y;
|
||||
|
||||
for (String word : words) {
|
||||
String testLine = line.length() > 0 ? line.toString() + " " + word : word;
|
||||
glyphLayout.setText(font, testLine);
|
||||
|
||||
if (glyphLayout.width > maxWidth && line.length() > 0) {
|
||||
font.draw(batch, line.toString(), x, currentY);
|
||||
line = new StringBuilder(word);
|
||||
currentY -= 25;
|
||||
} else {
|
||||
line = new StringBuilder(testLine);
|
||||
}
|
||||
}
|
||||
|
||||
if (line.length() > 0) {
|
||||
font.draw(batch, line.toString(), x, currentY);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
core/src/main/java/com/mygdx/game/UIUpdater.java
Normal file
33
core/src/main/java/com/mygdx/game/UIUpdater.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.mygdx.game;
|
||||
|
||||
public class UIUpdater {
|
||||
public static void updateUI(AbsurdCityBuilder1 game) {
|
||||
if (game.getGameState() != GameState.PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
Planet planet = game.getCurrentPlanet();
|
||||
String[] planetBuildings = Building.BUILDING_TYPES_BY_PLANET[planet.ordinal()];
|
||||
|
||||
if (game.getCurrentBuilding() != null && game.getCurrentProblem() != null) {
|
||||
String overlapText = game.getCurrentBuilding().isOverlapping ? " (пересекается!)" : "";
|
||||
String colorInfo = "";
|
||||
if (game.getCurrentBuilding().isComplete()) {
|
||||
colorInfo = String.format(" [Цвет: Тема %d]", game.getCurrentBuilding().colorThemeIndex + 1);
|
||||
}
|
||||
String fullText = "Строим " + game.getCurrentBuilding().type +
|
||||
" (" + game.getCurrentBuilding().constructionProgress + "/3)" + colorInfo +
|
||||
": " + game.getCurrentProblem().getQuestion() + overlapText;
|
||||
game.setProblemText(fullText);
|
||||
} else {
|
||||
String planetText = game.isSwitchingPlanets() ?
|
||||
"Перелет на " + game.getTargetPlanet().getName() + "..." :
|
||||
"Планета: " + planet.getName();
|
||||
|
||||
game.setProblemText(planetText +
|
||||
" | Тип здания: " + planetBuildings[game.getSelectedBuildingType()] +
|
||||
" (←/→ для выбора, кликните на поле для строительства)" +
|
||||
" | ESC - меню");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user