diff --git a/GameEngine/resources/test2.png b/GameEngine/resources/test2.png new file mode 100644 index 0000000..c0e8f4b --- /dev/null +++ b/GameEngine/resources/test2.png Binary files differ diff --git a/GameEngine/src/main/java/Main.java b/GameEngine/src/main/java/Main.java index db7e308..055d229 100644 --- a/GameEngine/src/main/java/Main.java +++ b/GameEngine/src/main/java/Main.java @@ -1,8 +1,10 @@ +import gameEngine.GameEditor; import gameEngine.views.Window; public class Main { public static void main(String[] args) { Window window = Window.get(); window.run(); + } } \ No newline at end of file diff --git a/GameEngine/src/main/java/gameEngine/GameEditor.java b/GameEngine/src/main/java/gameEngine/GameEditor.java new file mode 100644 index 0000000..1b1b01c --- /dev/null +++ b/GameEngine/src/main/java/gameEngine/GameEditor.java @@ -0,0 +1,176 @@ +package gameEngine; + +import gameEngine.entites.GameObject; +import gameEngine.entites.gameComponents.ColorController; +import gameEngine.entites.gameComponents.Mesh; +import gameEngine.scenes.*; +import gameEngine.scenes.*; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Map; + +public class GameEditor extends JFrame { + + private JList objectList; + private DefaultListModel listModel; + private JTextField posXField, posYField, posZField; + private JTextField rotXField, rotYField, rotZField; + private JTextField scaleXField, scaleYField, scaleZField; + private JTextField nameField; + private Scene gameScene; + private Timer updateTimer; + + public GameEditor() { + setTitle("Game Object Editor"); + setSize(500, 400); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // 閉じられないようにする + + // 左側のリスト(GameObjectの一覧) + listModel = new DefaultListModel<>(); + objectList = new JList<>(listModel); + JScrollPane scrollPane = new JScrollPane(objectList); + scrollPane.setPreferredSize(new Dimension(150, 400)); + + // 右側のパネル(プロパティの編集) + JPanel propertyPanel = new JPanel(); + propertyPanel.setLayout(new GridLayout(6, 1)); // NewGameObjectボタン用に行を追加 + + // Name + JPanel namePanel = new JPanel(new FlowLayout()); + namePanel.add(new JLabel("Name:")); + nameField = new JTextField(20); + namePanel.add(nameField); + propertyPanel.add(namePanel); + + // Position + JPanel posPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5)); // 間隔をゼロに設定 + posPanel.add(new JLabel("Position:")); + posXField = new JTextField(5); + posYField = new JTextField(5); + posZField = new JTextField(5); + posPanel.add(posXField); + posPanel.add(posYField); + posPanel.add(posZField); + propertyPanel.add(posPanel); + + // Rotation + JPanel rotPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5)); + rotPanel.add(new JLabel("Rotation:")); + rotXField = new JTextField(5); + rotYField = new JTextField(5); + rotZField = new JTextField(5); + rotPanel.add(rotXField); + rotPanel.add(rotYField); + rotPanel.add(rotZField); + propertyPanel.add(rotPanel); + + // Scale + JPanel scalePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5)); + scalePanel.add(new JLabel("Scale:")); + scaleXField = new JTextField(5); + scaleYField = new JTextField(5); + scaleZField = new JTextField(5); + scalePanel.add(scaleXField); + scalePanel.add(scaleYField); + scalePanel.add(scaleZField); + propertyPanel.add(scalePanel); + + // New GameObjectボタンを追加 + JButton newGameObjectButton = new JButton("New GameObject"); + newGameObjectButton.addActionListener(e -> createNewGameObject()); + propertyPanel.add(newGameObjectButton); + + // Applyボタン + JButton applyButton = new JButton("Apply"); + applyButton.addActionListener(new ApplyButtonListener()); + propertyPanel.add(applyButton); + + // リスト選択時の処理 + objectList.addListSelectionListener(e -> loadSelectedGameObject()); + + // UIを追加 + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(scrollPane, BorderLayout.WEST); + getContentPane().add(propertyPanel, BorderLayout.CENTER); + + setVisible(true); + } + + // New GameObjectを作成 + private void createNewGameObject() { + gameScene.CreateNewObject(); + updateGameObjectList(gameScene); + } + + public void updateListByScene(Scene gameScene){ + this.gameScene = gameScene; + updateGameObjectList(gameScene); + } + + // GameObjectのリストを更新 + public void updateGameObjectList(Scene gameScene) { + listModel.clear(); + for (Map.Entry entry : gameScene.gameObjects.entrySet()) { + listModel.addElement(entry.getValue().name); // 名前をリストに表示 + } + } + + // 選択されたGameObjectのプロパティをロードする + private void loadSelectedGameObject() { + String selectedName = objectList.getSelectedValue(); + if (selectedName != null) { + for (Map.Entry entry : gameScene.gameObjects.entrySet()) { + GameObject gameObject = entry.getValue(); + if (gameObject.name.equals(selectedName)) { + nameField.setText(gameObject.name); + posXField.setText(String.valueOf(gameObject.transform.position.x)); + posYField.setText(String.valueOf(gameObject.transform.position.y)); + posZField.setText(String.valueOf(gameObject.transform.position.z)); + rotXField.setText(String.valueOf(gameObject.transform.rotation.x)); + rotYField.setText(String.valueOf(gameObject.transform.rotation.y)); + rotZField.setText(String.valueOf(gameObject.transform.rotation.z)); + scaleXField.setText(String.valueOf(gameObject.transform.scale.x)); + scaleYField.setText(String.valueOf(gameObject.transform.scale.y)); + scaleZField.setText(String.valueOf(gameObject.transform.scale.z)); + break; + } + } + } + } + + // 選択されたGameObjectのプロパティを更新 + private class ApplyButtonListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String selectedName = objectList.getSelectedValue(); + if (selectedName != null) { + for (Map.Entry entry : gameScene.gameObjects.entrySet()) { + GameObject gameObject = entry.getValue(); + if (gameObject.name.equals(selectedName)) { + gameObject.name = nameField.getText(); + gameObject.transform.setPosition( + Float.parseFloat(posXField.getText()), + Float.parseFloat(posYField.getText()), + Float.parseFloat(posZField.getText()) + ); + gameObject.transform.setRotation( + Float.parseFloat(rotXField.getText()), + Float.parseFloat(rotYField.getText()), + Float.parseFloat(rotZField.getText()) + ); + gameObject.transform.setScale( + Float.parseFloat(scaleXField.getText()), + Float.parseFloat(scaleYField.getText()), + Float.parseFloat(scaleZField.getText()) + ); + updateGameObjectList(gameScene); + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/GameEngine/src/main/java/gameEngine/entites/Camera.java b/GameEngine/src/main/java/gameEngine/entites/Camera.java index 99900bc..a2b5c13 100644 --- a/GameEngine/src/main/java/gameEngine/entites/Camera.java +++ b/GameEngine/src/main/java/gameEngine/entites/Camera.java @@ -2,4 +2,15 @@ public class Camera extends Entity{ + public enum ProjectionType{ + PERSPECTIVE, //透視投影 + ORTHOGRAPHIC, //平行投影 + } + + private final ProjectionType projection; + + public Camera(ProjectionType projection){ + this.projection = projection; + } + } diff --git a/GameEngine/src/main/java/gameEngine/entites/GameObject.java b/GameEngine/src/main/java/gameEngine/entites/GameObject.java index 0101214..9f13466 100644 --- a/GameEngine/src/main/java/gameEngine/entites/GameObject.java +++ b/GameEngine/src/main/java/gameEngine/entites/GameObject.java @@ -7,6 +7,7 @@ public class GameObject extends Entity { public boolean active = true; + public String name = "GameObject"; private final List gameComponents = new ArrayList<>(); public void addComponent(GameComponent component) { @@ -25,6 +26,10 @@ } } + public void setName(String name){ + this.name = name; + } + public void setActive(boolean active) { this.active = active; } diff --git a/GameEngine/src/main/java/gameEngine/entites/gameComponents/Mesh.java b/GameEngine/src/main/java/gameEngine/entites/gameComponents/Mesh.java index ea0bf8e..d2d37c1 100644 --- a/GameEngine/src/main/java/gameEngine/entites/gameComponents/Mesh.java +++ b/GameEngine/src/main/java/gameEngine/entites/gameComponents/Mesh.java @@ -1,6 +1,7 @@ package gameEngine.entites.gameComponents; import gameEngine.entites.GameObject; +import gameEngine.views.Texture; import gameEngine.views.Window; import static org.lwjgl.opengl.GL11.*; diff --git a/GameEngine/src/main/java/gameEngine/entites/gameComponents/Texture.java b/GameEngine/src/main/java/gameEngine/entites/gameComponents/Texture.java deleted file mode 100644 index 5cb612d..0000000 --- a/GameEngine/src/main/java/gameEngine/entites/gameComponents/Texture.java +++ /dev/null @@ -1,94 +0,0 @@ -package gameEngine.entites.gameComponents; - -import org.lwjgl.BufferUtils; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; - -import static org.lwjgl.opengl.GL11.*; - -public class Texture { - - /* - 指定された画像ファイルを読み込み、そのピクセルデータをOpenGLにアップロードして - テクスチャとして利用できるようにする - */ - - private int id; //OpenGLのテクスチャID - private int width; // 読み込んだ画像の幅 - private int height; // 読み込んだ画像の高さ - - public Texture(String path) { - BufferedImage bi; - try { - //ImageIO.read(new File(path)): 画像ファイルを読み込み、BufferedImageオブジェクトを作成 - //BufferedImageはJava標準ライブラリのクラス - bi = ImageIO.read(new File(path)); - width = bi.getWidth(); - height = bi.getHeight(); - - //画像のピクセルデータをRGB形式で取得 - //pixelsRawは整数配列で、各ピクセルの色データが格納される - int[] pixelsRaw = bi.getRGB(0, 0, width, height, null, 0, width); - - //BufferUtils.createByteBuffer(width * height * 4): OpenGLに送信するためのバッファ(ByteBuffer)を作成 - ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4); - - // 各ピクセルを取り出し、色成分(R, G, B, A)を抽出してByteBufferに格納 - // (pixel >> 16) & 0xFF: ピクセルデータの上位16ビットを右にシフトし、赤色成分を抽出。 - // 同様に緑(8ビット右シフト)、青(そのまま)、アルファ(24ビット右シフト)も抽出 - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - int pixel = pixelsRaw[y * width + x]; - pixels.put((byte) ((pixel >> 16) & 0xFF)); // Red - pixels.put((byte) ((pixel >> 8) & 0xFF)); // Green - pixels.put((byte) (pixel & 0xFF)); // Blue - pixels.put((byte) ((pixel >> 24) & 0xFF)); // Alpha - } - } - // ByteBufferを読み込み可能な状態に - pixels.flip(); - - // 新しいテクスチャIDを生成 - id = glGenTextures(); - - // 生成したテクスチャIDを現在のテクスチャとしてバインド - // 以降のテクスチャ関連の操作はこのテクスチャに対して行われる - glBindTexture(GL_TEXTURE_2D, id); - - // テクスチャデータをOpenGLに送信 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - //テクスチャのフィルタリング方法を設定 - //ニアレストフィルタリング:拡大縮小時のぼやけがなくなる - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // テクスチャのバインディングを解除 - glBindTexture(GL_TEXTURE_2D, 0); - - } catch (IOException e) { - e.printStackTrace(); - } - } - - public int getId() { - return id; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public void delete() { - //テクスチャを削除し、OpenGLからリソースを解放します。 - glDeleteTextures(id); - } -} \ No newline at end of file diff --git a/GameEngine/src/main/java/gameEngine/scenes/GameScene.java b/GameEngine/src/main/java/gameEngine/scenes/GameScene.java index fd2bba2..f8ad5db 100644 --- a/GameEngine/src/main/java/gameEngine/scenes/GameScene.java +++ b/GameEngine/src/main/java/gameEngine/scenes/GameScene.java @@ -9,45 +9,78 @@ import static org.lwjgl.opengl.GL11.glClearColor; public class GameScene extends Scene { - public GameScene(){ + + private boolean isCreateObject = false; + private boolean isAddComponent = false; + + public GameScene() { System.out.println("Active Game scene"); glClearColor(1, 1, 1, 0); - gameObjects.put("0", new GameObject()); - gameObjects.get("0").addComponent(new ColorController()); + gameObjects.put(0, new GameObject()); + gameObjects.get(0).addComponent(new ColorController()); + gameObjects.get(0).setName("ColorController"); - gameObjects.put("sprite", new GameObject()); - gameObjects.get("sprite").addComponent(new Mesh(gameObjects.get("sprite"), Mesh.MeshType.SPRITE, "test.png")); + gameObjects.put(1, new GameObject()); + gameObjects.get(1).addComponent(new Mesh(gameObjects.get(1), Mesh.MeshType.SPRITE, "test.png")); + gameObjects.get(1).setName("Player"); } @Override public void update(float dt) { + if(isCreateObject) + { + createGameObject(); + isCreateObject = false; + } if (Input.GetKey(GLFW_KEY_W)) { - float y = gameObjects.get("sprite").transform.position.y; - gameObjects.get("sprite").transform.setPosition(gameObjects.get("sprite").transform.position.x, y - 1, 0); + float y = gameObjects.get(1).transform.position.y; + gameObjects.get(1).transform.setPosition(gameObjects.get(1).transform.position.x, y - 1, 0); } if (Input.GetKey(GLFW_KEY_A)) { - float x = gameObjects.get("sprite").transform.position.x; - gameObjects.get("sprite").transform.setPosition(x - 1, gameObjects.get("sprite").transform.position.y, 0); + float x = gameObjects.get(1).transform.position.x; + gameObjects.get(1).transform.setPosition(x - 1, gameObjects.get(1).transform.position.y, 0); } if (Input.GetKey(GLFW_KEY_S)) { - float y = gameObjects.get("sprite").transform.position.y; - gameObjects.get("sprite").transform.setPosition(gameObjects.get("sprite").transform.position.x, y + 1, 0); + float y = gameObjects.get(1).transform.position.y; + gameObjects.get(1).transform.setPosition(gameObjects.get(1).transform.position.x, y + 1, 0); } if (Input.GetKey(GLFW_KEY_D)) { - float x = gameObjects.get("sprite").transform.position.x; - gameObjects.get("sprite").transform.setPosition(x + 1, gameObjects.get("sprite").transform.position.y, 0); + float x = gameObjects.get(1).transform.position.x; + gameObjects.get(1).transform.setPosition(x + 1, gameObjects.get(1).transform.position.y, 0); } - if (Input.GetKey(GLFW_KEY_LEFT)) { - float rotation = gameObjects.get("sprite").transform.rotation.z; - gameObjects.get("sprite").transform.setRotation(0, 0, rotation - 1); // 左回転 + float rotation = gameObjects.get(1).transform.rotation.z; + gameObjects.get(1).transform.setRotation(0, 0, rotation - 1); // 左回転 } if (Input.GetKey(GLFW_KEY_RIGHT)) { - float rotation = gameObjects.get("sprite").transform.rotation.z; - gameObjects.get("sprite").transform.setRotation(0, 0, rotation + 1); // 右回転 + float rotation = gameObjects.get(1).transform.rotation.z; + gameObjects.get(1).transform.setRotation(0, 0, rotation + 1); // 右回転 } + } + public void CreateNewObject(){ + if(isCreateObject) return; + isCreateObject = true; + } + + public void AddComponent(){ + if(isAddComponent) return; + isAddComponent = true; + } + + private void createGameObject(){ + int newId = gameObjects.size(); + gameObjects.put(newId, new GameObject()); + gameObjects.get(newId).addComponent(new Mesh(gameObjects.get(newId), Mesh.MeshType.SPRITE, "test.png")); + gameObjects.get(newId).setName("Player" + newId); + } + + private void addComponent(){ + gameObjects.get(0).addComponent(new ColorController()); + } + + } diff --git a/GameEngine/src/main/java/gameEngine/scenes/Scene.java b/GameEngine/src/main/java/gameEngine/scenes/Scene.java index d91a8c0..bad8a66 100644 --- a/GameEngine/src/main/java/gameEngine/scenes/Scene.java +++ b/GameEngine/src/main/java/gameEngine/scenes/Scene.java @@ -6,10 +6,13 @@ public abstract class Scene { - public HashMap gameObjects = new HashMap<>(); + public HashMap gameObjects = new HashMap<>(); public Scene(){ } public abstract void update(float dt); + + public void CreateNewObject() { + } } diff --git a/GameEngine/src/main/java/gameEngine/views/Texture.java b/GameEngine/src/main/java/gameEngine/views/Texture.java new file mode 100644 index 0000000..b7e5433 --- /dev/null +++ b/GameEngine/src/main/java/gameEngine/views/Texture.java @@ -0,0 +1,94 @@ +package gameEngine.views; + +import org.lwjgl.BufferUtils; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; + +import static org.lwjgl.opengl.GL11.*; + +public class Texture { + + /* + 指定された画像ファイルを読み込み、そのピクセルデータをOpenGLにアップロードして + テクスチャとして利用できるようにする + */ + + private int id; //OpenGLのテクスチャID + private int width; // 読み込んだ画像の幅 + private int height; // 読み込んだ画像の高さ + + public Texture(String path) { + BufferedImage bi; + try { + //ImageIO.read(new File(path)): 画像ファイルを読み込み、BufferedImageオブジェクトを作成 + //BufferedImageはJava標準ライブラリのクラス + bi = ImageIO.read(new File(path)); + width = bi.getWidth(); + height = bi.getHeight(); + + //画像のピクセルデータをRGB形式で取得 + //pixelsRawは整数配列で、各ピクセルの色データが格納される + int[] pixelsRaw = bi.getRGB(0, 0, width, height, null, 0, width); + + //BufferUtils.createByteBuffer(width * height * 4): OpenGLに送信するためのバッファ(ByteBuffer)を作成 + ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4); + + // 各ピクセルを取り出し、色成分(R, G, B, A)を抽出してByteBufferに格納 + // (pixel >> 16) & 0xFF: ピクセルデータの上位16ビットを右にシフトし、赤色成分を抽出。 + // 同様に緑(8ビット右シフト)、青(そのまま)、アルファ(24ビット右シフト)も抽出 + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int pixel = pixelsRaw[y * width + x]; + pixels.put((byte) ((pixel >> 16) & 0xFF)); // Red + pixels.put((byte) ((pixel >> 8) & 0xFF)); // Green + pixels.put((byte) (pixel & 0xFF)); // Blue + pixels.put((byte) ((pixel >> 24) & 0xFF)); // Alpha + } + } + // ByteBufferを読み込み可能な状態に + pixels.flip(); + + // 新しいテクスチャIDを生成 + id = glGenTextures(); + + // 生成したテクスチャIDを現在のテクスチャとしてバインド + // 以降のテクスチャ関連の操作はこのテクスチャに対して行われる + glBindTexture(GL_TEXTURE_2D, id); + + // テクスチャデータをOpenGLに送信 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + //テクスチャのフィルタリング方法を設定 + //ニアレストフィルタリング:拡大縮小時のぼやけがなくなる + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // テクスチャのバインディングを解除 + glBindTexture(GL_TEXTURE_2D, 0); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public int getId() { + return id; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void delete() { + //テクスチャを削除し、OpenGLからリソースを解放します。 + glDeleteTextures(id); + } +} \ No newline at end of file diff --git a/GameEngine/src/main/java/gameEngine/views/Window.java b/GameEngine/src/main/java/gameEngine/views/Window.java index beeff65..5ce4acb 100644 --- a/GameEngine/src/main/java/gameEngine/views/Window.java +++ b/GameEngine/src/main/java/gameEngine/views/Window.java @@ -1,4 +1,5 @@ package gameEngine.views; +import gameEngine.GameEditor; import gameEngine.Time; import gameEngine.entites.GameObject; import gameEngine.input.*; @@ -24,13 +25,13 @@ public int height; private String title; private long glfwWindow; - + private static GameEditor gameEditor; private Window() { this.width = 1200; this.height = 900; this.title = "HelloWorld"; - + gameEditor = new GameEditor(); } public static void changeScene(int newScene){ @@ -41,6 +42,7 @@ for (GameObject obj : currentScene.gameObjects.values()) { obj.initComponents(); } + gameEditor.updateListByScene(currentScene); break; case 1: currentScene = new GameScene(); @@ -48,6 +50,8 @@ for (GameObject obj : currentScene.gameObjects.values()) { obj.initComponents(); } + gameEditor.updateListByScene(currentScene); + break; default: assert false : "Unknown Scene [" + newScene + "]";