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(); }
182 super.paintComponent(g);
183 Graphics2D g2d = (Graphics2D) g;
184 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
188 g2d.drawImage(bg, 0, 0, getWidth(), getHeight(),
null);
198 g2d.setColor(
new Color(200, 200, 200, 200));
200 for (java.util.Map.Entry<String, Object> entry :
stageObject.variables.entrySet()) {
201 String text = entry.getKey() +
": " + entry.getValue();
202 g2d.fillRoundRect(10, varY - 15, 120, 20, 5, 5);
203 g2d.setColor(Color.BLACK);
204 g2d.drawString(text, 15, varY);
205 g2d.setColor(
new Color(200, 200, 200, 200));
211 for (
int i = 0; i <
backdrops.size(); i++) {
212 if (
backdrops.get(i).getName().equals(name)) {
234 return (keyCode >= 0 && keyCode <
keysDown.length) ?
keysDown[keyCode] :
false;
243 this.setPreferredSize(
new Dimension(480 * scale, 360 * scale));
244 SwingUtilities.invokeLater(() -> {
248 this.requestFocusInWindow();
250 for (java.util.function.BiConsumer<Double, Double> listener :
scaleListeners) {
260 int code = e.getKeyCode();
263 if (listeners !=
null)
for (Runnable r : listeners)
stageObject.startScript(r);
267 for (
int i =
sprites.size() - 1; i >= 0; i--) {
282 public static void run(Runnable setup) {
286 public static void run(
Stage stage, Runnable setup) {
288 SwingUtilities.invokeLater(() -> {
289 JFrame
frame =
new JFrame(
"JScratch Stage");
291 frame.setLayout(
new BorderLayout());
293 JToolBar toolBar =
new JToolBar();
294 toolBar.setFloatable(
false);
296 JButton btn1x =
new JButton(
"480x360");
300 JButton btn2x =
new JButton(
"960x720");
304 JButton btn3x =
new JButton(
"1440x1080");
308 frame.add(toolBar, BorderLayout.NORTH);
309 frame.add(stage, BorderLayout.CENTER);
312 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
313 frame.setVisible(
true);
314 stage.requestFocusInWindow();
331 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)