3import java.awt.AlphaComposite;
5import java.awt.Dimension;
6import java.awt.Graphics;
7import java.awt.Graphics2D;
8import java.awt.RenderingHints;
9import java.awt.event.KeyEvent;
10import java.awt.event.KeyListener;
11import java.awt.event.MouseEvent;
12import java.awt.event.MouseListener;
13import java.awt.event.MouseMotionListener;
14import java.awt.image.BufferedImage;
15import java.util.ArrayList;
17import java.util.concurrent.CopyOnWriteArrayList;
18import javax.swing.JFrame;
19import javax.swing.JPanel;
20import javax.swing.JToolBar;
21import javax.swing.JButton;
22import javax.swing.SwingUtilities;
23import javax.swing.Timer;
24import java.awt.BorderLayout;
26public class Stage extends JPanel implements KeyListener, MouseListener, MouseMotionListener {
32 private List<Sprite>
sprites =
new CopyOnWriteArrayList<>();
33 private List<Costume>
backdrops =
new ArrayList<>();
46 private final boolean[]
keysDown =
new boolean[65536];
49 private java.util.concurrent.CountDownLatch
frameLatch =
new java.util.concurrent.CountDownLatch(1);
52 private java.util.Map<String, List<Runnable>>
broadcastListeners =
new java.util.concurrent.ConcurrentHashMap<>();
53 private java.util.Map<Integer, List<Runnable>>
keyListeners =
new java.util.concurrent.ConcurrentHashMap<>();
54 private List<java.util.function.BiConsumer<Double, Double>>
scaleListeners =
new java.util.concurrent.CopyOnWriteArrayList<>();
63 this.setPreferredSize(
new Dimension(480, 360));
64 this.setBackground(Color.WHITE);
65 this.setFocusable(
true);
66 this.addKeyListener(
this);
67 this.addMouseListener(
this);
68 this.addMouseMotionListener(
this);
73 java.util.concurrent.CountDownLatch oldLatch =
frameLatch;
74 frameLatch =
new java.util.concurrent.CountDownLatch(1);
98 if (listeners !=
null) {
99 for (Runnable r : listeners) {
106 broadcastListeners.computeIfAbsent(message, k ->
new CopyOnWriteArrayList<>()).add(action);
110 keyListeners.computeIfAbsent(keyCode, k ->
new java.util.concurrent.CopyOnWriteArrayList<>()).add(action);
118 switch(keyName.toLowerCase()) {
121 case "down arrow":
return isKeyPressed(KeyEvent.VK_DOWN);
122 case "right arrow":
return isKeyPressed(KeyEvent.VK_RIGHT);
123 case "left arrow":
return isKeyPressed(KeyEvent.VK_LEFT);
125 for(
boolean b :
keysDown)
if(b)
return true;
128 if(keyName.length() == 1) {
129 char c = keyName.toUpperCase().charAt(0);
137 try {
frameLatch.await(); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
170 super.paintComponent(g);
171 Graphics2D g2d = (Graphics2D) g;
172 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
176 g2d.drawImage(bg, 0, 0, getWidth(), getHeight(),
null);
186 g2d.setColor(
new Color(200, 200, 200, 200));
188 for (java.util.Map.Entry<String, Object> entry :
stageObject.variables.entrySet()) {
189 String text = entry.getKey() +
": " + entry.getValue();
190 g2d.fillRoundRect(10, varY - 15, 120, 20, 5, 5);
191 g2d.setColor(Color.BLACK);
192 g2d.drawString(text, 15, varY);
193 g2d.setColor(
new Color(200, 200, 200, 200));
199 for (
int i = 0; i <
backdrops.size(); i++) {
200 if (
backdrops.get(i).getName().equals(name)) {
222 return (keyCode >= 0 && keyCode <
keysDown.length) ?
keysDown[keyCode] :
false;
231 this.setPreferredSize(
new Dimension(480 * scale, 360 * scale));
232 SwingUtilities.invokeLater(() -> {
236 this.requestFocusInWindow();
238 for (java.util.function.BiConsumer<Double, Double> listener :
scaleListeners) {
248 int code = e.getKeyCode();
251 if (listeners !=
null)
for (Runnable r : listeners)
stageObject.startScript(r);
255 for (
int i =
sprites.size() - 1; i >= 0; i--) {
270 public static void run(Runnable setup) {
274 public static void run(
Stage stage, Runnable setup) {
276 SwingUtilities.invokeLater(() -> {
277 JFrame
frame =
new JFrame(
"JScratch Stage");
279 frame.setLayout(
new BorderLayout());
281 JToolBar toolBar =
new JToolBar();
282 toolBar.setFloatable(
false);
284 JButton btn1x =
new JButton(
"480x360");
288 JButton btn2x =
new JButton(
"960x720");
292 JButton btn3x =
new JButton(
"1440x1080");
296 frame.add(toolBar, BorderLayout.NORTH);
297 frame.add(stage, BorderLayout.CENTER);
300 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
301 frame.setVisible(
true);
302 stage.requestFocusInWindow();
319 frame.setVisible(
false);
void handleMouseClick(int mx, int my)
boolean containsPoint(int mx, int my)
void setStage(Stage stage)
void mouseClicked(MouseEvent e)
void switchBackdropTo(String name)
void paintComponent(Graphics g)
void broadcast(String message)
String join(Object a, Object b)
String currentBackdropName
final ScratchObject stageObject
void keyReleased(KeyEvent e)
List< Costume > backdrops
java.util.concurrent.CountDownLatch frameLatch
void addToList(String listName, Object item)
void mouseReleased(MouseEvent e)
double getVariableAsNumber(String name)
List< java.util.function.BiConsumer< Double, Double > > scaleListeners
static void run(Runnable setup)
static Stage getInstance()
void whenScaleChanged(java.util.function.BiConsumer< Double, Double > action)
void whenIReceive(String message, Runnable action)
void setVariable(String name, Object value)
static void run(Stage stage, Runnable setup)
void keyTyped(KeyEvent e)
void mouseEntered(MouseEvent e)
boolean isKeyPressed(String keyName)
void mouseDragged(MouseEvent e)
java.util.Map< Integer, List< Runnable > > keyListeners
void keyPressed(KeyEvent e)
void startScript(Runnable script)
void playSound(String path)
void whenKeyPressed(int keyCode, Runnable action)
void mousePressed(MouseEvent e)
java.util.Map< String, List< Runnable > > broadcastListeners
Object getVariable(String name)
String getVariableAsString(String name)
void mouseExited(MouseEvent e)
void setStageScale(int scale, JFrame frame)
void setVolume(double vol)
void changeVariableBy(String name, double amount)
void mouseMoved(MouseEvent e)
boolean isKeyPressed(int keyCode)
void addBackdrop(Costume c)