Initial commit
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
package ru.samsung.gamestudiovtim2026;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Screen;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
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.SpriteBatch;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class GameScreen implements Screen {
|
||||
private final MyGdxGame game;
|
||||
private OrthographicCamera camera;
|
||||
private SpriteBatch batch;
|
||||
private BitmapFont font;
|
||||
|
||||
private Player player;
|
||||
private Array<Obstacle> obstacles;
|
||||
private float obstacleTimer;
|
||||
private float gameTime;
|
||||
private float distance;
|
||||
private float gameSpeed;
|
||||
|
||||
private int score;
|
||||
private int highScore;
|
||||
|
||||
private Texture lineTexture;
|
||||
|
||||
public GameScreen(MyGdxGame game) {
|
||||
this.game = game;
|
||||
this.batch = game.batch;
|
||||
this.font = game.font;
|
||||
|
||||
camera = new OrthographicCamera();
|
||||
camera.setToOrtho(false, 800, 480);
|
||||
|
||||
highScore = ScoreManager.loadHighScore();
|
||||
lineTexture = createLineTexture();
|
||||
|
||||
restart();
|
||||
}
|
||||
|
||||
private Texture createLineTexture() {
|
||||
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
|
||||
pixmap.setColor(Color.GRAY);
|
||||
pixmap.fill();
|
||||
Texture texture = new Texture(pixmap);
|
||||
pixmap.dispose();
|
||||
return texture;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
player = new Player();
|
||||
obstacles = new Array<>();
|
||||
obstacleTimer = 0;
|
||||
gameTime = 0;
|
||||
distance = 0;
|
||||
gameSpeed = 200;
|
||||
score = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(float delta) {
|
||||
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
update(delta);
|
||||
|
||||
camera.update();
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
batch.begin();
|
||||
|
||||
drawLines();
|
||||
player.render(batch);
|
||||
|
||||
for (Obstacle obstacle : obstacles) {
|
||||
if (obstacle.isVisible()) {
|
||||
obstacle.render(batch);
|
||||
}
|
||||
}
|
||||
|
||||
drawUI();
|
||||
|
||||
batch.end();
|
||||
}
|
||||
|
||||
private void update(float delta) {
|
||||
gameTime += delta;
|
||||
distance += gameSpeed * delta;
|
||||
|
||||
player.update(delta);
|
||||
handleInput();
|
||||
generateObstacles(delta);
|
||||
updateObstacles(delta);
|
||||
checkCollisions();
|
||||
|
||||
// Плавное увеличение скорости со временем
|
||||
gameSpeed += delta * 1.5f;
|
||||
score = (int)(distance / 10);
|
||||
}
|
||||
|
||||
private void handleInput() {
|
||||
if (Gdx.input.justTouched()) {
|
||||
int touchY = Gdx.input.getY();
|
||||
int screenHeight = Gdx.graphics.getHeight();
|
||||
|
||||
if (touchY < screenHeight / 3) {
|
||||
player.moveUp();
|
||||
} else if (touchY > 2 * screenHeight / 3) {
|
||||
player.moveDown();
|
||||
}
|
||||
}
|
||||
|
||||
if (Gdx.input.isKeyJustPressed(com.badlogic.gdx.Input.Keys.UP) ||
|
||||
Gdx.input.isKeyJustPressed(com.badlogic.gdx.Input.Keys.W)) {
|
||||
player.moveUp();
|
||||
}
|
||||
if (Gdx.input.isKeyJustPressed(com.badlogic.gdx.Input.Keys.DOWN) ||
|
||||
Gdx.input.isKeyJustPressed(com.badlogic.gdx.Input.Keys.S)) {
|
||||
player.moveDown();
|
||||
}
|
||||
if (Gdx.input.isKeyJustPressed(com.badlogic.gdx.Input.Keys.SPACE)) {
|
||||
player.jump();
|
||||
}
|
||||
|
||||
// Для тестирования на ПК - выход по ESC
|
||||
if (Gdx.input.isKeyJustPressed(com.badlogic.gdx.Input.Keys.ESCAPE)) {
|
||||
game.switchToMainMenu();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateObstacles(float delta) {
|
||||
obstacleTimer += delta;
|
||||
|
||||
// Генерируем препятствия с интервалом (интервал уменьшается с увеличением скорости)
|
||||
float spawnInterval = Math.max(0.8f, 2.0f - (gameSpeed / 500));
|
||||
|
||||
if (obstacleTimer > spawnInterval) {
|
||||
obstacleTimer = 0;
|
||||
|
||||
int line = MathUtils.random(0, 2);
|
||||
float spawnX = 800;
|
||||
|
||||
// Проверяем, чтобы препятствия не были слишком близко
|
||||
boolean tooClose = false;
|
||||
float minDistance = 150 + (gameSpeed / 10); // Минимальное расстояние увеличивается со скоростью
|
||||
|
||||
for (Obstacle obstacle : obstacles) {
|
||||
if (obstacle.getLine() == line && obstacle.getBounds().x > 800 - minDistance) {
|
||||
tooClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tooClose) {
|
||||
obstacles.add(new Obstacle(spawnX, line, gameSpeed * 1.2f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateObstacles(float delta) {
|
||||
for (int i = obstacles.size - 1; i >= 0; i--) {
|
||||
Obstacle obstacle = obstacles.get(i);
|
||||
obstacle.update(delta);
|
||||
|
||||
if (!obstacle.isPassed() && obstacle.getBounds().x < player.getBounds().x) {
|
||||
obstacle.setPassed(true);
|
||||
score += 5; // Бонус за прохождение препятствия
|
||||
}
|
||||
|
||||
if (obstacle.isOffScreen()) {
|
||||
obstacles.removeIndex(i);
|
||||
obstacle.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCollisions() {
|
||||
for (Obstacle obstacle : obstacles) {
|
||||
if (obstacle.isVisible() && obstacle.collidesWith(player.getBounds())) {
|
||||
if (score > highScore) {
|
||||
highScore = score;
|
||||
ScoreManager.saveHighScore(highScore);
|
||||
}
|
||||
ScoreManager.saveLastScore(score);
|
||||
game.switchToMainMenu();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawLines() {
|
||||
batch.setColor(Color.GRAY);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float y = 400 - i * 160;
|
||||
batch.draw(lineTexture, 0, y, 800, 2);
|
||||
}
|
||||
batch.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
private void drawUI() {
|
||||
font.setColor(Color.WHITE);
|
||||
font.draw(batch, "Score: " + score, 20, 460);
|
||||
font.draw(batch, "Best: " + highScore, 20, 440);
|
||||
// Убрали Distance и Speed из отображения
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
camera.setToOrtho(false, 800, 480);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {}
|
||||
|
||||
@Override
|
||||
public void hide() {}
|
||||
|
||||
@Override
|
||||
public void pause() {}
|
||||
|
||||
@Override
|
||||
public void resume() {}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
player.dispose();
|
||||
for (Obstacle obstacle : obstacles) {
|
||||
obstacle.dispose();
|
||||
}
|
||||
lineTexture.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package ru.samsung.gamestudiovtim2026;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Screen;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
||||
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||
|
||||
public class MainMenuScreen implements Screen {
|
||||
private final MyGdxGame game;
|
||||
private Stage stage;
|
||||
private Skin skin;
|
||||
private OrthographicCamera camera;
|
||||
private SpriteBatch batch;
|
||||
private BitmapFont font;
|
||||
|
||||
private Label highScoreLabel;
|
||||
private Label lastScoreLabel;
|
||||
|
||||
public MainMenuScreen(MyGdxGame game) {
|
||||
this.game = game;
|
||||
this.batch = game.batch;
|
||||
this.font = game.font;
|
||||
|
||||
camera = new OrthographicCamera();
|
||||
camera.setToOrtho(false, 800, 480);
|
||||
|
||||
stage = new Stage(new ScreenViewport());
|
||||
Gdx.input.setInputProcessor(stage);
|
||||
|
||||
skin = new Skin();
|
||||
skin.add("default-font", font);
|
||||
|
||||
com.badlogic.gdx.graphics.Pixmap pixmap = new com.badlogic.gdx.graphics.Pixmap(1, 1,
|
||||
com.badlogic.gdx.graphics.Pixmap.Format.RGBA8888);
|
||||
pixmap.setColor(Color.WHITE);
|
||||
pixmap.fill();
|
||||
skin.add("white", new com.badlogic.gdx.graphics.Texture(pixmap));
|
||||
pixmap.dispose();
|
||||
|
||||
TextButton.TextButtonStyle buttonStyle = new TextButton.TextButtonStyle();
|
||||
buttonStyle.font = font;
|
||||
buttonStyle.fontColor = Color.WHITE;
|
||||
buttonStyle.downFontColor = Color.RED;
|
||||
buttonStyle.up = skin.newDrawable("white", Color.DARK_GRAY);
|
||||
buttonStyle.down = skin.newDrawable("white", Color.GRAY);
|
||||
buttonStyle.over = skin.newDrawable("white", Color.LIGHT_GRAY);
|
||||
|
||||
Label.LabelStyle labelStyle = new Label.LabelStyle();
|
||||
labelStyle.font = font;
|
||||
labelStyle.fontColor = Color.WHITE;
|
||||
|
||||
skin.add("default", buttonStyle);
|
||||
skin.add("default", labelStyle);
|
||||
|
||||
createUI();
|
||||
}
|
||||
|
||||
private void createUI() {
|
||||
Table table = new Table();
|
||||
table.setFillParent(true);
|
||||
stage.addActor(table);
|
||||
|
||||
// Английский текст для избежания квадратиков
|
||||
Label title = new Label("RUNNING SMILEY", skin);
|
||||
title.setFontScale(1.5f); // Уменьшаем размер заголовка
|
||||
|
||||
TextButton playButton = new TextButton("PLAY", skin);
|
||||
TextButton exitButton = new TextButton("EXIT", skin);
|
||||
|
||||
int highScore = ScoreManager.loadHighScore();
|
||||
int lastScore = ScoreManager.loadLastScore();
|
||||
|
||||
highScoreLabel = new Label("BEST: " + highScore, skin);
|
||||
lastScoreLabel = new Label("LAST: " + lastScore, skin);
|
||||
|
||||
playButton.addListener(new ClickListener() {
|
||||
@Override
|
||||
public void clicked(InputEvent event, float x, float y) {
|
||||
game.switchToGameScreen();
|
||||
}
|
||||
});
|
||||
|
||||
exitButton.addListener(new ClickListener() {
|
||||
@Override
|
||||
public void clicked(InputEvent event, float x, float y) {
|
||||
Gdx.app.exit();
|
||||
}
|
||||
});
|
||||
|
||||
table.add(title).padBottom(40).row();
|
||||
table.add(playButton).width(180).height(50).padBottom(15).row();
|
||||
table.add(exitButton).width(180).height(50).padBottom(30).row();
|
||||
table.add(highScoreLabel).padBottom(10).row();
|
||||
table.add(lastScoreLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(float delta) {
|
||||
Gdx.gl.glClearColor(0.1f, 0.1f, 0.2f, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
camera.update();
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
|
||||
batch.begin();
|
||||
// Можно добавить простой фон
|
||||
batch.end();
|
||||
|
||||
stage.act(delta);
|
||||
stage.draw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
stage.getViewport().update(width, height, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
highScoreLabel.setText("BEST: " + ScoreManager.loadHighScore());
|
||||
lastScoreLabel.setText("LAST: " + ScoreManager.loadLastScore());
|
||||
Gdx.input.setInputProcessor(stage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {}
|
||||
|
||||
@Override
|
||||
public void pause() {}
|
||||
|
||||
@Override
|
||||
public void resume() {}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stage.dispose();
|
||||
skin.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package ru.samsung.gamestudiovtim2026;
|
||||
|
||||
import com.badlogic.gdx.Game;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
|
||||
public class MyGdxGame extends Game {
|
||||
public static final int SCR_WIDTH = 960;
|
||||
public static final int SCR_HEIGHT = 960;
|
||||
public SpriteBatch batch;
|
||||
public BitmapFont font;
|
||||
|
||||
private GameScreen gameScreen;
|
||||
private MainMenuScreen mainMenuScreen;
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
batch = new SpriteBatch();
|
||||
|
||||
// Создаем шрифт без FreeType
|
||||
font = createSimpleFont();
|
||||
|
||||
mainMenuScreen = new MainMenuScreen(this);
|
||||
gameScreen = new GameScreen(this);
|
||||
|
||||
setScreen(mainMenuScreen);
|
||||
}
|
||||
|
||||
private BitmapFont createSimpleFont() {
|
||||
try {
|
||||
// Пробуем использовать стандартный шрифт, но уменьшим его размер
|
||||
BitmapFont simpleFont = new BitmapFont();
|
||||
simpleFont.getData().setScale(0.8f); // Уменьшаем размер шрифта
|
||||
return simpleFont;
|
||||
} catch (Exception e) {
|
||||
// Если что-то пошло не так, создаем минимальный шрифт
|
||||
return new BitmapFont();
|
||||
}
|
||||
}
|
||||
|
||||
public void switchToGameScreen() {
|
||||
gameScreen.restart();
|
||||
setScreen(gameScreen);
|
||||
}
|
||||
|
||||
public void switchToMainMenu() {
|
||||
setScreen(mainMenuScreen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
batch.dispose();
|
||||
font.dispose();
|
||||
if (gameScreen != null) {
|
||||
gameScreen.dispose();
|
||||
}
|
||||
if (mainMenuScreen != null) {
|
||||
mainMenuScreen.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package ru.samsung.gamestudiovtim2026;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
|
||||
public class Obstacle {
|
||||
private Texture texture;
|
||||
private Rectangle bounds;
|
||||
private float speed;
|
||||
private int line; // Линия, на которой находится препятствие
|
||||
private boolean passed;
|
||||
|
||||
public Obstacle(float x, int line, float speed) {
|
||||
texture = new Texture("spike_block.png");
|
||||
this.line = line;
|
||||
this.speed = speed;
|
||||
this.passed = false;
|
||||
|
||||
float[] linePositions = {400, 240, 80};
|
||||
bounds = new Rectangle(x, linePositions[line], 60, 60);
|
||||
}
|
||||
|
||||
public void update(float deltaTime) {
|
||||
// Препятствия движутся справа налево
|
||||
bounds.x -= speed * deltaTime;
|
||||
}
|
||||
|
||||
public void render(SpriteBatch batch) {
|
||||
// Отрисовываем в мировых координатах
|
||||
batch.draw(texture, bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
|
||||
public boolean isOffScreen() {
|
||||
// Препятствие ушло за левый край экрана
|
||||
return bounds.x < -bounds.width;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
// Препятствие видимо на экране (не вышло за левый край)
|
||||
return bounds.x > -bounds.width;
|
||||
}
|
||||
|
||||
public boolean collidesWith(Rectangle playerBounds) {
|
||||
return bounds.overlaps(playerBounds);
|
||||
}
|
||||
|
||||
public boolean isPassed() {
|
||||
return passed;
|
||||
}
|
||||
|
||||
public void setPassed(boolean passed) {
|
||||
this.passed = passed;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
texture.dispose();
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package ru.samsung.gamestudiovtim2026;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
|
||||
public class Player {
|
||||
private Texture texture;
|
||||
private Rectangle bounds;
|
||||
private int currentLine; // 0 - верхняя, 1 - средняя, 2 - нижняя
|
||||
private float[] linePositions = {400, 240, 80}; // Y-позиции линий
|
||||
private boolean isJumping;
|
||||
private float jumpTime;
|
||||
|
||||
public Player() {
|
||||
texture = new Texture("smile.png");
|
||||
// Игрок фиксирован по X (100px от левого края)
|
||||
bounds = new Rectangle(100, linePositions[1], 60, 60);
|
||||
currentLine = 1; // Начинаем со средней линии
|
||||
isJumping = false;
|
||||
}
|
||||
|
||||
public void update(float deltaTime) {
|
||||
// Игрок НЕ движется по X, только плавно перемещается по Y между линиями
|
||||
|
||||
// Плавное перемещение между линиями
|
||||
float targetY = linePositions[currentLine];
|
||||
if (Math.abs(bounds.y - targetY) > 1) {
|
||||
bounds.y += (targetY - bounds.y) * 5 * deltaTime;
|
||||
}
|
||||
|
||||
// Обработка прыжка
|
||||
if (isJumping) {
|
||||
jumpTime += deltaTime;
|
||||
if (jumpTime > 0.3f) { // Длительность прыжка
|
||||
isJumping = false;
|
||||
jumpTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void moveUp() {
|
||||
if (currentLine > 0) {
|
||||
currentLine--;
|
||||
}
|
||||
}
|
||||
|
||||
public void moveDown() {
|
||||
if (currentLine < 2) {
|
||||
currentLine++;
|
||||
}
|
||||
}
|
||||
|
||||
public void jump() {
|
||||
if (!isJumping) {
|
||||
isJumping = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void render(SpriteBatch batch) {
|
||||
float drawY = bounds.y;
|
||||
if (isJumping) {
|
||||
drawY += 50 * (float)Math.sin(jumpTime * 10);
|
||||
}
|
||||
batch.draw(texture, bounds.x, drawY, bounds.width, bounds.height);
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public int getCurrentLine() {
|
||||
return currentLine;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
texture.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package ru.samsung.gamestudiovtim2026;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Preferences;
|
||||
|
||||
public class ScoreManager {
|
||||
private static final String PREFS_NAME = "game_preferences";
|
||||
private static final String HIGH_SCORE_KEY = "high_score";
|
||||
private static final String LAST_SCORE_KEY = "last_score";
|
||||
|
||||
public static void saveHighScore(int score) {
|
||||
Preferences prefs = Gdx.app.getPreferences(PREFS_NAME);
|
||||
prefs.putInteger(HIGH_SCORE_KEY, score);
|
||||
prefs.flush();
|
||||
}
|
||||
|
||||
public static int loadHighScore() {
|
||||
Preferences prefs = Gdx.app.getPreferences(PREFS_NAME);
|
||||
return prefs.getInteger(HIGH_SCORE_KEY, 0);
|
||||
}
|
||||
|
||||
public static void saveLastScore(int score) {
|
||||
Preferences prefs = Gdx.app.getPreferences(PREFS_NAME);
|
||||
prefs.putInteger(LAST_SCORE_KEY, score);
|
||||
prefs.flush();
|
||||
}
|
||||
|
||||
public static int loadLastScore() {
|
||||
Preferences prefs = Gdx.app.getPreferences(PREFS_NAME);
|
||||
return prefs.getInteger(LAST_SCORE_KEY, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user