so I'm following a tutorial for how to make a 2D game and my button does not, want to go to the place i specify i am going to put the code i have on a separate site as its connected to other classes I've made. but this is the class I'm looking at: MenuState:
package game.dl.gamestates;
import java.awt.Graphics2D;
import game.dl.Managers.MouseManager;
import game.dl.gamestate.GameState;
import game.dl.gamestate.GameStateManager;
import game.dl.gamestate.gameStateButton;
import game.dl.main.Main;
public class MenuState extends GameState {
MouseManager mm;
gameStateButton startGame;
public MenuState(GameStateManager gsm) {
super(gsm);
}
#Override
public void init() {
startGame = new gameStateButton(Main.width / 2, 200, new DungeonLvlLoader(gsm), gsm, "start Game");
mm = new MouseManager();
}
#Override
public void tick(double deltaTime) {
mm.tick();
startGame.tick();
}
#Override
public void render(Graphics2D g) {
startGame.render(g);
mm.render(g);
// g.drawString("TESTING", Main.width, Main.height);
// g.drawString("Hello World!", 150, 200);
g.clipRect(0, 0, Main.width, Main.height);
}
}
this is the GameStateButton.java class:
package game.dl.gamestate;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import game.dl.Managers.MouseManager;
import game.dl.main.Assets;
import game.gos.main.VectorToF;
public class gameStateButton extends Rectangle{
private VectorToF pos = new VectorToF();
private GameState gameState;
private GameStateManager gsm;
// private boolean isClicked;
private boolean isHeldOver;
private int width = 32 *3;
private int height = 32;
private BufferedImage defaultImage;
private String buttonMsg;
public gameStateButton(float xpos, float ypos, GameState gameState, GameStateManager gsm, String buttonMsg) {
this.gameState = gameState;
this.gsm = gsm;
this.pos.xpos = pos.xpos;
this.pos.ypos = pos.ypos;
this.buttonMsg = buttonMsg;
setBounds((int)pos.xpos, (int)pos.ypos, width, height);
defaultImage = Assets.getButton_notHoveredOver();
}
public gameStateButton(float xpos, float ypos, String buttonMsg) {
this.pos.xpos = pos.xpos;
this.pos.ypos = pos.ypos;
this.buttonMsg = buttonMsg;
setBounds((int)pos.xpos, (int)pos.ypos, width, height);
defaultImage = Assets.getButton_notHoveredOver();
}
public void tick(){
setBounds((int)pos.xpos, (int)pos.ypos, width, height);
if(getBounds().contains(MouseManager.mouse)){
isHeldOver = true;
}else{
isHeldOver = false;
}
if(isHeldOver){
if(defaultImage != Assets.getButton_hoveredOver()){
defaultImage = Assets.getButton_hoveredOver();
}
}else{
if(defaultImage != Assets.getButton_notHoveredOver()){
defaultImage = Assets.getButton_notHoveredOver();
}
}
if(gameState != null){
if(isHeldOver){
if(isPressed()){
gsm.states.push(gameState);
isHeldOver = false;
MouseManager.pressed = false;
}
}
}
}
public void render(Graphics2D g){
g.drawImage(defaultImage, (int)pos.xpos, (int)pos.ypos, width, height, null);
g.drawString(buttonMsg, pos.xpos, pos.ypos);
}
// public boolean isClicked(){
// return isClicked;
// }
public boolean isHeldOver(){
return isHeldOver;
}
public boolean isPressed (){
return MouseManager.pressed;
}
}
this is the full code dump:
https://drive.google.com/file/d/0B7JJSxzNdpBrNmdFRTgyVXhRSVU/view?usp=sharing
Your gameStateButton class is initialized as:
startGame = new gameStateButton(Main.width / 2, 200, new DungeonLvlLoader(gsm), gsm, "start Game");
Looking inside your code zip (btw, next time add the gameStateButton.java code here), you have a fixed width of 32*3 pixel and 32 pixel height for the button.
You are setting it at x = Main.width/2, y=200.
You can change those values to be whatever you want.
Now you have not told us what is the actual result (i.e. where it shows now), nor what is the expected result (i.e. where you want it to be), but that line is what is defining its initial position: if it doesn't show there, then something is changing its place. If it doesn't show at all, then probably you are drawing it in the wrong order and it gets overwritten.
So after playing around and looking at my other classes for a while I found the problem. in gameStateButton.java the constructor was pulling the x and y pos from the class fields and not the constructor variable so it should look like this:
public gameStateButton(float xpos, float ypos, GameState gameState, GameStateManager gsm, String buttonMsg) {
this.gameState = gameState;
this.gsm = gsm;
this.pos.xpos = xpos;
this.pos.ypos = ypos;
this.buttonMsg = buttonMsg;
setBounds((int)pos.xpos, (int)pos.ypos, width, height);
defaultImage = Assets.getButton_notHoveredOver();
}
and NOT this:
public gameStateButton(float xpos, float ypos, GameState gameState, GameStateManager gsm, String buttonMsg) {
this.gameState = gameState;
this.gsm = gsm;
this.pos.xpos = pos.xpos;
this.pos.ypos = pos.ypos;
this.buttonMsg = buttonMsg;
setBounds((int)pos.xpos, (int)pos.ypos, width, height);
defaultImage = Assets.getButton_notHoveredOver();
}
Related
I'm trying to make a racing game with the top down view on a static player in the middle of the screen, so instead of moving the player through the map, the map would move around the player. Since it's a racing game, I wanted it to also be somewhat similar to a car, but I've been having trouble with rotating the map around the player and having that work with translations.
I've tried keeping track of the center by adding or subtracting from it, which is what I did for the translations, but it doesn't work with the rotate method. The rotate function wouldn't rotate about the player and instead would rotate the player around some other point, and the translations would snap to a different location from the rotations. I'm sure my approach is flawed, and I have read about layers and such, but I'm not sure what I can do with them or how to use them. Also, any recommendations as to how to use java graphics in general would be greatly appreciated!
This is what I have in my main:
import javax.swing.JFrame;
import java.awt.BorderLayout;
public class game
{
public static void main(String []args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 1000;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Map b = new Map();
frame.add(b,BorderLayout.CENTER);
frame.setVisible(true);
b.startAnimation();
}
}
And this is the class that handles all the graphics
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Map extends JComponent implements Runnable, KeyListener
{
private int speed = 5;
private int xcenter = 500; // starts on player
private int ycenter = 300;
private double angle = 0.0;
private int[] xcords = {xcenter+10, xcenter, xcenter+20};
private int[] ycords = {ycenter-10, ycenter+20, ycenter+20};
private boolean moveNorth = false;
private boolean moveEast = false;
private boolean moveSouth = false;
private boolean moveWest = false;
public Map()
{
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void startAnimation()
{
Thread t = new Thread(this);
t.start();
}
public void paintComponent(Graphics g)
{
g.fillPolygon(xcords, ycords, 3);
// move screen
if(moveNorth)
{
ycenter += speed;
g.translate(xcenter, ycenter);
}
else if(moveEast)
{
angle += ((1 * Math.PI/180) % (2 * Math.PI));
((Graphics2D) g).rotate(angle, 0, 0);
}
else if(moveSouth)
{
System.out.println(xcenter + ", " + ycenter);
ycenter -= speed;
((Graphics2D) g).rotate(angle, 0, 0);
g.translate(xcenter, ycenter);
}
else if(moveWest)
{
angle -= Math.toRadians(1) % (2 * Math.PI);
((Graphics2D) g).rotate(angle, 0, 0);
}
for(int i = -10; i < 21; i++)
{
g.drawLine(i * 50, -1000, i * 50, 1000);
g.drawLine(-1000, i * 50, 1000, i * 50);
}
g.drawOval(0, 0, 35, 35);
}
public void run()
{
while (true)
{
try
{
if(moveNorth || moveEast || moveSouth || moveWest)
{
repaint();
}
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
public void keyPressed(KeyEvent e)
{
if(e.getExtendedKeyCode() == 68) // d
{
moveEast = true;
}
else if(e.getExtendedKeyCode() == 87) // w
{
moveNorth = true;
}
else if(e.getExtendedKeyCode() == 65) // a
{
moveWest = true;
}
else if(e.getExtendedKeyCode() == 83) // s
{
moveSouth = true;
}
}
public void keyReleased(KeyEvent e)
{
moveNorth = false;
moveEast = false;
moveSouth = false;
moveWest = false;
}
public void keyTyped(KeyEvent e)
{
}
}
You have to keep in mind that transformations are compounding, so if you rotate the Graphics context by 45 degrees, everything painted after it will be rotated 45 degrees (around the point of rotation), if you rotate it again by 45 degrees, everything painted after it will be rotated a total of 90 degrees.
If you want to paint additional content after a transformation, then you either need to undo the transformation, or, preferably, take a snapshot of the Graphics context and dispose of it (the snapshot) when you're done.
You also need to beware of the point of rotation, Graphics2D#rotate(double) will rotate the Graphics around the point of origin (ie 0x0), which may not be desirable. You can change this by either changing the origin point (ie translate) or using Graphics2D#rotate(double, double, double), which allows you to define the point of rotation.
For example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class TestPane extends JPanel {
enum Direction {
LEFT, RIGHT;
}
protected enum InputAction {
PRESSED_LEFT, PRESSED_RIGHT, RELEASED_LEFT, RELEASED_RIGHT
}
private BufferedImage car;
private BufferedImage road;
private Set<Direction> directions = new TreeSet<>();
private double directionOfRotation = 0;
public TestPane() throws IOException {
car = ImageIO.read(getClass().getResource("/images/Car.png"));
road = ImageIO.read(getClass().getResource("/images/Road.png"));
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), InputAction.PRESSED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), InputAction.RELEASED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), InputAction.PRESSED_RIGHT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), InputAction.RELEASED_RIGHT);
am.put(InputAction.PRESSED_LEFT, new DirectionAction(Direction.LEFT, true));
am.put(InputAction.RELEASED_LEFT, new DirectionAction(Direction.LEFT, false));
am.put(InputAction.PRESSED_RIGHT, new DirectionAction(Direction.RIGHT, true));
am.put(InputAction.RELEASED_RIGHT, new DirectionAction(Direction.RIGHT, false));
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (directions.contains(Direction.RIGHT)) {
directionOfRotation += 1;
} else if (directions.contains(Direction.LEFT)) {
directionOfRotation -= 1;
}
// No doughnuts for you :P
if (directionOfRotation > 180) {
directionOfRotation = 180;
} else if (directionOfRotation < -180) {
directionOfRotation = -180;
}
repaint();
}
});
timer.start();
}
protected void setDirectionActive(Direction direction, boolean active) {
if (active) {
directions.add(direction);
} else {
directions.remove(direction);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(213, 216);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
drawRoadSurface(g2d);
drawCar(g2d);
g2d.dispose();
}
protected void drawCar(Graphics2D g2d) {
g2d = (Graphics2D) g2d.create();
int x = (getWidth() - car.getWidth()) / 2;
int y = (getHeight() - car.getHeight()) / 2;
g2d.drawImage(car, x, y, this);
g2d.dispose();
}
protected void drawRoadSurface(Graphics2D g2d) {
g2d = (Graphics2D) g2d.create();
// This sets the point of rotation at the center of the window
int midX = getWidth() / 2;
int midY = getHeight() / 2;
g2d.rotate(Math.toRadians(directionOfRotation), midX, midY);
// We then need to offset the top/left corner so that what
// we want draw appears to be in the center of the window,
// and thus will be rotated around it's center
int x = midX - (road.getWidth() / 2);
int y = midY - (road.getHeight() / 2);
g2d.drawImage(road, x, y, this);
g2d.dispose();
}
protected class DirectionAction extends AbstractAction {
private Direction direction;
private boolean active;
public DirectionAction(Direction direction, boolean active) {
this.direction = direction;
this.active = active;
}
#Override
public void actionPerformed(ActionEvent e) {
setDirectionActive(direction, active);
}
}
}
}
I have this code which is basically a home menu with two clickable rectangles.
Start Game
Info
Start Game works fine.
Info is what is not really working. When pressed, the info screen will appear, but the home menu buttons will still be there though not visible (can be clicked).. it seems that when the info menu is appearing, the home menu buttons are not getting cleared.
Also, any point on the info menu is clickable and will show the home menu again. (not what intended, only the back buttons should do that).
How can I fix those problems ?
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
public class HomeMenu extends JComponent implements MouseListener, MouseMotionListener {
private static final String GAME_TITLE = "BRICK DESTROY";
private static final String START_TEXT = "START";
private static final String INFO_TEXT = "INFO";
private static final String howtoPlay = """
1- Click Start\n
2- Choose the mode\n
3- Each mode has 3 levels\n
4- To play/pause press space, use 'A' and 'D' to move\n
5- To open pause menu press 'ESC'\n
6- To open DebugPanel press 'ALT-SHIFT-F1'""";
private static final String backText = "BACK";
private static final Color BORDER_COLOR = new Color(200,8,21); //Venetian Red
private static final Color DASH_BORDER_COLOR = new Color(255, 216, 0);//school bus yellow
private static final Color TEXT_COLOR = new Color(255, 255, 255);//white
private static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();;
private static final Color CLICKED_TEXT = Color.ORANGE.darker();
private static final int BORDER_SIZE = 5;
private static final float[] DASHES = {12,6};
private Rectangle menuFace;
private Rectangle infoFace;
private Rectangle startButton;
private Rectangle infoButton;
private Rectangle backButton;
private BasicStroke borderStoke;
private BasicStroke borderStoke_noDashes;
private Image img = Toolkit.getDefaultToolkit().createImage("1.jpeg");
private Font gameTitleFont;
private Font infoFont;
private Font buttonFont;
private Font howtoPlayFont;
private GameFrame owner;
private boolean startClicked;
private boolean infoClicked = false;
private boolean backClicked = false;
public HomeMenu(GameFrame owner,Dimension area){
this.setFocusable(true);
this.requestFocusInWindow();
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.owner = owner;
menuFace = new Rectangle(new Point(0,0),area);
infoFace = new Rectangle(new Point(0,0),area);
this.setPreferredSize(area);
Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
startButton = new Rectangle(btnDim);
infoButton = new Rectangle(btnDim);
backButton = new Rectangle(btnDim);
borderStoke = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,0,DASHES,0);
borderStoke_noDashes = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
gameTitleFont = new Font("Calibri",Font.BOLD,28);
infoFont = new Font("Calibri",Font.BOLD,24);
buttonFont = new Font("Calibri",Font.BOLD,startButton.height-2);
howtoPlayFont = new Font("Calibri",Font.PLAIN,14);
}
public void paint(Graphics g){
drawMenu((Graphics2D)g);
}
public void drawMenu(Graphics2D g2d){
if(infoClicked) {
drawInfoMenu(g2d);
return;
}else{
drawContainer(g2d);
Color prevColor = g2d.getColor();
Font prevFont = g2d.getFont();
double x = menuFace.getX();
double y = menuFace.getY();
g2d.translate(x,y);
//methods calls
drawText(g2d);
drawButton(g2d);
//end of methods calls
g2d.translate(-x,-y);
g2d.setFont(prevFont);
g2d.setColor(prevColor);
}
Toolkit.getDefaultToolkit().sync();
}
private void drawContainer(Graphics2D g2d){
Color prev = g2d.getColor();
//g2d.setColor(BG_COLOR);
g2d.drawImage(img,0,0,menuFace.width,menuFace.height,this);
//g2d.fill(menuFace);
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(menuFace);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(menuFace);
g2d.setStroke(tmp);
g2d.setColor(prev);
}
private void drawText(Graphics2D g2d){
g2d.setColor(TEXT_COLOR);
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE,frc);
int sX,sY;
sY = (int)(menuFace.getHeight() / 4);
sX = (int)(menuFace.getWidth() - gameTitleRect.getWidth()) / 2;
sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(gameTitleFont);
g2d.drawString(GAME_TITLE,sX,sY);
}
private void drawButton(Graphics2D g2d){
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT,frc);
Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT,frc);
g2d.setFont(buttonFont);
int x = (menuFace.width - startButton.width) / 2;
int y =(int) ((menuFace.height - startButton.height) * 0.5);
startButton.setLocation(x,y);
x = (int)(startButton.getWidth() - txtRect.getWidth()) / 2;
y = (int)(startButton.getHeight() - txtRect.getHeight()) / 2;
x += startButton.x;
y += startButton.y + (startButton.height * 0.9);
if(startClicked){
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(startButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(START_TEXT,x,y);
g2d.setColor(tmp);
}
else{
g2d.draw(startButton);
g2d.drawString(START_TEXT,x,y);
}
x = startButton.x;
y = startButton.y;
y *= 1.3;
infoButton.setLocation(x,y);
x = (int)(infoButton.getWidth() - mTxtRect.getWidth()) / 2;
y = (int)(infoButton.getHeight() - mTxtRect.getHeight()) / 2;
x += infoButton.getX();
y += infoButton.getY() + (startButton.height * 0.9);
if(infoClicked){
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(infoButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(INFO_TEXT,x,y);
g2d.setColor(tmp);
}
else{
g2d.draw(infoButton);
g2d.drawString(INFO_TEXT,x,y);
}
}
private void drawInfoMenu(Graphics2D g2d){
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT,frc);
Color prev = g2d.getColor();
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(infoFace);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(infoFace);
g2d.fillRect(0,0,infoFace.width,infoFace.height);
g2d.setStroke(tmp);
g2d.setColor(prev);
g2d.setColor(TEXT_COLOR);
int sX,sY;
sY = (int)(infoFace.getHeight() / 15);
sX = (int)(infoFace.getWidth() - infoRec.getWidth()) / 2;
sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(infoFont);
g2d.drawString(INFO_TEXT,sX,sY);
TextLayout layout = new TextLayout(howtoPlay, howtoPlayFont, frc);
String[] outputs = howtoPlay.split("\n");
for(int i=0; i<outputs.length; i++) {
g2d.setFont(howtoPlayFont);
g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
}
backButton.setLocation(getWidth()/3,getHeight()-50);
int x = (int)(backButton.getWidth() - infoRec.getWidth()) / 2;
int y = (int)(backButton.getHeight() - infoRec.getHeight()) / 2;
x += backButton.x+11;
y += backButton.y + (layout.getBounds().getHeight() * 1.35);
backButton.setLocation(getWidth()/3,getHeight()-50);
if(backClicked){
Color tmp1 = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(backButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(backText,x,y);
g2d.setColor(tmp1);
infoClicked = false;
repaint();
}
else{
g2d.draw(backButton);
g2d.drawString(backText,x,y);
}
}
#Override
public void mouseClicked(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p)){
owner.enableGameBoard();
}
else if(infoButton.contains(p)){
infoClicked = true;
}
else if(backButton.contains(p)){
infoClicked = false;
}
repaint();
}
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p)){
startClicked = true;
repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);
}
else if(infoButton.contains(p)){
infoClicked = true;
}
else if(backButton.contains(p)){
infoClicked = false;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
if(startClicked){
startClicked = false;
repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);
}
else if(infoClicked){
infoClicked = false;
}
else if(backClicked){
infoClicked = true;
}
repaint();
}
#Override
public void mouseEntered(MouseEvent mouseEvent) {
}
#Override
public void mouseExited(MouseEvent mouseEvent) {
}
#Override
public void mouseDragged(MouseEvent mouseEvent) {
}
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p) || infoButton.contains(p) || backButton.contains(p)) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else {
this.setCursor(Cursor.getDefaultCursor());
}
}
}
Here are the images of both windows
main menu
info menu, pressing anywhere = back to home menu, pressing roughly in the middle = start game or back to main menu too
First read, Performing Custom Painting and Painting in AWT and Swing to get a better understanding how painting in Swing works and how you're suppose to work with it.
But I already have ...
public void paint(Graphics g){
drawMenu((Graphics2D)g);
}
would suggest otherwise. Seriously, go read those links so you understand all the issues that the above decision is going to create for you.
You're operating in a OO language, you need to take advantage of that and decouple your code and focus on the "single responsibility" principle.
I'm kind of tired of talking about it, so you can do some reading:
https://softwareengineering.stackexchange.com/questions/244476/what-is-decoupling-and-what-development-areas-can-it-apply-to
Cohesion and Decoupling, what do they represent?
Single Responsibility Principle
Single Responsibility Principle in Java with Examples
SOLID Design Principles Explained: The Single Responsibility Principle
These are basic concepts you really need to understand as they will make your live SOOO much easier and can be applied to just about any language.
As an example, from your code...
public HomeMenu(GameFrame owner,Dimension area){
//...
this.setPreferredSize(area);
There is no good reason (other than laziness (IMHO)) that any caller should be telling a component what size it should be, that's not their responsibility. It's the responsibility of the component to tell the parent container how big it would like to be and for the parent component to figure out how it's going to achieve that (or ignore it as the case may be).
The "basic" problem you're having is a simple one. Your "God" class is simply trying to do too much (ie it's taken on too much responsibility). Now we "could" add a dozen or more flags into the code to compensate for this, which is just going to increase the coupling and complexity, making it harder to understand and maintain, or we can take a step back, break it down into individual areas of responsibility and build the solution around those, for example...
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new HomePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HomePane extends JPanel {
public HomePane() {
setLayout(new BorderLayout());
navigateToMenu();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void navigateToMenu() {
removeAll();
HomeMenuPane pane = new HomeMenuPane(new HomeMenuPane.NavigationListener() {
#Override
public void navigateToInfo(HomeMenuPane source) {
HomePane.this.navigateToInfo();
}
#Override
public void navigateToStartGame(HomeMenuPane source) {
startGame();
}
});
add(pane);
revalidate();
repaint();
}
protected void navigateToInfo() {
removeAll();
HowToPlayPane pane = new HowToPlayPane(new HowToPlayPane.NavigationListener() {
#Override
public void navigateBack(HowToPlayPane source) {
navigateToMenu();
}
});
add(pane);
revalidate();
repaint();
}
protected void startGame() {
removeAll();
add(new JLabel("This is pretty awesome, isn't it!", JLabel.CENTER));
revalidate();
repaint();
}
}
public abstract class AbstractBaseMenuPane extends JPanel {
protected static final Color BORDER_COLOR = new Color(200, 8, 21); //Venetian Red
protected static final Color DASH_BORDER_COLOR = new Color(255, 216, 0);//school bus yellow
protected static final Color TEXT_COLOR = new Color(255, 255, 255);//white
protected static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();
protected static final Color CLICKED_TEXT = Color.ORANGE.darker();
protected static final int BORDER_SIZE = 5;
protected static final float[] DASHES = {12, 6};
private Rectangle border;
private BasicStroke borderStoke;
private BasicStroke borderStoke_noDashes;
private BufferedImage backgroundImage;
public AbstractBaseMenuPane() {
borderStoke = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, DASHES, 0);
borderStoke_noDashes = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
border = new Rectangle(new Point(0, 0), getPreferredSize());
// You are now responsible for filling the background
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
BufferedImage backgroundImage = getBackgroundImage();
if (backgroundImage != null) {
g2d.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
}
Color prev = g2d.getColor();
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(border);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(border);
g2d.dispose();
}
public void setBackgroundImage(BufferedImage backgroundImage) {
this.backgroundImage = backgroundImage;
repaint();
}
public BufferedImage getBackgroundImage() {
return backgroundImage;
}
}
public class HomeMenuPane extends AbstractBaseMenuPane {
public static interface NavigationListener {
public void navigateToInfo(HomeMenuPane source);
public void navigateToStartGame(HomeMenuPane source);
}
private static final String GAME_TITLE = "BRICK DESTROY";
private static final String START_TEXT = "START";
private static final String INFO_TEXT = "INFO";
private Rectangle startButton;
private Rectangle infoButton;
private Font gameTitleFont;
private Font buttonFont;
// Don't do this, this just sucks (for so many reasons)
// Use ImageIO.read instead and save yourself a load of frustration
//private Image img = Toolkit.getDefaultToolkit().createImage("1.jpeg");
private Point lastClickPoint;
private NavigationListener navigationListener;
public HomeMenuPane(NavigationListener navigationListener) {
this.navigationListener = navigationListener;
try {
setBackgroundImage(ImageIO.read(getClass().getResource("/images/BrickWall.jpg")));
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
lastClickPoint = p;
if (startButton.contains(p)) {
peformStartGameAction();
} else if (infoButton.contains(p)) {
performInfoAction();
}
repaint();
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
lastClickPoint = null;
repaint();
}
});
this.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (startButton.contains(p) || infoButton.contains(p)) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
setCursor(Cursor.getDefaultCursor());
}
}
});
Dimension area = getPreferredSize();
Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
startButton = new Rectangle(btnDim);
infoButton = new Rectangle(btnDim);
gameTitleFont = new Font("Calibri", Font.BOLD, 28);
buttonFont = new Font("Calibri", Font.BOLD, startButton.height - 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Color prevColor = g2d.getColor();
Font prevFont = g2d.getFont();
//methods calls
drawText(g2d);
drawButton(g2d);
//end of methods calls
g2d.setFont(prevFont);
g2d.setColor(prevColor);
g2d.dispose();
}
private void drawText(Graphics2D g2d) {
g2d.setColor(TEXT_COLOR);
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE, frc);
int sX, sY;
sY = (int) (getHeight() / 4);
sX = (int) (getWidth() - gameTitleRect.getWidth()) / 2;
sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(gameTitleFont);
g2d.drawString(GAME_TITLE, sX, sY);
}
private void drawButton(Graphics2D g2d) {
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT, frc);
Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT, frc);
g2d.setFont(buttonFont);
int x = (getWidth() - startButton.width) / 2;
int y = (int) ((getHeight() - startButton.height) * 0.5);
startButton.setLocation(x, y);
x = (int) (startButton.getWidth() - txtRect.getWidth()) / 2;
y = (int) (startButton.getHeight() - txtRect.getHeight()) / 2;
x += startButton.x;
y += startButton.y + (startButton.height * 0.9);
if (lastClickPoint != null && startButton.contains(lastClickPoint)) {
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(startButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(START_TEXT, x, y);
g2d.setColor(tmp);
} else {
g2d.draw(startButton);
g2d.drawString(START_TEXT, x, y);
}
x = startButton.x;
y = startButton.y;
y *= 1.3;
infoButton.setLocation(x, y);
x = (int) (infoButton.getWidth() - mTxtRect.getWidth()) / 2;
y = (int) (infoButton.getHeight() - mTxtRect.getHeight()) / 2;
x += infoButton.getX();
y += infoButton.getY() + (startButton.height * 0.9);
if (lastClickPoint != null && infoButton.contains(lastClickPoint)) {
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(infoButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(INFO_TEXT, x, y);
g2d.setColor(tmp);
} else {
g2d.draw(infoButton);
g2d.drawString(INFO_TEXT, x, y);
}
}
protected void peformStartGameAction() {
navigationListener.navigateToStartGame(this);
}
protected void performInfoAction() {
navigationListener.navigateToInfo(this);
}
}
public class HowToPlayPane extends AbstractBaseMenuPane {
public static interface NavigationListener {
public void navigateBack(HowToPlayPane source);
}
private static final String HOW_TO_PLAY_TEXT = """
1- Click Start\n
2- Choose the mode\n
3- Each mode has 3 levels\n
4- To play/pause press space, use 'A' and 'D' to move\n
5- To open pause menu press 'ESC'\n
6- To open DebugPanel press 'ALT-SHIFT-F1'""";
private static final String BACK_TEXT = "BACK";
private static final String INFO_TEXT = "INFO";
private Rectangle backButton;
private boolean backClicked = false;
private Font infoFont;
private Font howtoPlayFont;
private NavigationListener navigationListener;
public HowToPlayPane(NavigationListener navigationListener) {
this.navigationListener = navigationListener;
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (backButton.contains(p)) {
backClicked = true;
repaint();
performBackAction();
}
}
#Override
public void mouseReleased(MouseEvent e) {
backClicked = false;
}
});
this.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (backButton.contains(p)) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
setCursor(Cursor.getDefaultCursor());
}
}
});
Dimension btnDim = new Dimension(getPreferredSize().width / 3, getPreferredSize().height / 12);
backButton = new Rectangle(btnDim);
infoFont = new Font("Calibri", Font.BOLD, 24);
howtoPlayFont = new Font("Calibri", Font.PLAIN, 14);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(BORDER_COLOR);
g2d.fillRect(0, 0, getWidth(), getHeight());
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT, frc);
//
// Color prev = g2d.getColor();
//
// Stroke tmp = g2d.getStroke();
//
// g2d.setStroke(borderStoke_noDashes);
// g2d.setColor(DASH_BORDER_COLOR);
// g2d.draw(infoFace);
//
// g2d.setStroke(borderStoke);
// g2d.setColor(BORDER_COLOR);
// g2d.draw(infoFace);
//
// g2d.fillRect(0, 0, infoFace.width, infoFace.height);
//
// g2d.setStroke(tmp);
//
// g2d.setColor(prev);
//
g2d.setColor(TEXT_COLOR);
int sX, sY;
sY = (int) (getHeight() / 15);
sX = (int) (getWidth() - infoRec.getWidth()) / 2;
sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(infoFont);
g2d.drawString(INFO_TEXT, sX, sY);
TextLayout layout = new TextLayout(HOW_TO_PLAY_TEXT, howtoPlayFont, frc);
String[] outputs = HOW_TO_PLAY_TEXT.split("\n");
for (int i = 0; i < outputs.length; i++) {
g2d.setFont(howtoPlayFont);
g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
}
backButton.setLocation(getWidth() / 3, getHeight() - 50);
int x = (int) (backButton.getWidth() - infoRec.getWidth()) / 2;
int y = (int) (backButton.getHeight() - infoRec.getHeight()) / 2;
x += backButton.x + 11;
y += backButton.y + (layout.getBounds().getHeight() * 1.35);
backButton.setLocation(getWidth() / 3, getHeight() - 50);
if (backClicked) {
Color tmp1 = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(backButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(BACK_TEXT, x, y);
g2d.setColor(tmp1);
repaint();
} else {
g2d.draw(backButton);
g2d.drawString(BACK_TEXT, x, y);
}
g2d.dispose();
}
protected void performBackAction() {
navigationListener.navigateBack(this);
}
}
}
Now, this example makes use of components to present different views (it even has a nice abstract implementation to allow for code re-use 😱), but it occurs to me, that, if you "really" wanted to, you could have a series of "painter" classes, which could be used to delegate the painting of the current state to, and mouse clicks/movements could be delegated to, meaning you could have a single component, which would simple delegate the painting (via the paintComponent method) to which ever painter is active.
And, wouldn't you know it, they have a design principle for that to, the Delegation Pattern
The above example also makes use of the observer pattern, so you might want to have a look into that as well
I am trying to implement langton's ant , and i did it well :
langton's ant java simulation screen
for painting in my jPanel, i override the paintComponent at each step but it take so much time for painting every black or white rectangle , i just want that at each step i only paint the two rectangle who have changed!?
So my question is, how to only paint a rectangle without changing what was painted in previous frame?
here is my code for painting
public void paintComponent(Graphics g){
g.setColor(Color.white);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(Color.black);
int careLargeur = getWidth() / m;
int careHauteur = getHeight() / n;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(map[i][j])
g.fillRect(j*careLargeur,i*careHauteur,careLargeur,careHauteur);
}
//draw fourmi
g.setColor(Color.red);
g.fillOval(jF*careLargeur, iF*careHauteur, careLargeur, careHauteur);
}
any help? or should i give more details ?
here is the jar :
Paint your rectangles to a BufferedImage, and then draw that BufferedImage within your paintComponent method. You could also limit how much is re-drawn by using one of the repaint(...) overrides that specifies the exact rectangular region to repaint.
So your paintComponent method could be as simple as this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
g.setColor(Color.red);
g.fillOval(jF*careLargeur, iF*careHauteur, careLargeur, careHauteur);
}
With drawing changes being made to the img BufferedImage.
Assuming that you're using a Swing Timer to drive the state changes to your model, you could
change the model, and then
update the BufferedImage based on the model changes, and
call repaint(...) on only the updated region.
Incomplete code attempt.... not yet done!
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
/**
* https://en.wikipedia.org/wiki/Langton%27s_ant
* https://stackoverflow.com/a/44930371/522444
* #author Pete
*
*/
public class LangtonsAnt {
private static final int TIMER_DELAY = 30;
private static void createAndShowGui() {
Model model = new Model(800);
View view = new View(800);
Controller controller = new Controller(model, view);
JFrame frame = new JFrame("Langtons Ant");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
controller.startTimer(TIMER_DELAY);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static class Model {
public static final String POINT = "point";
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
private int gridSize;
private boolean[][] grid; // false is white. Better to use enums
private Point oldValue;
private Point point; // ant location
public Model(int gridSize) {
this.gridSize = gridSize;
grid = new boolean[gridSize][gridSize];
int x = gridSize / 2;
int y = gridSize / 2;
setPoint(new Point(x, y));
}
public void setPoint(Point point) {
this.oldValue = this.point;
Point newValue = point;
this.point = point;
support.firePropertyChange(POINT, oldValue, newValue);
}
public Point getPoint() {
return point;
}
public boolean[][] getGrid() {
return grid;
}
public int getGridSize() {
return gridSize;
}
public void step() {
// first will hold relative new positions
int newX = 0;
int newY = 0;
boolean gridPoint = getGridPoint(point);
if (oldValue == null) {
newX = point.x;
newY = point.y - 1;
} else {
int dX = point.x - oldValue.x;
int dY = point.y - oldValue.y;
if (dX != 0) {
// from left or right
newY = dX > 0 ? 1 : -1; // assume "white" or false
newY = gridPoint ? -newY : newY; // if "black" then reverse
} else {
// from up or down
newX = dY > 0 ? -1 : 1; // assume "white" or false
newX = gridPoint ? -newX : newX; // if "black" then reverse
}
// convert from relative to absolute new positions
newX = point.x + newX;
newY = point.y + newY;
}
setGridPoint(point, !gridPoint);
setPoint(new Point(newX, newY));
}
public boolean getGridPoint(int x, int y) {
return grid[x][y];
}
public boolean getGridPoint(Point p) {
return getGridPoint(p.x, p.y);
}
public void setGridPoint(int x, int y, boolean b) {
grid[x][y] = b;
}
public void setGridPoint(Point p, boolean b) {
setGridPoint(p.x, p.y, b);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
support.addPropertyChangeListener(propertyName, l);
}
}
private static class Controller {
private Model model;
private View view;
private Timer timer;
public Controller(Model model, View view) {
this.model = model;
this.view = view;
view.setAntImg(createAntImg());
model.addPropertyChangeListener(Model.POINT, new ModelListener());
}
private BufferedImage createAntImg() {
// trivial image for now
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
g.setColor(Color.RED);
g.fillRect(0, 0, 1, 1);
g.dispose();
return img;
}
public void startTimer(int delay) {
timer = new Timer(delay, new TimerListener());
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
model.step();
}
}
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO Finish this.
// get the new point and old point
// translate model coord to view coord
// Change the state of the view's buffered image
// repaint the limited region that was changed
}
}
}
private static class View extends JPanel {
private static final Color BACKGROUND = Color.WHITE;
private BufferedImage gridImg;
private BufferedImage antImg;
private Point guiAntLocation;
private int pixelWidth;
public View(int pixelWidth) {
this.pixelWidth = pixelWidth;
gridImg = new BufferedImage(pixelWidth, pixelWidth, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = gridImg.createGraphics();
g2.setColor(BACKGROUND);
g2.fillRect(0, 0, pixelWidth, pixelWidth);
g2.dispose();
}
public int getPixelWidth() {
return pixelWidth;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (getGridImg() != null) {
g.drawImage(getGridImg(), 0, 0, this);
}
if (guiAntLocation != null && antImg != null) {
int x = guiAntLocation.x;
int y = guiAntLocation.y;
g.drawImage(antImg, x, y, this);
}
}
public void setGuiAntLocation(Point guiAntLocation) {
this.guiAntLocation = guiAntLocation;
}
public Point getGuiAntLocation() {
return guiAntLocation;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || getGridImg() == null) {
return super.getPreferredSize();
}
return new Dimension(getGridImg().getWidth(), getGridImg().getHeight());
}
public BufferedImage getGridImg() {
return gridImg;
}
public void setGridImg(BufferedImage gridImg) {
this.gridImg = gridImg;
}
public void setAntImg(BufferedImage antImg) {
this.antImg = antImg;
}
}
}
I cannot get my repaint method to work in my SimonPanel class. At first, I thought it was because I used paint() instead of paintComponent(), but that didn't seem to solve the problem. My
SimonShape.java(Holds the frame and changes the colors of the shape)
public class SimonShape extends JFrame implements KeyListener {
private int level = 1;
// speed of the light up sequence
private int lightUpSpd = 500;
// chooses random color based on numbers 0-3
private int random;
// keeps track of user inputs
private int compCounter = 0;
ArrayList<Integer> comp = new ArrayList<Integer>();
SimonPanel simon = new SimonPanel();
//SimonLabel keyLabel = new SimonLabel();
private Color blue = Color.BLUE.darker();
private Color red = Color.RED.darker();
private Color yellow = Color.YELLOW.darker();
private Color green = Color.GREEN.darker();
public SimonShape ()
{
JLabel label = new JLabel();
setSize(800,800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
simon.setFocusable(true);
simon.setOpaque(true);
simon.addKeyListener(this);
this.add(simon);
setVisible(true);
simon.requestFocusInWindow();
label.setFocusable(true);
label.setOpaque(true);
label.addKeyListener(this);
this.add(label);
setVisible(true);
label.requestFocusInWindow();
randomColorChange();
}
private void randomColorChange()
{
JOptionPane.showMessageDialog(this, "Level " + level);
random = (int) (Math.random() * 4);
comp.add(random);
//light up sequence
for (int i = 0; i < level; i++)
{
if (comp.get(i) == 0) simon.colorChange(0);
else if (comp.get(i) == 1) simon.colorChange(1);
else if (comp.get(i) == 2) simon.colorChange(2);
else if (comp.get(i) == 3) simon.colorChange(3);
}
}
SimonPanel.java (Holds the shape)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Arc2D;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.Timer;
public class SimonPanel extends JPanel{
private int width = 500;
private int height = 500;
private int x = 150;
private int y = 150;
private int TURN = 45;
private SimonListener listener;
private Timer timer;
private Color blue = Color.BLUE.darker();
private Color red = Color.RED.darker();
private Color yellow = Color.YELLOW.darker();
private Color green = Color.GREEN.darker();
// speed of the light up sequence
private int lightUpSpd = 500;
// chooses random color based on numbers 0-3
private int random;
// keeps track of user inputs
private int compCounter = 0;
public SimonPanel()
{
}
public void colorChange(int color)
{
if (color == 0)
{
//lightUp();
green.brighter();
repaint();
listener = new SimonListener(this,green);
timer = new Timer(lightUpSpd,listener);
System.out.println("green");
timer.start();
}
else if (color == 1)
{
red.brighter();
repaint();
listener = new SimonListener(this,red);
timer = new Timer(lightUpSpd,listener);
System.out.println("red");
timer.start();
}
else if (color == 2)
{
blue.brighter();
repaint();
listener = new SimonListener(this,blue);
timer = new Timer(lightUpSpd,listener);
System.out.println("blue");
timer.start();
}
else if (color == 3)
{
yellow.brighter();
this.repaint();
listener = new SimonListener(this,yellow);
timer = new Timer(lightUpSpd,listener);
System.out.println("yellow");
timer.start();
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// Blue Section
g2.setStroke(new BasicStroke(1.0f));
g2.setPaint(blue);
g2.fill(new Arc2D.Double(x,y,width,height,180+TURN,90,Arc2D.PIE));
// Red Section
g2.setStroke(new BasicStroke(2.0f));
g2.setPaint(red);
g2.fill(new Arc2D.Double(x,y,width,height,90+TURN,90,Arc2D.PIE));
// Yellow Section
g2.setStroke(new BasicStroke(2.0f));
g2.setPaint(yellow);
g2.fill(new Arc2D.Double(x,y,width,height,-90+TURN,90,Arc2D.PIE));
// Green Section
g2.setStroke(new BasicStroke(2.0f));
g2.setPaint(green);
g2.fill(new Arc2D.Double(x,y,width,height,360+TURN,90,Arc2D.PIE));
}
}
Test Class
public class SimonTest {
public static void main(String[] args)
{
new SimonShape();
}
}
SimonListener.java
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class SimonListener implements ActionListener {
private JPanel panel;
private Color color;
public SimonListener(JPanel panel, Color color)
{
this.panel = panel;
this.color = color;
}
public void setColor(Color newColor)
{
color = newColor;
}
public void actionPerformed(ActionEvent e)
{
color.brighter();
System.out.println("Called");
panel.repaint();
((Timer) e.getSource()).stop();
}
}
Your "main" problem "seems" to the fact that you are not assiging the changes to the color objects back to anything;
green.brighter();
From the JavaDocs
Creates a new Color that is a brighter version of this Color.
You should be doing something more like
green = green.brighter();
I would also consider having a "base" color from which you can derive bright/darker colors from, but that's me
I've a VERY simple AWT Painting. Just playing aound to make something bigger. But can't get it working ...
What happens is that only elypse2 is shown - regardless of repaint()ing it or not.
I also tried to use Swing components instead of AWT (JFrame, JComponent) but this also changes nothing.
Is using a Layout Manager necessary? But I want to draw only graphical components, like arcs, rectangles, line, poly-lines, aso ...
Here's the main():
public static void main(String[] args) {
Frame testFrame = new Frame("Grafx-Test");
testFrame.setSize(300, 200);
testFrame.setAlwaysOnTop(true);
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
testFrame.setVisible(true);
}
});
Elypse elypse = new Elypse(new Point(70, 80), 30, 30, Color.BLUE, false);
testFrame.add(elypse);
Elypse elypse2 = new Elypse(new Point(70, 50), 50, 30, Color.BLUE, true);
testFrame.add(elypse2);
}
and here the used class:
public class Elypse extends Canvas {
private Point start;
private int width;
private int height;
private Color c;
private boolean filled;
public Elypse(Point start, int width, int height, Color c, boolean filled) {
this.start = start;
this.width = width;
this.height = height;
this.c = c;
this.filled = filled;
}
#Override
public void paint(Graphics g) {
g.setColor(c);
if (filled) {
g.fillOval(start.x, start.y, width, height);
}
else {
g.drawOval(start.x, start.y, width, height);
}
}
}
You neglect to pack() the enclosing Window. Note the characteristic symptom in your original code: resizing the frame, which generates an update, causes elypse2 to appear.
Addendum: You can see both Elypse instances by using a layout such as GridLayout.
testFrame.setLayout(new GridLayout(0, 1));
As tested:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
public class Test {
public static void main(String[] args) {
Frame testFrame = new Frame("Grafx-Test");
testFrame.setAlwaysOnTop(true);
Elypse elypse = new Elypse(new Point(70, 80), 30, 30, Color.BLUE, false);
testFrame.add(elypse);
Elypse elypse2 = new Elypse(new Point(70, 50), 50, 30, Color.BLUE, true);
testFrame.add(elypse2);
testFrame.pack();
testFrame.setVisible(true);
}
private static class Elypse extends Canvas {
private Point start;
private int width;
private int height;
private Color c;
private boolean filled;
public Elypse(Point start, int width, int height, Color c, boolean filled) {
this.start = start;
this.width = width;
this.height = height;
this.c = c;
this.filled = filled;
}
#Override
public void paint(Graphics g) {
g.setColor(c);
if (filled) {
g.fillOval(start.x, start.y, width, height);
} else {
g.drawOval(start.x, start.y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
}
}