Initial commit

This commit is contained in:
2026-06-16 11:02:07 +03:00
commit 273f4a90f4
72 changed files with 1924 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
sourceCompatibility = 1.7
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
sourceSets.main.java.srcDirs = [ "src/" ]
eclipse.project.name = appName + "-core"
dependencies {
// Основное ядро LibGDX
api "com.badlogicgames.gdx:gdx:$gdxVersion"
}
+26
View File
@@ -0,0 +1,26 @@
package com.mygdx.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
public class AudioManager {
public boolean isMusicOn = true;
public static final String BACKGROUND_MUSIC_PATH = "bg.mp3";
public Music backgroundMusic;
public AudioManager() {
backgroundMusic = Gdx.audio.newMusic(Gdx.files.internal(BACKGROUND_MUSIC_PATH));
backgroundMusic.setVolume(1f);
backgroundMusic.setLooping(true);
updateSoundFlag();
updateMusicFlag();
}
private void updateSoundFlag() {
}
public void updateMusicFlag() {
if (isMusicOn) backgroundMusic.play();
else backgroundMusic.stop();
}
}
+16
View File
@@ -0,0 +1,16 @@
package com.mygdx.game;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.math.Vector3;
class Emitter {
public ModelInstance instance;
public Vector3 direction;
public Emitter(Model m, float x, float y, float z, float dx, float dy, float dz) {
instance = new ModelInstance(m, x, y, z);
direction = new Vector3(dx, dy, dz).nor();
instance.transform.setToLookAt(direction, Vector3.Y).inv().setTranslation(x, y, z);
}
}
+219
View File
@@ -0,0 +1,219 @@
package com.mygdx.game;
import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g3d.*;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.math.*;
import com.badlogic.gdx.scenes.scene2d.*;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
public class GameScreen implements Screen {
private final MyGdxGame game;
private PerspectiveCamera cam;
private CameraInputController camCtrl;
private Environment env;
private SceneManager sm;
private LaserRenderer lr;
private float winTimer = 0;
private float levelTime = 0; // Общее время прохождения уровня
private final int level;
private Stage stage;
private Texture uiBtnTexture;
private BitmapFont font;
private HelpUI helpUI;
private Label timerLabel; // Визуальный элемент таймера
public GameScreen(MyGdxGame game, int level) {
this.game = game;
this.level = level;
}
@Override
public void show() {
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(50, 60, 50);
cam.lookAt(0, 0, 0);
cam.near = 10f;
cam.far = 500f;
cam.update();
camCtrl = new CameraInputController(cam);
camCtrl.pinchZoomFactor = 50f;
camCtrl.scrollFactor = -0.5f;
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(new InputMultiplexer(stage, camCtrl));
/* font = new BitmapFont();
font.getData().setScale(2f);
*/
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("Montserrat-Bold.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
// 2. Устанавливаем нужный размер СРАЗУ (вместо setScale)
parameter.size = 20;
// 3. Указываем, какие символы нужно подготовить (обязательно добавляем русские!)
String RUSSIAN_CHARACTERS = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
parameter.characters = FreeTypeFontGenerator.DEFAULT_CHARS + RUSSIAN_CHARACTERS;
// 4. Генерируем сам шрифт
font = generator.generateFont(parameter);
uiBtnTexture = createButtonTexture();
createMenuButton();
createTimerUI(); // Создаем интерфейс таймера
helpUI = new HelpUI(stage, font, game);
env = new Environment();
env.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
env.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
sm = new SceneManager();
sm.loadLevel(level);
lr = new LaserRenderer(game.shapeRenderer);
levelTime = 0; // Сброс таймера при старте
}
private void createTimerUI() {
timerLabel = new Label("ВРЕМЯ: 0.0", new Label.LabelStyle(font, Color.WHITE));
timerLabel.setPosition(20, Gdx.graphics.getHeight() - 150);
stage.addActor(timerLabel);
}
private void createMenuButton() {
Stack menuStack = new Stack();
Image btnImg = new Image(uiBtnTexture);
Label btnLbl = new Label("МЕНЮ", new Label.LabelStyle(font, Color.BLACK));
btnLbl.setAlignment(com.badlogic.gdx.utils.Align.center);
menuStack.add(btnImg);
menuStack.add(btnLbl);
menuStack.setSize(140, 70);
menuStack.setPosition(20, Gdx.graphics.getHeight() - 90);
menuStack.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new LevelSelectScreen(game));
}
});
stage.addActor(menuStack);
}
private Texture createButtonTexture() {
Pixmap pm = new Pixmap(128, 64, Pixmap.Format.RGBA8888);
pm.setColor(Color.BLACK);
pm.fillRectangle(0, 0, 128, 64);
pm.setColor(Color.WHITE);
pm.fillRectangle(3, 3, 122, 58);
Texture t = new Texture(pm);
pm.dispose();
return t;
}
@Override
public void render(float delta) {
// Обновляем таймер, только если уровень еще не пройден полностью (до начала winTimer)
boolean allHit = sm.targets.size > 0;
for (Target t : sm.targets) {
if (!t.hit) {
allHit = false;
break;
}
}
if (!allHit) {
levelTime += delta;
timerLabel.setText(String.format("ВРЕМЯ: %.1f", levelTime));
// Подсветка таймера золотым, если укладываемся в лимит
float timeLimit = 2.0f + (0.1f * level);
if (levelTime <= timeLimit) {
timerLabel.setColor(Color.GOLD);
} else {
timerLabel.setColor(Color.GRAY);
}
}
if (Gdx.input.justTouched()) {
boolean hitUI = stage.hit(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY(), true) != null;
if (!hitUI) {
sm.checkClick(cam.getPickRay(Gdx.input.getX(), Gdx.input.getY()));
}
}
camCtrl.update();
lr.calculate(sm);
if (allHit) {
winTimer += delta;
if (winTimer > 2f) {
Preferences prefs = Gdx.app.getPreferences("LaserPuzzleSettings");
int reachedLevel = prefs.getInteger("reachedLevel", 1);
// Сохраняем прогресс уровней
if (level >= reachedLevel) {
prefs.putInteger("reachedLevel", level + 1);
}
// Проверяем на "золотую звезду" (лимит времени)
float timeLimit = 2.0f + (0.1f * level);
if (levelTime <= timeLimit) {
// Сохраняем флаг золотого уровня
prefs.putBoolean("gold_" + level, true);
}
prefs.flush();
// Переход на следующий уровень
if (level < 40) {
game.setScreen(new GameScreen(game, level + 1));
} else {
game.setScreen(new LevelSelectScreen(game));
}
}
} else {
winTimer = 0;
}
Gdx.gl.glClearColor(1f, 1f, 1f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
game.modelBatch.begin(cam);
sm.render(game.modelBatch, env);
game.modelBatch.end();
lr.render(cam);
stage.act(delta);
stage.draw();
}
@Override public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
timerLabel.setPosition(100, height - 150);
}
@Override public void dispose() {
if (sm != null) sm.dispose();
if (stage != null) stage.dispose();
if (uiBtnTexture != null) uiBtnTexture.dispose();
if (font != null) font.dispose();
if (helpUI != null) helpUI.dispose();
}
@Override public void pause() {}
@Override public void resume() {}
@Override public void hide() {}
}
+156
View File
@@ -0,0 +1,156 @@
package com.mygdx.game;
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.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
public class HelpUI {
private final Stage stage;
private final Table helpMenu;
private Texture circleTexture;
private Texture rectTexture;
private Texture closeTexture;
private final Label musicStatusLabel;
public HelpUI(final Stage stage, BitmapFont font, final MyGdxGame game) {
this.stage = stage;
circleTexture = createCircleTexture(60, Color.WHITE);
rectTexture = createRectTexture(1, 1, new Color(0, 0, 0, 0.85f));
closeTexture = createRectTexture(40, 40, Color.RED);
float screenWidth = stage.getViewport().getWorldWidth();
float screenHeight = stage.getViewport().getWorldHeight();
// --- Кнопка Помощи (?) ---
Stack helpBtn = new Stack();
Image bgHelp = new Image(circleTexture);
Label symbolHelp = new Label("?", new Label.LabelStyle(font, Color.BLACK));
symbolHelp.setAlignment(Align.center);
helpBtn.add(bgHelp);
helpBtn.add(symbolHelp);
helpBtn.setSize(60, 60);
helpBtn.setPosition(screenWidth - 80, screenHeight - 80);
// --- Кнопка Музыки ---
Stack musicBtn = new Stack();
Image bgMusic = new Image(circleTexture);
musicStatusLabel = new Label(game.audioManager.isMusicOn ? "ON" : "OFF", new Label.LabelStyle(font, Color.BLACK));
musicStatusLabel.setFontScale(0.6f);
musicStatusLabel.setAlignment(Align.center);
musicBtn.add(bgMusic);
musicBtn.add(musicStatusLabel);
musicBtn.setSize(60, 60);
musicBtn.setPosition(screenWidth - 150, screenHeight - 80);
// --- Окно помощи ---
helpMenu = new Table();
helpMenu.setFillParent(true);
helpMenu.setVisible(false);
Image overlay = new Image(rectTexture);
overlay.setFillParent(true);
Table content = new Table();
// Устанавливаем темно-синий фон для контента
content.setBackground(new Image(createRectTexture(1, 1, new Color(0.1f, 0.1f, 0.15f, 1f))).getDrawable());
content.pad(50); // Увеличены отступы
Stack closeBtn = new Stack();
Image closeBg = new Image(closeTexture);
Label closeX = new Label("X", new Label.LabelStyle(font, Color.WHITE));
closeX.setAlignment(Align.center);
closeBtn.add(closeBg);
closeBtn.add(closeX);
Label title = new Label("КАК ИГРАТЬ", new Label.LabelStyle(font, Color.GOLD));
title.setFontScale(1.2f); // Увеличен заголовок
// Текст с правилами
Label description = new Label(
"1. Нажимай на зеркала, чтобы вращать их.\n\n" +
"2. Направляй лазер на все пирамиды-цели.\n\n" +
"3. Когда все цели станут зелеными, уровень пройден!\n\n\n" +
"[ СИСТЕМА ЗВЕЗД ]\n\n" +
"Пройди уровень быстро, чтобы получить Золотой Статус.\n" +
"Лимит времени = 2.0 сек + 0.1 сек за каждый уровень.\n" +
"Золотые уровни подсвечиваются желтым в меню!",
new Label.LabelStyle(font, Color.WHITE)
);
description.setWrap(true);
description.setAlignment(Align.left);
description.setFontScale(0.95f); // Масштаб текста возвращен к комфортному размеру
Table header = new Table();
header.add(title).expandX().left();
header.add(closeBtn).size(50, 50).right(); // Кнопка закрытия чуть больше
content.add(header).fillX().row();
content.add(new Label("", new Label.LabelStyle(font, Color.WHITE))).pad(15).row();
// Увеличена ширина текстового блока до 600 пикселей
content.add(description).width(600).padTop(10);
helpMenu.stack(overlay, content).center();
// --- Слушатели ---
helpBtn.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
helpMenu.setVisible(true);
}
});
closeBtn.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
helpMenu.setVisible(false);
}
});
musicBtn.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.audioManager.isMusicOn = !game.audioManager.isMusicOn;
game.audioManager.updateMusicFlag();
musicStatusLabel.setText(game.audioManager.isMusicOn ? "ON" : "OFF");
}
});
stage.addActor(helpBtn);
stage.addActor(musicBtn);
stage.addActor(helpMenu);
}
private Texture createCircleTexture(int size, Color color) {
Pixmap pixmap = new Pixmap(size, size, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.BLACK);
pixmap.fillCircle(size / 2, size / 2, size / 2 - 1);
pixmap.setColor(color);
pixmap.fillCircle(size / 2, size / 2, size / 2 - 4);
Texture t = new Texture(pixmap);
pixmap.dispose();
return t;
}
private Texture createRectTexture(int w, int h, Color color) {
Pixmap pixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
pixmap.setColor(color);
pixmap.fill();
Texture t = new Texture(pixmap);
pixmap.dispose();
return t;
}
public void dispose() {
if (circleTexture != null) circleTexture.dispose();
if (rectTexture != null) rectTexture.dispose();
if (closeTexture != null) closeTexture.dispose();
}
}
@@ -0,0 +1,97 @@
package com.mygdx.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.*;
import com.badlogic.gdx.math.collision.Ray;
import com.badlogic.gdx.utils.Array;
public class LaserRenderer {
private final ShapeRenderer sr;
private final Array<Array<Vector3>> paths = new Array<>();
private final Vector3 tmpHit = new Vector3(), hitPoint = new Vector3(), normal = new Vector3();
private final Ray ray = new Ray();
public LaserRenderer(ShapeRenderer sr) { this.sr = sr; }
public void calculate(SceneManager sm) {
paths.clear();
for (Target t : sm.targets) t.hit = false;
for (Emitter e : sm.emitters) {
Array<Vector3> path = new Array<>();
Vector3 pos = e.instance.transform.getTranslation(new Vector3()).add(0, SceneManager.LASER_HEIGHT, 0);
Vector3 dir = new Vector3(e.direction).nor();
path.add(new Vector3(pos));
trace(pos, dir, path, sm);
paths.add(path);
}
}
private void trace(Vector3 pos, Vector3 dir, Array<Vector3> path, SceneManager sm) {
for (int i = 0; i < 25; i++) {
float minD = Float.MAX_VALUE;
Object hitObj = null;
ray.set(pos, dir);
for (Wall w : sm.walls) if (w.active && intersect(ray, w.instance.transform, tmpHit)) {
float d = pos.dst2(tmpHit);
if (d < minD) { minD = d; hitPoint.set(tmpHit); hitObj = w; }
}
for (Mirror m : sm.mirrors) if (intersect(ray, m.transform, tmpHit)) {
float d = pos.dst2(tmpHit);
if (d < minD) {
minD = d;
hitPoint.set(tmpHit);
hitObj = m;
normal.set(0, 0, 1).rot(m.transform).nor();
}
}
for (Target t : sm.targets) if (Intersector.intersectRaySphere(ray, t.getPos(), 3.5f, tmpHit)) {
float d = pos.dst2(tmpHit);
if (d < minD) { minD = d; hitPoint.set(tmpHit); hitObj = t; }
}
if (hitObj == null) {
path.add(new Vector3(pos).add(new Vector3(dir).scl(1000f)));
break;
}
path.add(new Vector3(hitPoint));
if (hitObj instanceof Target) {
((Target)hitObj).hit = true;
break;
}
if (hitObj instanceof Wall) break;
float dot = dir.dot(normal);
dir.sub(new Vector3(normal).scl(2 * dot)).nor();
pos.set(hitPoint).add(new Vector3(dir).scl(0.5f));
}
}
private boolean intersect(Ray r, Matrix4 transform, Vector3 out) {
Matrix4 inv = new Matrix4(transform).inv();
Ray localRay = new Ray(new Vector3(r.origin).mul(inv), new Vector3(r.direction).rot(inv));
if (Intersector.intersectRayBounds(localRay, Mirror.bounds, out)) {
out.mul(transform);
return true;
}
return false;
}
public void render(PerspectiveCamera cam) {
sr.setProjectionMatrix(cam.combined);
sr.begin(ShapeRenderer.ShapeType.Line);
Gdx.gl.glLineWidth(5);
sr.setColor(Color.RED);
for (Array<Vector3> p : paths) {
for (int i = 0; i < p.size - 1; i++) {
sr.line(p.get(i), p.get(i + 1));
}
}
sr.end();
Gdx.gl.glLineWidth(1);
}
}
@@ -0,0 +1,143 @@
package com.mygdx.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
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.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
public class LevelSelectScreen implements Screen {
private final MyGdxGame game;
private Stage stage;
private BitmapFont font;
private Texture btnTex;
private Texture btnLockedTex;
private Texture btnGoldTex; // Текстура для золотого уровня
public LevelSelectScreen(MyGdxGame game) {
this.game = game;
}
@Override
public void show() {
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(stage);
// ВМЕСТО ЭТИХ ДВУХ СТРОК:
/*
font = new BitmapFont();
font.getData().setScale(2f);
*/
// 1. Создаем генератор из нашего .ttf файла
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("Montserrat-Bold.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
// 2. Устанавливаем нужный размер СРАЗУ (вместо setScale)
parameter.size = 20;
// 3. Указываем, какие символы нужно подготовить (обязательно добавляем русские!)
String RUSSIAN_CHARACTERS = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
parameter.characters = FreeTypeFontGenerator.DEFAULT_CHARS + RUSSIAN_CHARACTERS;
// 4. Генерируем сам шрифт
font = generator.generateFont(parameter);
btnTex = createBtnTexture(Color.WHITE);
btnLockedTex = createBtnTexture(Color.GRAY);
btnGoldTex = createBtnTexture(Color.GOLD); // Создаем золотую текстуру
Table container = new Table();
container.setFillParent(true);
Table grid = new Table();
grid.pad(20);
Preferences prefs = Gdx.app.getPreferences("LaserPuzzleSettings");
int reachedLevel = prefs.getInteger("reachedLevel", 1);
for (int i = 1; i <= 40; i++) {
final int levelNum = i;
boolean isGold = prefs.getBoolean("gold_" + i, false); // Проверка на золото
TextButton.TextButtonStyle style = new TextButton.TextButtonStyle();
style.font = font;
if (i <= reachedLevel) {
// Если уровень пройден быстро, ставим золотую текстуру
style.up = new TextureRegionDrawable(isGold ? btnGoldTex : btnTex);
style.fontColor = Color.BLACK;
} else {
style.up = new TextureRegionDrawable(btnLockedTex);
style.fontColor = Color.DARK_GRAY;
}
TextButton btn = new TextButton(String.valueOf(i), style);
if (i <= reachedLevel) {
btn.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new GameScreen(game, levelNum));
}
});
}
grid.add(btn).size(120, 120).pad(10);
if (i % 5 == 0) grid.row();
}
ScrollPane scroll = new ScrollPane(grid);
container.add(new Label("ВЫБОР УРОВНЯ", new Label.LabelStyle(font, Color.WHITE))).padBottom(20).row();
container.add(scroll).expand().fill();
stage.addActor(container);
}
private Texture createBtnTexture(Color color) {
Pixmap pm = new Pixmap(128, 128, Pixmap.Format.RGBA8888);
pm.setColor(Color.BLACK);
pm.fillRectangle(0, 0, 128, 128);
pm.setColor(color);
pm.fillRectangle(4, 4, 120, 120);
Texture t = new Texture(pm);
pm.dispose();
return t;
}
@Override
public void render(float delta) {
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(delta);
stage.draw();
}
@Override public void resize(int width, int height) { stage.getViewport().update(width, height, true); }
@Override public void pause() {}
@Override public void resume() {}
@Override public void hide() {}
@Override public void dispose() {
stage.dispose();
font.dispose();
btnTex.dispose();
btnLockedTex.dispose();
btnGoldTex.dispose();
}
}
+116
View File
@@ -0,0 +1,116 @@
package com.mygdx.game;
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.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.Rectangle;
import com.badlogic.gdx.math.Vector3;
public class MenuScreen implements Screen {
private final MyGdxGame game;
private SpriteBatch batch;
private ShapeRenderer sr;
private final OrthographicCamera cam;
private BitmapFont buttonFont;
private BitmapFont brandFont;
private GlyphLayout layout;
private final Rectangle btn = new Rectangle();
private final Vector3 touch = new Vector3();
private boolean initialized = false;
private Texture texture;
public MenuScreen(MyGdxGame game) {
this.game = game;
this.cam = new OrthographicCamera();
try {
texture = new Texture("menu_bg.png");
} catch (Exception e) {
texture = null;
}
layout = new GlyphLayout();
buttonFont = new BitmapFont();
buttonFont.getData().setScale(2.5f);
brandFont = new BitmapFont();
brandFont.getData().setScale(5.0f);
}
@Override
public void show() {
if (!initialized) {
this.batch = new SpriteBatch();
this.sr = new ShapeRenderer();
initialized = true;
}
resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
@Override
public void render(float delta) {
if (!initialized) return;
if (Gdx.input.justTouched()) {
cam.unproject(touch.set(Gdx.input.getX(), Gdx.input.getY(), 0));
if (btn.contains(touch.x, touch.y)) {
game.setScreen(new LevelSelectScreen(game));
}
}
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(cam.combined);
batch.begin();
if (texture != null) {
batch.draw(texture, 0, 0, cam.viewportWidth, cam.viewportHeight);
}
batch.end();
sr.setProjectionMatrix(cam.combined);
sr.begin(ShapeRenderer.ShapeType.Filled);
sr.setColor(Color.DARK_GRAY);
sr.rect(btn.x + 5, btn.y - 5, btn.width, btn.height);
sr.setColor(Color.FOREST);
sr.rect(btn.x, btn.y, btn.width, btn.height);
sr.end();
batch.begin();
drawButtonText(buttonFont, "START");
brandFont.setColor(Color.WHITE);
brandFont.draw(batch, "by Hikolit", 30, 80);
batch.end();
}
private void drawButtonText(BitmapFont font, String text) {
font.setColor(Color.WHITE);
layout.setText(font, text);
float x = btn.x + (btn.width - layout.width) / 2f;
float y = btn.y + (btn.height + layout.height) / 2f;
font.draw(batch, text, x, y);
}
@Override
public void resize(int w, int h) {
cam.setToOrtho(false, w, h);
btn.set(w / 2f - 200, h / 2f - 60, 400, 120);
}
@Override
public void dispose() {
if (texture != null) texture.dispose();
if (batch != null) batch.dispose();
if (sr != null) sr.dispose();
if (buttonFont != null) buttonFont.dispose();
if (brandFont != null) brandFont.dispose();
}
@Override public void pause() {}
@Override public void resume() {}
@Override public void hide() {}
}
+37
View File
@@ -0,0 +1,37 @@
package com.mygdx.game;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.math.collision.Ray;
class Mirror extends ModelInstance {
public float angle;
private final Matrix4 inv = new Matrix4();
public static final BoundingBox bounds = new BoundingBox(new Vector3(-2.2f, -4f, -0.4f), new Vector3(2.2f, 4f, 0.4f));
public Mirror(Model m, float x, float y, float z, float a) {
super(m);
transform.setToTranslation(x, y, z);
angle = a;
update();
}
public void rotate() {
angle = (angle + 45f) % 360f;
update();
}
private void update() {
Vector3 p = transform.getTranslation(new Vector3());
transform.setToRotation(Vector3.Y, angle).setTranslation(p);
inv.set(transform).inv();
}
public boolean intersect(Ray r) {
return Intersector.intersectRayBoundsFast(new Ray(new Vector3(r.origin).mul(inv), new Vector3(r.direction).rot(inv)), bounds);
}
}
+31
View File
@@ -0,0 +1,31 @@
package com.mygdx.game;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
public class MyGdxGame extends Game {
public ModelBatch modelBatch;
public ShapeRenderer shapeRenderer;
public AudioManager audioManager;
@Override
public void create() {
audioManager = new AudioManager();
modelBatch = new ModelBatch();
shapeRenderer = new ShapeRenderer();
setScreen(new MenuScreen(this));
}
@Override
public void render() {
super.render();
}
@Override
public void dispose() {
if (modelBatch != null) modelBatch.dispose();
if (shapeRenderer != null) shapeRenderer.dispose();
if (getScreen() != null) getScreen().dispose();
}
}
+135
View File
@@ -0,0 +1,135 @@
package com.mygdx.game;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.g3d.*;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.Ray;
import com.badlogic.gdx.utils.Array;
public class SceneManager {
public Array<Mirror> mirrors = new Array<>();
public Array<Emitter> emitters = new Array<>();
public Array<Target> targets = new Array<>();
public Array<Wall> walls = new Array<>();
public ModelInstance floor;
private final Model mirrorModel;
private final Model floorModel;
private final Model pyrModel;
private final Model boxModel;
private int currentLevel;
public static final float UNIT = 10.0f;
public static final float MIRROR_H = 10.0f;
public static final float LASER_HEIGHT = 5.0f;
public SceneManager() {
ModelBuilder mb = new ModelBuilder();
long attr = VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal;
mirrorModel = mb.createBox(6f, MIRROR_H, 1.0f, new Material(ColorAttribute.createDiffuse(Color.SKY)), attr);
floorModel = mb.createBox(400f, 0.5f, 400f, new Material(ColorAttribute.createDiffuse(Color.DARK_GRAY)), attr);
boxModel = mb.createBox(UNIT, UNIT, UNIT, new Material(ColorAttribute.createDiffuse(Color.GRAY)), attr);
mb.begin();
MeshPartBuilder mpb = mb.part("pyr", GL20.GL_TRIANGLES, attr, new Material(ColorAttribute.createDiffuse(Color.WHITE)));
Vector3 top = new Vector3(0, LASER_HEIGHT, 0), v1 = new Vector3(-2f,0,2f), v2 = new Vector3(2f,0,2f), v3 = new Vector3(2f,0,-2f), v4 = new Vector3(-2f,0,-2f);
mpb.triangle(top, v1, v2); mpb.triangle(top, v2, v3); mpb.triangle(top, v3, v4); mpb.triangle(top, v4, v1);
mpb.rect(v4, v3, v2, v1, new Vector3(0,-1,0));
pyrModel = mb.end();
floor = new ModelInstance(floorModel, 0, -0.25f, 0);
}
public void loadLevel(int lvl) {
this.currentLevel = lvl;
clearCurrentLevel();
switch (lvl) {
case 1: addEmitter(-2, 0, 1, 0, 0); addMirror(0, 0, 45); addTarget(0, 2); break;
case 2: addEmitter(-2, 0, 1, 0, 0); addWall(0, 0); addMirror(-1, 0, 45); addMirror(-1, 1, 45); addTarget(2, 1); break;
case 3: addEmitter(-2, -2, 1, 0, 0); addMirror(1, -2, 45); addMirror(1, 0, 135); addTarget(-2, 0); break;
case 4: addEmitter(-2, 2, 0, 0, -1); addWall(-1, 1); addWall(0, 1); addWall(1, 1); addMirror(-2, -1, 45); addMirror(2, -1, 45); addTarget(2, 2); break;
case 5: addEmitter(-1, -2, 0, 0, 1); addMirror(-1, 2, 45); addMirror(1, 2, 45); addTarget(1, -2); break;
case 6: addEmitter(-2, 0, 1, 0, 0); addEmitter(0, -2, 0, 0, 1); addMirror(1, 0, 45); addMirror(0, 1, 45); addTarget(1, 2); addTarget(2, 1); break;
case 7: addEmitter(-2, 1, 1, 0, 0); addEmitter(-2, -1, 1, 0, 0); addWall(0, 0); addMirror(1, 1, 45); addMirror(1, -1, 45); addTarget(1, 2); addTarget(1, -2); break;
case 8: addEmitter(-2, 2, 1, 0, 0); addEmitter(-2, -2, 1, 0, 0); addMirror(0, 2, 45); addMirror(0, -2, 45); addWall(0, 0); addTarget(2, 2); addTarget(2, -2); break;
case 9: for(int i=-1; i<=1; i++) addWall(i, 0); addEmitter(-2, 1, 0, 0, -1); addEmitter(2, 1, 0, 0, -1); addMirror(-2, -1, 45); addMirror(2, -1, 45); addTarget(-1, -1); addTarget(1, -1); break;
case 10: addEmitter(-1, -1, 1, 0, 0); addEmitter(1, 1, -1, 0, 0); addMirror(1, -1, 45); addMirror(-1, 1, 45); addTarget(1, 0); addTarget(-1, 0); break;
case 11: addEmitter(-2, 2, 1, 0, 0); addWall(-1, 1); addWall(1, 1); addWall(0, 0); addMirror(2, 2, 45); addMirror(2, -2, 45); addMirror(-2, -2, 45); addTarget(-2, 0); break;
case 12: addEmitter(0, 0, 1, 0, 0); addMirror(2, 0, 45); addMirror(2, 2, 135); addMirror(-2, 2, 45); addMirror(-2, -2, 135); addTarget(0, -2); break;
case 13: addEmitter(-2, 2, 1, 0, 0); addEmitter(-2, 0, 1, 0, 0); addEmitter(-2, -2, 1, 0, 0); addMirror(0, 2, 45); addMirror(0, 0, 45); addMirror(0, -2, 45); addTarget(2, 2); addTarget(2, 0); addTarget(2, -2); break;
case 14: for(int i=-1; i<=1; i++) for(int j=-1; j<=1; j++) addWall(i, j); addEmitter(-3, 0, 0, 0, 1); addMirror(-3, 3, 45); addMirror(3, 3, 45); addMirror(3, -3, 45); addMirror(-2, -3, 45); addMirror(-2, -2, 45); addTarget(0, -2); break;
case 15: addEmitter(-2, 2, 0, 0, -1); addMirror(-2, -2, 45); addMirror(-1, -2, 45); addMirror(-1, 2, 45); addMirror(0, 2, 45); addMirror(0, -2, 45); addMirror(1, -2, 45); addMirror(1, 2, 45); addMirror(2, 2, 45); addTarget(2, -2); break;
case 16: for(int x=-2; x<=2; x++) { addWall(x, 3); addWall(x, -3); } addEmitter(-1, 0, 0, 0, 1); addMirror(-1, 2, 45); addMirror(1, 2, 45); addMirror(1, -2, 45); addMirror(2, -2, 45); addMirror(2, 0, 45); addTarget(0, 0); break;
case 17: addEmitter(-4, -5, 0, 0, 1); addMirror(-4, -3, 45); addMirror(-2, -3, 135); addMirror(-2, -1, 45); addMirror(2, -1, 135); addMirror(2, 1, 45); addMirror(-2, 1, 135); addMirror(-2, 3, 45); addMirror(2, 3, 135); addTarget(2, 5); break;
case 18: addEmitter(-2, 1, 1, 0, 0); addEmitter(2, -1, -1, 0, 0); addMirror(0, 1, 45); addMirror(0, -1, 45); addMirror(-1, 0, 135); addMirror(1, 0, 135); addTarget(2, 1); addTarget(-2, -1); break;
case 19: addEmitter(-5, 0, 1, 0, 0); addMirror(-3, 0, 45); addMirror(-3, -3, 135); addMirror(1, -3, 45); addMirror(1, 3, 135); addMirror(3, 3, 45); addMirror(3, 0, 135); addTarget(5, 0); break;
case 20: int[][] heartWalls = {{0, -4}, {-1, -3}, {1, -3}, {-2, -2}, {2, -2}, {-3, -1}, {3, -1}, {-4, 0}, {4, 0}, {-4, 1}, {4, 1}, {-3, 2}, {3, 2}, {-2, 3}, {2, 3}, {-1, 3}, {1, 3}}; for(int[] p : heartWalls) addWall(p[0], p[1]); addEmitter(0, 5, 0, 0, -1); addMirror(0, 2, 45); addMirror(2, 2, 135); addMirror(2, -1, 45); addMirror(-2, -1, 135); addMirror(-2, 1, 45); addTarget(0, 0); break;
case 21: addEmitter(-4, -4, 1, 0, 0); for(int i=-2; i<=2; i++) { addWall(i, -1); addWall(i, 1); } addMirror(4, -4, 45); addMirror(4, 0, 45); addMirror(-4, 0, 45); addMirror(-4, 4, 45); addTarget(4, 4); break;
case 22: addEmitter(-5, -2, 1, 0, 0); for(int z=-5; z<=5; z++) { if(z != -2) addWall(-2, z); if(z != 2) addWall(2, z); } addMirror(0, -2, 45); addMirror(0, 2, 135); addTarget(5, 2); break;
case 23: addEmitter(-5, -5, 1, 0, 0); addMirror(-2, -5, 45); addMirror(-2, 0, 135); addMirror(2, 0, 45); addMirror(2, 5, 135); addTarget(5, 5); break;
case 24: for(int x=-1; x<=1; x++) for(int z=-1; z<=1; z++) addWall(x, z); addEmitter(-4, 0, 0, 0, 1); addMirror(-4, 4, 45); addMirror(4, 4, 135); addMirror(4, -4, 45); addMirror(0, -4, 135); addTarget(0, -2); break;
case 25: addEmitter(-5, 0, 1, 0, 0); for(int i=-1; i<=1; i++) { addWall(i, 0); addWall(0, i); } addMirror(-3, 0, 45); addMirror(-3, 3, 45); addMirror(3, 3, 45); addMirror(3, 0, 45); addTarget(5, 0); break;
case 26: addEmitter(-6, -3, 1, 0, 0); addEmitter(-6, 0, 1, 0, 0); addEmitter(-6, 3, 1, 0, 0); addMirror(0, -3, 45); addMirror(2, 0, 135); addMirror(4, 3, 45); addTarget(0, 6); addTarget(2, -4); addTarget(4, 8); break;
case 27: addEmitter(-4, 0, 1, 0, 0); addMirror(0, 0, 45); addMirror(0, 2, 135); addTarget(-4, 2); break;
case 28: addEmitter(-8, -4, 1, 0, 0); addEmitter(-8, 0, 1, 0, 0); addEmitter(-8, 4, 1, 0, 0); addMirror(-4, -4, 45); addMirror(0, 0, 135); addMirror(4, 4, 45); addTarget(-4, 2); addTarget(0, -6); addTarget(4, 10); break;
case 29: addEmitter(-6, -4, 1, 0, 0); addEmitter(-6, 0, 1, 0, 0); addEmitter(-6, 4, 1, 0, 0); addMirror(-2, -4, 45); addMirror(-2, -2, 135); addMirror(0, 0, 45); addMirror(0, 2, 135); addMirror(2, 4, 45); addMirror(2, 6, 135); addTarget(6, -2); addTarget(6, 2); addTarget(6, 6); break;
case 30: addEmitter(-6, -2, 1, 0, 0); addEmitter(-6, 2, 1, 0, 0); for(int x=-4; x<=4; x++) addWall(x, 0); addMirror(-2, -2, 45); addMirror(2, -2, 135); addMirror(-2, 2, 135); addMirror(2, 2, 45); addTarget(6, -2); addTarget(6, 2); break;
case 31: addEmitter(-7, -7, 1, 0, 1); addEmitter(7, -7, -1, 0, 1); addEmitter(0, -10, 0, 0, 1); addMirror(-3, -3, 45); addMirror(3, -3, 135); addMirror(0, 0, 90); addTarget(-5, 5); addTarget(5, 5); addTarget(0, 8); break;
case 32: addEmitter(-4, 0, 1, 0, 0); addEmitter(4, 0, -1, 0, 0); addEmitter(0, -4, 0, 0, 1); addMirror(-2, 0, 45); addMirror(2, 0, 135); addMirror(0, -2, 45); addTarget(-2, 5); addTarget(2, 5); addTarget(5, -2); break;
case 33: addEmitter(-7, -3, 1, 0, 0); addEmitter(-7, 0, 1, 0, 0); addEmitter(-7, 3, 1, 0, 0); for(int z=-5; z<=5; z++) if(z % 3 != 0) addWall(0, z); addMirror(-3, -3, 45); addMirror(-3, 0, 135); addMirror(-3, 3, 45); addTarget(3, -3); addTarget(3, 0); addTarget(3, 3); break;
case 34: addEmitter(-6, -6, 1, 0, 0); addEmitter(-6, 0, 1, 0, 0); addEmitter(-6, 6, 1, 0, 0); addMirror(0, -6, 45); addMirror(0, 0, 135); addMirror(0, 6, 45); addTarget(0, -3); addTarget(0, 3); addTarget(0, 9); break;
case 35: addEmitter(-5, 0, 1, 0, 0); addEmitter(5, 0, -1, 0, 0); addMirror(0, 0, 45); addTarget(0, 3); addTarget(0, -3); break;
case 36: addEmitter(-8, -4, 1, 0, 0); addEmitter(-8, 4, 1, 0, 0); for(int i=-2; i<=2; i++) addWall(0, i); addMirror(-4, -4, 45); addMirror(-4, 4, 135); addMirror(4, -4, 135); addMirror(4, 4, 45); addTarget(8, -4); addTarget(8, 4); break;
case 37: addEmitter(-8, 0, 1, 0, 0); addMirror(-6, 0, 45); addMirror(-6, 4, 135); addMirror(0, 4, 45); addMirror(0, -4, 135); addMirror(6, -4, 45); addMirror(6, 0, 135); addTarget(9, 0); break;
case 38: addEmitter(-7, -5, 1, 0, 0); addEmitter(-7, 0, 1, 0, 0); addEmitter(-7, 5, 1, 0, 0); addWall(-2, -2); addWall(-2, 2); addWall(2, -2); addWall(2, 2); addMirror(-4, -5, 45); addMirror(-4, 5, 135); addMirror(0, 0, 90); addTarget(7, -5); addTarget(7, 0); addTarget(7, 5); break;
case 39: addEmitter(-5, -5, 1, 0, 0); for(int i=-3; i<=3; i++) { addWall(i, -3); addWall(i, 3); addWall(3, i); } addMirror(5, -5, 45); addMirror(5, 5, 135); addMirror(-5, 5, 45); addMirror(-5, 0, 135); addTarget(0, 0); break;
case 40: addEmitter(-12, -12, 1, 0, 0);for(int i = -3; i <= 3; i++) {addWall(i, 0);addWall(0, i);}addMirror(-8, -12, 45);addMirror(-8, -8, 135);addMirror(-4, -8, 45);addMirror(-4, -4, 135);addMirror(4, -4, 45);addMirror(4, 4, 135);addMirror(8, 4, 45);addMirror(8, 8, 135);addMirror(12, 8, 45);addMirror(12, 12, 135);addMirror(-12, 12, 45);addMirror(-12, 0, 135);addTarget(12, 0);break; default: addEmitter(-1, 0, 1, 0, 0);addTarget(1, 0);break;
}
}
private void clearCurrentLevel() {
mirrors.clear(); emitters.clear(); targets.clear(); walls.clear();
}
private void addEmitter(int gx, int gz, float dx, float dy, float dz) {
emitters.add(new Emitter(pyrModel, gx * UNIT, 0, gz * UNIT, dx, dy, dz));
}
private void addTarget(int gx, int gz) {
targets.add(new Target(pyrModel, gx * UNIT, 0, gz * UNIT));
}
private void addMirror(int gx, int gz, float angle) {
mirrors.add(new Mirror(mirrorModel, gx * UNIT, MIRROR_H/2, gz * UNIT, angle));
}
private void addWall(int gx, int gz) {
walls.add(new Wall(boxModel, gx * UNIT, UNIT / 2f, gz * UNIT));
}
public void render(ModelBatch batch, Environment env) {
batch.render(floor, env);
for (Emitter e : emitters) batch.render(e.instance, env);
for (Target t : targets) {
t.updateVisual();
batch.render(t.instance, env);
}
for (Mirror m : mirrors) batch.render(m, env);
for (Wall w : walls) if(w.active) batch.render(w.instance, env);
}
public void checkClick(Ray ray) {
for (Mirror m : mirrors) if (m.intersect(ray)) { m.rotate(); break; }
}
public void dispose() {
mirrorModel.dispose(); floorModel.dispose(); pyrModel.dispose(); boxModel.dispose();
}
public void nextLevel() {
loadLevel((currentLevel % 40) + 1);
}
}
+24
View File
@@ -0,0 +1,24 @@
package com.mygdx.game;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.math.Vector3;
class Target {
public ModelInstance instance;
public boolean hit = false;
public Target(Model m, float x, float y, float z) {
instance = new ModelInstance(m, x, y, z);
}
public Vector3 getPos() {
return instance.transform.getTranslation(new Vector3()).add(0, SceneManager.LASER_HEIGHT, 0);
}
public void updateVisual() {
instance.nodes.get(0).parts.get(0).material.set(ColorAttribute.createDiffuse(hit ? Color.GREEN : Color.WHITE));
}
}
+13
View File
@@ -0,0 +1,13 @@
package com.mygdx.game;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
class Wall {
public ModelInstance instance;
public boolean active = true;
public Wall(Model m, float x, float y, float z) {
instance = new ModelInstance(m, x, y, z);
}
}
Binary file not shown.