Newer
Older
AlgebraicDataflowArchitectureModel / GameEngine / src / main / java / gameEngine / GameEditor.java
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"});

        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;
                    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;
    }

}