package gameEngine; import gameEngine.entites.Entity; import gameEngine.entites.GameObject; import gameEngine.entites.gameComponents.GameComponent; import gameEngine.entites.gameComponents.*; import gameEngine.scenes.*; import org.joml.Vector3f; import javax.swing.*; import java.awt.*; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.util.List; import java.util.Map; public class GameEditor extends JFrame { private JList<String> objectList; private DefaultListModel<String> listModel; private DefaultListModel<GameComponent> componentListModel; private JList<GameComponent> componentList; private JLabel entityLabel, nameLabel, posLabel, rotLabel, scaLabel; private JTextField posXField, posYField, posZField; private JTextField rotXField, rotYField, rotZField; private JTextField scaleXField, scaleYField, scaleZField; private JTextField nameField; private Scene gameScene; private Timer updateTimer; private JComboBox<String> componentDropdown; private String lastLoadedName; private Vector3f lastLoadedPos, lastLoadedRot, lastLoadedScale; public GameEditor() { setTitle("Game Object Editor"); setSize(500, 400); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // 閉じられないようにする setLayout(null); // レイアウトを絶対座標に設定 initializeUIComponents();// 各UI要素の初期化 initializeUpdateTimer(); // 定期的にリスト更新を行うタイマーを初期化 setVisible(true); // フレームを表示 } // UI要素を初期化し、配置関数を呼び出す private void initializeUIComponents() { listModel = new DefaultListModel<>(); objectList = new JList<>(listModel); JScrollPane scrollPane = new JScrollPane(objectList); objectList.setCellRenderer(createEntityRenderer()); componentListModel = new DefaultListModel<>(); componentList = new JList<>(componentListModel); JScrollPane componentScrollPane = new JScrollPane(componentList); componentList.setCellRenderer(createComponentRenderer()); // 各UIコンポーネントの作成と配置 entityLabel = new JLabel("Entity:"); nameField = new JTextField(20); nameLabel = new JLabel("Name:"); posLabel = new JLabel("Position:"); rotLabel = new JLabel("Rotation:"); scaLabel = new JLabel("Scale:"); posXField = new JTextField(5); posYField = new JTextField(5); posZField = new JTextField(5); rotXField = new JTextField(5); rotYField = new JTextField(5); rotZField = new JTextField(5); scaleXField = new JTextField(5); scaleYField = new JTextField(5); scaleZField = new JTextField(5); componentDropdown = new JComboBox<>(new String[]{"ColorController", "CopyEntity", "MoveImage", "Physics"}); addChangeListener(posXField, posYField, posZField, rotXField, rotYField, rotZField, scaleXField, scaleYField, scaleZField, nameField); JButton newGameObjectButton = new JButton("Add Entity"); newGameObjectButton.addActionListener(e -> createNewGameObject()); JButton addComponentButton = new JButton("+ Component"); addComponentButton.addActionListener(e -> addComponentToGameObject()); JButton removeComponentButton = new JButton("- Component"); removeComponentButton.addActionListener(e -> removeComponentFromGameObject()); int pos = 170; // 各要素の位置とサイズを設定 setComponentBounds(entityLabel, 10, 5, 100, 30); setComponentBounds(scrollPane, 10, 30, 150, 300); setComponentBounds(componentScrollPane, 350, 170, 130, 165); setComponentBounds(nameLabel, pos, 10, 100, 30); setComponentBounds(nameField, pos+50, 10, 170, 25); setComponentBounds(posLabel, pos, 50, 100, 30); setComponentBounds(posXField, pos + 50, 50, 50, 30); setComponentBounds(posYField, pos + 110, 50, 50, 30); setComponentBounds(posZField, pos + 170, 50, 50, 30); setComponentBounds(rotLabel, pos, 90, 100, 30); setComponentBounds(rotXField, pos + 50, 90, 50, 30); setComponentBounds(rotYField, pos + 110, 90, 50, 30); setComponentBounds(rotZField, pos + 170, 90, 50, 30); setComponentBounds(scaLabel, pos, 130, 100, 30); setComponentBounds(scaleXField, pos + 50, 130, 50, 30); setComponentBounds(scaleYField, pos + 110, 130, 50, 30); setComponentBounds(scaleZField, pos + 170, 130, 50, 30); setComponentBounds(newGameObjectButton, 200, 170, 110, 20); setComponentBounds(addComponentButton, 200, 260, 130, 20); setComponentBounds(removeComponentButton, 200, 290, 130, 20); setComponentBounds(componentDropdown, 200, 225, 130, 20); // ドロップダウンの位置とサイズを設定 objectList.addListSelectionListener(e -> { if (!e.getValueIsAdjusting()) { // ユーザーが調整中でない場合のみ loadSelectedGameObject(); // オブジェクトのプロパティをロード } }); } private void addChangeListener(JTextField... fields) { for (JTextField field : fields) { field.addActionListener(e -> applyGameObjectChanges()); field.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { updateTimer.stop(); } @Override public void focusLost(FocusEvent e) { applyGameObjectChanges(); updateTimer.start(); } }); } } private void initializeUpdateTimer() { updateTimer = new Timer(750, e -> { String selectedObject = objectList.getSelectedValue(); GameComponent selectedComponent = componentList.getSelectedValue(); updateGameObjectList(gameScene); if (selectedObject != null) { objectList.setSelectedValue(selectedObject, true); Entity selectedEntity = gameScene.getEntity(selectedObject); if (selectedEntity instanceof GameObject) { updateComponentList((GameObject) selectedEntity); } } if (selectedComponent != null) { componentList.setSelectedValue(selectedComponent, true); } }); updateTimer.start(); } private ListCellRenderer<String> createEntityRenderer() { return (list, value, index, isSelected, cellHasFocus) -> { JLabel label = new JLabel(); Entity entity = gameScene.getEntity(value); label.setText(entity.getName()); label.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground()); label.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground()); label.setOpaque(true); return label; }; } private ListCellRenderer<GameComponent> createComponentRenderer() { return (list, value, index, isSelected, cellHasFocus) -> { JLabel label = new JLabel(value.getClass().getSimpleName()); label.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground()); label.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground()); label.setOpaque(true); return label; }; } private void setComponentBounds(Component component, int x, int y, int width, int height) { component.setBounds(x, y, width, height); add(component); //フレームに追加 } private void createNewGameObject() { gameScene.addNewObject(); // 新しいGameObjectを作成 updateGameObjectList(gameScene); // オブジェクトリストの更新 objectList.setSelectedIndex(listModel.getSize() - 1); // 新規作成したオブジェクトを選択 applyGameObjectChanges(); // 作成直後に即座にプロパティを反映させる } private void addComponentToGameObject() { // 現在の選択状態を保存 String selectedObject = objectList.getSelectedValue(); GameComponent selectedComponent = componentList.getSelectedValue(); // コンポーネントの追加処理 if (selectedObject != null) { Entity selectedEntity = gameScene.getEntity(selectedObject); if (selectedEntity instanceof GameObject) { GameObject gameObject = (GameObject) selectedEntity; String component = (String) componentDropdown.getSelectedItem(); switch (component) { case "ColorController": gameScene.addComponentToGameObject(gameObject, new ColorController()); break; case "CopyEntity": gameScene.addComponentToGameObject(gameObject, new CopyEntity(gameObject)); break; case "MoveImage": gameScene.addComponentToGameObject(gameObject, new MoveImage(gameObject)); break; case "Physics": gameScene.addComponentToGameObject(gameObject, new Physics(gameObject)); break; default: JOptionPane.showMessageDialog(this, "Unknown Component Selected"); break; } // リストの更新 updateComponentList(gameObject); updateGameObjectList(gameScene); // オブジェクトリストの更新 //ダイアログ JOptionPane.showMessageDialog(this, "Component Added to " + selectedEntity.name); } } // 選択状態を復元 if (selectedObject != null) { objectList.setSelectedValue(selectedObject, true); } if (selectedComponent != null) { componentList.setSelectedValue(selectedComponent, true); } } private void removeComponentFromGameObject() { String selectedIdStr = objectList.getSelectedValue(); if (selectedIdStr != null) { Entity selectedEntity = gameScene.getEntity(selectedIdStr); if (selectedEntity instanceof GameObject) { GameObject gameObject = (GameObject) selectedEntity; GameComponent selectedComponent = componentList.getSelectedValue(); // GameComponentとして取得 if (selectedComponent != null) { gameScene.removeComponentFromGameObject(gameObject, selectedComponent); updateComponentList(gameObject); // コンポーネントリストの更新 JOptionPane.showMessageDialog(this, "Component Removed from " + selectedEntity.name); } } } } private void updateGameObjectList(Scene gameScene) { listModel.clear(); for (Map.Entry<String, Entity> entry : gameScene.entities.entrySet()) { Entity entity = entry.getValue(); listModel.addElement(entity.getId()); } objectList.repaint(); } private void updateComponentList(GameObject gameObject) { componentListModel.clear(); // リストをクリア List<GameComponent> components = gameObject.gameComponents; for (GameComponent component : components) { componentListModel.addElement(component); // コンポーネントを追加 } componentList.repaint(); } private void loadSelectedGameObject() { String selectedIdStr = objectList.getSelectedValue(); if (selectedIdStr != null) { Entity selectedEntity = gameScene.getEntity(selectedIdStr); if (selectedEntity != null) { loadObjectProperties(selectedEntity); if (selectedEntity instanceof GameObject) { updateComponentList((GameObject) selectedEntity); } } } } private void applyGameObjectChanges() { String selectedIdStr = objectList.getSelectedValue(); if (selectedIdStr != null) { Entity selectedEntity = gameScene.getEntity(selectedIdStr); if (selectedEntity != null) { try { String newName = nameField.getText(); if (!newName.equals(lastLoadedName)) { selectedEntity.setName(newName); } Vector3f newPos = new Vector3f( Float.parseFloat(posXField.getText()), Float.parseFloat(posYField.getText()), Float.parseFloat(posZField.getText()) ); if (!newPos.equals(lastLoadedPos)) { selectedEntity.transform.setPosition(newPos); } Vector3f newRot = new Vector3f( Float.parseFloat(rotXField.getText()), Float.parseFloat(rotYField.getText()), Float.parseFloat(rotZField.getText()) ); if (!newRot.equals(lastLoadedRot)) { selectedEntity.transform.setRotation(newRot); } Vector3f newScale = new Vector3f( Float.parseFloat(scaleXField.getText()), Float.parseFloat(scaleYField.getText()), Float.parseFloat(scaleZField.getText()) ); if (!newScale.equals(lastLoadedScale)) { selectedEntity.transform.setScale(newScale); } updateGameObjectList(gameScene); } catch (NumberFormatException e) { JOptionPane.showMessageDialog(this, "Invalid input. Please enter valid numbers.", "Error", JOptionPane.ERROR_MESSAGE); } } } } public void updateListByScene(Scene gameScene) { this.gameScene = gameScene; updateGameObjectList(gameScene); componentListModel.clear(); componentList.repaint(); } //entityの情報を取得 private void loadObjectProperties(Entity entity) { nameField.setText(entity.getName()); Vector3f pos = entity.transform.position; posXField.setText(String.valueOf(pos.x)); posYField.setText(String.valueOf(pos.y)); posZField.setText(String.valueOf(pos.z)); Vector3f rot = entity.transform.rotation; rotXField.setText(String.valueOf(rot.x)); rotYField.setText(String.valueOf(rot.y)); rotZField.setText(String.valueOf(rot.z)); Vector3f scale = entity.transform.scale; scaleXField.setText(String.valueOf(scale.x)); scaleYField.setText(String.valueOf(scale.y)); scaleZField.setText(String.valueOf(scale.z)); lastLoadedName = entity.getName(); lastLoadedPos = pos; lastLoadedRot = rot; lastLoadedScale = scale; } }