diff --git a/README.md b/README.md
index 09ec93a..d687ac2 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,31 @@ This game engine was developed to create and play role-playing games with jump-n
The engine is currently still at an early stage, which means that essential functions may still be missing.
A rough overview of the available features can be found in the table below.
-To download and try out the editor/engine, you can download it from this website: [Download](https://sunnix.de/downloads).
+To download and try out the editor/engine, you can download it from this [repo](https://github.com/Sunnnix/Sunnixs_RPG_Engine/releases/tag/V0.6) or from this website: [Download](https://sunnix.de/downloads).
> [!NOTE]
> The engine does not contain any graphics, music, or sounds; you have to add them yourself!
## Patch Notes
+
+ V0.6
+
+- Objects with events and components
+ - Events
+ - Move
+ - Wait
+ - Message
+ - Play Sound
+ - Components
+ - Render
+- Event controlled textbox
+- Object animation V1
+- Audio System for playing Sounds
+- Object states
+
+
+
V0.5
@@ -62,23 +80,23 @@ To download and try out the editor/engine, you can download it from this website
## Supported Features
-| Description | Since |
-|---------------------------------|---------|
-| Set BGM from Map | 0.4 |
-| Editor multi-language support | 0.4 |
-| Load custom tilesets | 0.3 |
-| Create 3D maps with walls | 0.2 |
-| Start the game from the editor | 0.1 |
+| Description | Since |
+|------------------------------------------|-------|
+| Audio System V2 (playable Sounds) | 0.6 |
+| Sprite animation | 0.6 |
+| Dynamic Object properties via Components | 0.6 |
+| Object control via Events | 0.6 |
+| Objects | 0.6 |
+| Audio System V1 (only BGM) | 0.4 |
+| Editor multi-language support | 0.4 |
+| Load custom tilesets | 0.3 |
+| Create 3D maps with walls | 0.2 |
+| Start the game from the editor | 0.1 |
## Upcoming Features
| Description | Planned | Progress | Priority |
|-------------------------------------------------------|---------|----------|----------|
-| Objects with events and components | 0.6 | 90% | High |
-| Event controlled textbox | 0.6 | 100% | High |
-| Object animation V1 | 0.6 | 100% | High |
-| Audio System for playing Sounds | 0.6 | 100% | High |
-| Object states | 0.6 | 100% | High |
| Tile animation | 0.7 | 0% | Medium |
| Physics System | 0.7 | 0% | High |
| Map Transition System / Teleporter objects and events | 0.7 | 0% | High |
diff --git a/editor/res/de/sunnix/srpge/editor/lang/en.lang b/editor/res/de/sunnix/srpge/editor/lang/en.lang
index 756ab8b..cf30b3a 100644
--- a/editor/res/de/sunnix/srpge/editor/lang/en.lang
+++ b/editor/res/de/sunnix/srpge/editor/lang/en.lang
@@ -254,6 +254,8 @@ view.dialog_resources.audio.default_value=Default Volume:
# States View
view.dialog_resources.variables.states.id=ID
view.dialog_resources.variables.states.prio=Priority
+view.dialog_resources.variables.states.add_state=Add State
+view.dialog_resources.variables.states.remove_state=Remove State
# Dialog Language
dialog.language.reload_editor.text=The new Language Pack has been loaded and is now being used. However, in order to update all texts, you need to restart the editor.
@@ -268,6 +270,9 @@ dialog.language.no_lang_selected=No Language Pack selected!
dialog.language.lang_not_found=Language Pack not found!
dialog.language.en_fallback=Use English if translation is missing
+# Dialog Player
+dialog.player.sprite.title=Edit player sprites
+
# Dialog Objects
dialog_object.title=Edit Object
dialog_object.add_event=Add Event
@@ -275,6 +280,20 @@ dialog_object.edit_event=Edit Event
dialog_object.remove_event=Remove Event
dialog_object.remove_component.text=Are you sure you want to delete this component?\nAll settings for this component will be lost
dialog_object.remove_component.title=Delete component
+dialog_object.add_component=+ Add Component
+
+# Components
+component.render =Renderer
+component.render.set_sprite=Set Sprite
+component.render.set_state_sprite=Set State Sprites
+component.render.state_dialog=State Sprite Editor
+component.render.state_dialog.add=Add State
+component.render.state_dialog.remove=Remove State
+component.render.state_dialog.no_state=No state availible!
+component.render.state_dialog.title=States
+component.render.state_dialog.select=Select state
+component.render.state_dialog.select_sprite.title=Select Sprite
+component.render.state_dialog.select_sprite.text=Select Sprite for State:
# Events
event_dialog.edit=Edit %s
diff --git a/editor/src/de/sunnix/srpge/editor/window/Window.java b/editor/src/de/sunnix/srpge/editor/window/Window.java
index 84fb47a..914af86 100644
--- a/editor/src/de/sunnix/srpge/editor/window/Window.java
+++ b/editor/src/de/sunnix/srpge/editor/window/Window.java
@@ -87,6 +87,7 @@ public class Window extends JFrame {
private boolean showGrid = true;
@Getter
+ @Setter
private GameObject player;
public Window(){
diff --git a/editor/src/de/sunnix/srpge/editor/window/menubar/PlayerSpriteManager.java b/editor/src/de/sunnix/srpge/editor/window/menubar/PlayerSpriteManager.java
index 56a68b9..87d1b97 100644
--- a/editor/src/de/sunnix/srpge/editor/window/menubar/PlayerSpriteManager.java
+++ b/editor/src/de/sunnix/srpge/editor/window/menubar/PlayerSpriteManager.java
@@ -10,20 +10,19 @@
import java.awt.event.WindowListener;
import static de.sunnix.srpge.editor.lang.Language.getString;
-import static de.sunnix.srpge.editor.lang.Language.removeLanguagePack;
public class PlayerSpriteManager extends JDialog {
private boolean loopShouldStop;
public PlayerSpriteManager(Window window){
- super(window, "Edit player sprites", true);
- var mainPanel = new JPanel(new BorderLayout(0, 5));
+ super(window, getString("dialog.player.sprite.title"), true);
+ var mainPanel = new JPanel(new BorderLayout(0, 10));
mainPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
setContentPane(mainPanel);
var player = window.getPlayer();
- var component = player.getComponent(RenderComponent.class);
+ var component = player.getComponent(RenderComponent.class).clone();
var centerPanel = new JPanel();
centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
centerPanel.setPreferredSize(new Dimension(180, 250));
@@ -33,7 +32,8 @@ public PlayerSpriteManager(Window window){
var loop = new Thread(() -> {
while(!loopShouldStop){
try {
- loopFunction.run();
+ if(loopFunction != null)
+ loopFunction.run();
Thread.sleep(16, 666666);
} catch (InterruptedException e) {
throw new RuntimeException(e);
@@ -43,6 +43,24 @@ public PlayerSpriteManager(Window window){
loop.setDaemon(true);
loop.start();
+
+ var buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
+
+ var btnApply = new JButton(getString("button.apply"));
+ btnApply.addActionListener(l -> {
+ player.getComponents().removeIf(c -> c.ID.equals(component.ID));
+ player.getComponents().add(component);
+ window.setProjectChanged();
+ dispose();
+ });
+ var btnCancel = new JButton(getString("button.cancel"));
+ btnCancel.addActionListener(l -> dispose());
+
+ buttonsPanel.add(btnApply);
+ buttonsPanel.add(btnCancel);
+
+ mainPanel.add(buttonsPanel, BorderLayout.SOUTH);
+
addWindowListener(creatwWindowListener());
setResizable(false);
diff --git a/editor/src/de/sunnix/srpge/editor/window/menubar/resource/SpriteView.java b/editor/src/de/sunnix/srpge/editor/window/menubar/resource/SpriteView.java
index d9ad919..cbf921e 100644
--- a/editor/src/de/sunnix/srpge/editor/window/menubar/resource/SpriteView.java
+++ b/editor/src/de/sunnix/srpge/editor/window/menubar/resource/SpriteView.java
@@ -84,7 +84,7 @@ private JPanel genTexturePanel(){
setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
addMouseListener(new MouseAdapter() {
@Override
- public void mouseClicked(MouseEvent e) {
+ public void mousePressed(MouseEvent e) {
var sprite = getCurrentSprite();
if(sprite == null)
return;
@@ -115,6 +115,7 @@ public void mouseClicked(MouseEvent e) {
mY /= spriteHeight;
sprite.getPattern(direction.getSelectedIndex()).add(mX + mY * texture.getWidth());
+ window.setProjectChanged();
direction.setSelectedIndex(direction.getSelectedIndex()); // reload list
}
});
@@ -185,6 +186,7 @@ private JPanel genProperties(){
var split = name.split("/");
c.setSelectedItem(split[0]);
});
+ addAL(imageCategory, l -> window.setProjectChanged());
pPanel.add(imageCategory, gbc);
gbc.gridy++;
imageResource = createPropertieComp(boxes[1], (c, s) -> {
@@ -238,7 +240,10 @@ private JPanel genProperties(){
var sprite = getCurrentSprite();
if (sprite == null)
return;
- sprite.setDirectionType((Sprite.DirectionType) directionType.getSelectedItem());
+ if(!sprite.getDirectionType().equals(directionType.getSelectedItem())) {
+ sprite.setDirectionType((Sprite.DirectionType) directionType.getSelectedItem());
+ window.setProjectChanged();
+ }
reloadSprite();
});
animPanel.add(directionType, gbc2);
@@ -256,7 +261,10 @@ private JPanel genProperties(){
var sprite = getCurrentSprite();
if (sprite == null)
return;
- sprite.setAnimationType((Sprite.AnimationType) animType.getSelectedItem());
+ if(!sprite.getAnimationType().equals(animType.getSelectedItem())) {
+ sprite.setAnimationType((Sprite.AnimationType) animType.getSelectedItem());
+ window.setProjectChanged();
+ }
reloadSprite();
});
animPanel.add(animType, gbc2);
@@ -296,6 +304,7 @@ public void keyPressed(KeyEvent e) {
return;
sprite.getPattern(direction.getSelectedIndex()).remove(index);
spriteListModel.remove(index);
+ window.setProjectChanged();
spriteList.setSelectedIndex(index - (spriteListModel.getSize() > index ? 0 : 1));
}
case KeyEvent.VK_UP -> {
@@ -309,6 +318,7 @@ public void keyPressed(KeyEvent e) {
pattern.add(index - 1, tex);
spriteListModel.remove(index);
spriteListModel.add(index - 1, tex);
+ window.setProjectChanged();
spriteList.setSelectedIndex(index - 1);
e.consume();
}
@@ -323,6 +333,7 @@ public void keyPressed(KeyEvent e) {
pattern.add(index + 1, tex);
spriteListModel.remove(index);
spriteListModel.add(index + 1, tex);
+ window.setProjectChanged();
spriteList.setSelectedIndex(index + 1);
e.consume();
}
@@ -354,8 +365,6 @@ public void keyPressed(KeyEvent e) {
pPanel.add(showIndex, gbc);
gbc.gridy++;
-// pPanel.add(new JLabel(getString("view.dialog_resources.sprite.animation_delay")), gbc);
-// gbc.gridy++;
animSpeed = createPropertieComp(new NumberPicker(getString("view.dialog_resources.sprite.animation_speed"), 1, 0, 1, Integer.MAX_VALUE), (c, s) -> {
if(s == null) {
animSpeed.setValue(1, true);
@@ -368,13 +377,14 @@ public void keyPressed(KeyEvent e) {
if(sprite == null)
return;
sprite.setAnimationSpeed(animSpeed.getValue());
+ window.setProjectChanged();
});
pPanel.add(animSpeed, gbc);
gbc.gridy++;
- var mPanel = new JPanel(new BorderLayout());
+ var mPanel = new JPanel(new FlowLayout());
mPanel.setPreferredSize(new Dimension(200, 0));
- mPanel.add(pPanel, BorderLayout.NORTH);
+ mPanel.add(pPanel);
var scroll = new JScrollPane(mPanel);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
diff --git a/editor/src/de/sunnix/srpge/editor/window/menubar/resource/StatesView.java b/editor/src/de/sunnix/srpge/editor/window/menubar/resource/StatesView.java
index a4d7903..87b3537 100644
--- a/editor/src/de/sunnix/srpge/editor/window/menubar/resource/StatesView.java
+++ b/editor/src/de/sunnix/srpge/editor/window/menubar/resource/StatesView.java
@@ -19,7 +19,10 @@
public class StatesView extends JPanel {
+ private Window window;
+
public StatesView(Window window, JPanel parent) {
+ this.window = window;
setLayout(new BorderLayout());
add(new JScrollPane(createTable()), BorderLayout.CENTER);
@@ -63,14 +66,18 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
// sorter.toggleSortOrder(1);
var popupMenu = new JPopupMenu();
- var addItem = new JMenuItem("Add State");
- var removeItem = new JMenuItem("Remove State");
+ var addItem = new JMenuItem(getString("view.dialog_resources.variables.states.add_state"));
+ var removeItem = new JMenuItem(getString("view.dialog_resources.variables.states.remove_state"));
- addItem.addActionListener(e -> ((TableModel) table.getModel()).addNewState());
+ addItem.addActionListener(e -> {
+ ((TableModel) table.getModel()).addNewState();
+ window.setProjectChanged();
+ });
removeItem.addActionListener(e -> {
int row = table.getSelectedRow();
if (row != -1) {
((TableModel) table.getModel()).removeState(row);
+ window.setProjectChanged();
}
});
@@ -148,9 +155,9 @@ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
var id = (String) aValue;
if(id.equals(state.id()) || id.isBlank() || states.stream().anyMatch(x -> id.equals(x.id())))
yield state;
- yield States.changeStateId(state, id);
+ yield States.changeStateId(window, state, id);
}
- case 1 -> States.changeStatePrio(state, Integer.parseInt((String) aValue));
+ case 1 -> States.changeStatePrio(window, state, Integer.parseInt((String) aValue));
default -> state;
});
fireTableDataChanged();
@@ -167,7 +174,7 @@ public void addNewState() {
public void removeState(int row){
var value = (String) getValueAt(row, 0);
- states.remove(States.removeState(value));
+ states.remove(States.removeState(window, value));
fireTableDataChanged();
}
diff --git a/editor/src/de/sunnix/srpge/editor/window/object/ObjectEditDialog.java b/editor/src/de/sunnix/srpge/editor/window/object/ObjectEditDialog.java
index 9b45894..7142697 100644
--- a/editor/src/de/sunnix/srpge/editor/window/object/ObjectEditDialog.java
+++ b/editor/src/de/sunnix/srpge/editor/window/object/ObjectEditDialog.java
@@ -133,7 +133,7 @@ private JComponent createComponentPanel(){
componentList = new ArrayList<>(object.getComponents().stream().map(Component::clone).toList());
componentsView = panel;
- var addbtn = new JButton("+ Add Component");
+ var addbtn = new JButton(getString("dialog_object.add_component"));
addbtn.setMaximumSize(new Dimension(Integer.MAX_VALUE, addbtn.getMinimumSize().height));
addbtn.addActionListener(a -> {
var component = ComponentCreateDialog.show(this, object);
diff --git a/editor/src/de/sunnix/srpge/editor/window/object/States.java b/editor/src/de/sunnix/srpge/editor/window/object/States.java
index a972960..8222096 100644
--- a/editor/src/de/sunnix/srpge/editor/window/object/States.java
+++ b/editor/src/de/sunnix/srpge/editor/window/object/States.java
@@ -1,6 +1,7 @@
package de.sunnix.srpge.editor.window.object;
import de.sunnix.sdso.DataSaveObject;
+import de.sunnix.srpge.editor.window.Window;
import de.sunnix.srpge.engine.ecs.State;
import java.util.ArrayList;
@@ -53,17 +54,26 @@ public static DataSaveObject save(DataSaveObject dso){
return dso;
}
- public static State changeStateId(State state, String newID) {
+ public static State changeStateId(Window window, State state, String newID) {
newID = newID.toLowerCase();
+ if(state.id().equals(newID))
+ return state;
states.remove(state.id());
var newState = new State(newID, state.priority());
states.put(newID, newState);
+ if(window != null)
+ window.setProjectChanged();
return newState;
}
- public static State changeStatePrio(State state, int newPrio) {
+ public static State changeStatePrio(Window window, State state, int newPrio) {
+ var curState = states.get(state.id());
+ if(curState != null && curState.priority() == newPrio)
+ return state;
var newState = new State(state.id(), newPrio);
states.put(state.id(), newState);
+ if(window != null)
+ window.setProjectChanged();
return newState;
}
@@ -72,10 +82,12 @@ public static boolean hasStateID(String id) {
return states.containsKey(id);
}
- public static State removeState(String id) {
+ public static State removeState(Window window, String id) {
id = id.toLowerCase();
if(!isRemovable(id))
throw new RuntimeException("State " + id + " can't be removed!");
+ if(window != null)
+ window.setProjectChanged();
return states.remove(id);
}
}
diff --git a/editor/src/de/sunnix/srpge/editor/window/object/components/RenderComponent.java b/editor/src/de/sunnix/srpge/editor/window/object/components/RenderComponent.java
index 2e31ed1..7382692 100644
--- a/editor/src/de/sunnix/srpge/editor/window/object/components/RenderComponent.java
+++ b/editor/src/de/sunnix/srpge/editor/window/object/components/RenderComponent.java
@@ -31,7 +31,7 @@ public RenderComponent() {
@Override
public String genName() {
- return "Renderer";
+ return getString("component.render");
}
@Override
@@ -103,7 +103,7 @@ public void paint(Graphics g) {
}, 250);
setSpriteBtn.addActionListener(a -> {
- var newSprite = window.getSingleton(Resources.class).sprites.showSelectDialogSinglePath(parent, "Select sprite", null, "Sprite", defaultSprite);
+ var newSprite = window.getSingleton(Resources.class).sprites.showSelectDialogSinglePath(parent, getString("component.render.set_sprite"), null, getString("name.sprite"), defaultSprite);
if(newSprite == null)
return;
defaultSprite = newSprite;
@@ -111,7 +111,7 @@ public void paint(Graphics g) {
parent.repaint();
});
- var setStateSpritesBtn = addView(parent, new JButton("Set State Sprites"));
+ var setStateSpritesBtn = addView(parent, new JButton(getString("component.render.set_state_sprite")));
setStateSpritesBtn.addActionListener(l -> new StateSpriteEditDialog(window, parent, stateSprites));
return () -> {
@@ -144,7 +144,7 @@ private static class StateSpriteEditDialog extends JDialog {
private final Map stateSprites;
public StateSpriteEditDialog(Window window, JPanel parent, HashMap stateSprites){
- super(DialogUtils.getWindowForComponent(parent), "State Sprite Editor", ModalityType.APPLICATION_MODAL);
+ super(DialogUtils.getWindowForComponent(parent), getString("component.render.state_dialog"), ModalityType.APPLICATION_MODAL);
this.window = window;
this.parent = parent;
var content = new JPanel(new BorderLayout(5, 5));
@@ -206,17 +206,17 @@ else if(index % 2 == 0) {
private MouseAdapter genMouseListener(DefaultListModel> model, JList> list){
var popup = new JPopupMenu();
- var addMenu = new JMenuItem("Add State");
- var removeMenu = new JMenuItem("Remove State");
+ var addMenu = new JMenuItem(getString("component.render.state_dialog.add"));
+ var removeMenu = new JMenuItem(getString("component.render.state_dialog.remove"));
addMenu.addActionListener(a -> {
var states = States.getStates().stream().filter(x -> !stateSprites.containsKey(x.id())).toList();
if(states.isEmpty()) {
- JOptionPane.showMessageDialog(parent, "No state availible!", "States", JOptionPane.ERROR_MESSAGE);
+ JOptionPane.showMessageDialog(parent, getString("component.render.state_dialog.no_state"), getString("component.render.state_dialog.title"), JOptionPane.ERROR_MESSAGE);
return;
}
var statestrings = states.stream().map(x -> String.format("(%s) %s", x.priority(), x.id())).toArray(String[]::new);
- var selection = (String) JOptionPane.showInputDialog(parent, "Select state", "States", JOptionPane.PLAIN_MESSAGE, null, statestrings, statestrings[0]);
+ var selection = (String) JOptionPane.showInputDialog(parent, getString("component.render.state_dialog.select"), getString("component.render.state_dialog.title"), JOptionPane.PLAIN_MESSAGE, null, statestrings, statestrings[0]);
if(selection == null)
return;
var state = states.get(Arrays.stream(statestrings).toList().indexOf(selection));
@@ -246,9 +246,9 @@ public void mousePressed(MouseEvent e) {
var selection = window.getSingleton(Resources.class).sprites
.showSelectDialog(
StateSpriteEditDialog.this.rootPane,
- "Select Sprite",
- "Select Sprite for State:",
- "Sprite",
+ getString("component.render.state_dialog.select_sprite.title"),
+ getString("component.render.state_dialog.select_sprite.text"),
+ getString("name.sprite"),
stateSprites.get(list.getSelectedValue().getValue()
)
);
@@ -290,4 +290,12 @@ private JPanel createButtons(HashMap originalMap) {
}
}
+
+ @Override
+ public Component clone() {
+ var comp = (RenderComponent) super.clone();
+ comp.stateSprites = new HashMap<>(comp.stateSprites);
+ return comp;
+ }
+
}