Processing, redraw on mouse click within a class - java

I'm trying to make a simple click to change color in class draw. I tried to print the statement to see if it would re-draw but it's not re-drawing at all. The click works. Does anybody know why this is happening?
Here's the code so far.
Monster firstmonster;
Monster secondmonster;
void setup() {
size(600,400);
firstmonster = new Monster(100,200);
secondmonster = new Monster(300,200);
firstmonster.draw();
secondmonster.draw();
noLoop();
}
class Monster {
float xpos;
float ypos;
boolean isAngry;
int timeAngry;
Monster(float x, float y) {
xpos = x;
ypos = y;
isAngry = false;
timeAngry = 0;
}
void draw() {
if(isAngry = true && timeAngry<60){
print(int(timeAngry));
timeAngry=timeAngry+1;
rectMode(CENTER);
fill(127-timeAngry*5,0,0);
rect(xpos+100,ypos+100,20,100);
fill(255,200,200);
ellipse(xpos+100,ypos+70,60,60);
ellipse(xpos+81,ypos+70,16,32);
ellipse(xpos+119,ypos+70,16,32);
line(xpos+90,ypos+150,xpos+80,ypos+160);
line(xpos+110,ypos+150,xpos+120,ypos+160);
} else {
timeAngry = 0;
rectMode(CENTER);
print(int(timeAngry));
fill(127,0,0);
rect(xpos+100,ypos+100,20,100);
fill(255,200,200);
ellipse(xpos+100,ypos+70,60,60);
ellipse(xpos+81,ypos+70,16,32);
ellipse(xpos+119,ypos+70,16,32);
line(xpos+90,ypos+150,xpos+80,ypos+160);
line(xpos+110,ypos+150,xpos+120,ypos+160);
}
}
void mousePressed(){
poke();
}
void poke(){
isAngry = true;
print(timeAngry);
timeAngry=timeAngry+1;
redraw();
}
}
void mousePressed(){
firstmonster.mousePressed();
}
Also I can't seem to make the two models differentiate. If I put firstmonster.poke() then both the first and second model color change.

You don't have a global void draw() { .. } in your code, so there is nothing for redraw to trigger. Move code that should be draw as part of a frame out of setup(). Setup is for, unsurprisingly, one time setup code.
void setup() {
size(600,400);
firstmonster = new Monster(100,200);
secondmonster = new Monster(300,200);
noLoop();
}
void draw() {
firstmonster.draw();
secondmonster.draw();
}
Should do the trick.

Related

Custom Java game engine is rendering spaces between tiles when the character moves

So I've been trying to figure out what's wrong with my code, but I've had basically no luck when it comes to finding what's wrong. I've seen plenty of folks who had similar issues but none of the fixes that were suggested helped with my problem.
I've made a video showcasing my problem, but I'll give an explanation here too: whenever I move on the screen, the tiles in my game engine don't sync up with each other in terms of positioning, and it seems to be only on the rendering end. When I do any sort of checks to see if the distance between two tiles changes, I don't get any sort of errors. I get these gaps between the tiles specifically when I'm moving up or left, and they instead merge slightly when I move down or right, as if some of the tiles are updating faster than the others.
I don't want to just start dumping my couple thousand lines of code here since that won't really help anyone, but I'm also not well versed in the game development world, so I'm not entirely sure what pieces of code are super relevant here. If there's anything that y'all would like to see, let me know and I'll happily provide it.
The main method and postInit looks like this:
public static void main (String[] args)
{
EventQueue.invokeLater(() ->{
ex = new ShootyGame();
ex.dispose();
ex.setLayout(null);
ex.setUndecorated(Settings.isFullscreen);
ex.setVisible(true);
ex.setCursor(ex.getToolkit().createCustomCursor(
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), new Point(), null)); //hides the system cursor
ex.createBufferStrategy(2);
postInit();
});
}
private static void postInit()
{
//add a window listener to the main JFrame
ex.addWindowListener(new WindowAdapter()
{
/**
* Autosaves when the window is closed, then kills the game.
*/
#Override
public void windowClosing(WindowEvent e)
{
//TODO autosaving
kill();
}
});
render.start(); //these are just the two threads being started
run.start();
}
My two threads, which basically just run the step and render methods in my game class:
private static class Running extends Thread
{
boolean stop = false;
int fps = TickManager.fromFPS(Settings.FPS);
public void run()
{
while (!stop)
{
try
{
Running.sleep(fps);
}
catch(InterruptedException e)
{
System.err.println("B");
}
game.step();
}
}
}
private static class Render extends Thread
{
boolean stop = false;
int fps = TickManager.fromFPS(Settings.FPS);
public void run()
{
while (!stop)
{
try
{
Running.sleep(fps);
}
catch(InterruptedException e)
{
System.err.println("A");
}
game.render();
}
}
}
The run method in my Game class just calls the current character's step method (it'll call more later), which is what's directly used to move the Camera class' x and y position. The character step looks like this:
public void step()
{
this.calculateMove(); //gets info on which keys are being pressed, adds or subtracts an integer from dx and dy (which are also ints) based on which are being pressed
Game.cam.update(-this.dx, -this.dy); //sends the opposite movement to the camera
//change the position of the player character by the appropriate x and y amounts
this.changeX(this.dx);
this.changeY(this.dy);
this.reset(); //just sets dx and dy back to 0 after moving
}
And now to the rendering stuff here's the entire camera class since it's probably the most relevant class:
public class Camera
{
private int x;
private int y;
public Camera(int x, int y)
{
this.x = x;
this.y = y;
}
public void update(int dx, int dy)
{
moveX(dx);
moveY(dy);
}
public void moveX(int dx)
{
this.x += dx;
}
public void moveY(int dy)
{
this.y += dy;
}
/**
* Gets the top left corner of the camera's x position.
* #return The x position of the top left corner of the camera
*/
public int getCamX()
{
return this.x;
}
/**
* Gets the top left corner of the camera's y position.
* #return The y position of the top left corner of the camera
*/
public int getCamY()
{
return this.y;
}
}
And finally, the relevant code for the actual painting of the tiles:
public void render() //this is the part that the render thread calls initially
{
Toolkit.getDefaultToolkit().sync();
repaint();
}
public void paint(Graphics g) //the paint method, mostly handled in doDrawing
{
super.paint(g);
doDrawing(g);
}
private void doDrawing(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
//stuff that happens if the game isn't paused
if(!GameStates.isPaused)
{
currentMap.drawMap(g2d, this);
currentChar.draw(g2d, this);
}
}
public void drawMap(Graphics2D g2d, ImageObserver observer)
{
//for each tile in the map, call its draw method
for(int i = 0; i < this.tileArray.length; i++)
{
for(int j = 0; j < this.tileArray[0].length; j++)
{
this.tileArray[i][j].draw(g2d, observer);
}
}
}
public void draw(Graphics2D g2d, ImageObserver observer, BufferedImage image)
{
g2d.drawImage(image, this.getX() + Game.cam.getCamX(), this.getY() + Game.cam.getCamY() observer);
}
Sorry for the long winded post, I've just tried everything I can think of (and that my Googling abilities can help me think of) and I'm throwing this out as a last-ditch effort before I just move to an actual game engine. I wanted to make my own engine from scratch for the sake of getting more experience in Java, but if I can't figure this out I'd rather just move to a proper engine and actually make a game. Any help is massively appreciated :)
EDIT: capitalization

Swing animation flickers and makes GUI slow to respond

I'm trying to write a simple program: a bouncing ball that appears and starts bouncing after you press the "Start" button on the screen. The program should be closed by pressing "X".
For some reason, it runs very slowly. The ball is blinking, and I have to wait for a long time after I press the "X" for program to close.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class Bounce
{
public static void main(String[] args)
{
JFrame frame = new BounceFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
class BounceFrame extends JFrame
{
public BounceFrame()
{
setSize(WIDTH, HEIGHT);
setTitle("Bounce");
Container contentPane = getContentPane();
canvas = new BallCanvas();
contentPane.add(canvas, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
addButton(buttonPanel, "Start", new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
addBall();
}
});
contentPane.add(buttonPanel, BorderLayout.SOUTH);
}
public void addButton(Container c, String title, ActionListener listener)
{
JButton button = new JButton(title);
c.add(button);
button.addActionListener(listener);
}
public void addBall()
{
try
{
Ball b = new Ball(canvas);
canvas.add(b);
for (int i = 1; i <= 10000; i++)
{
b.move();
Thread.sleep(10);
}
}
catch (InterruptedException exception)
{
}
}
private BallCanvas canvas;
public static final int WIDTH = 300;
public static final int HEIGHT = 200;
}
class BallCanvas extends JPanel
{
public void add(Ball b)
{
balls.add(b);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (int i = 0; i < balls.size(); i++)
{
Ball b = (Ball)balls.get(i);
b.draw(g2);
}
}
private ArrayList balls = new ArrayList();
}
class Ball
{
public Ball(Component c) { canvas = c; }
public void draw(Graphics2D g2)
{
g2.fill(new Ellipse2D.Double(x, y, XSIZE, YSIZE));
}
public void move()
{
x += dx;
y += dy;
if (x < 0)
{
x = 0;
dx = -dx;
}
if (x + XSIZE >= canvas.getWidth())
{
x = canvas.getWidth() - XSIZE;
dx = -dx;
}
if (y < 0)
{
y = 0;
dy = -dy;
}
if (y + YSIZE >= canvas.getHeight())
{
y = canvas.getHeight() - YSIZE;
dy = -dy;
}
canvas.paint(canvas.getGraphics());
}
private Component canvas;
private static final int XSIZE = 15;
private static final int YSIZE = 15;
private int x = 0;
private int y = 0;
private int dx = 2;
private int dy = 2;
}
The slowness comes from two related problems, one simple and one more complex.
Problem #1: paint vs. repaint
From the
JComponent.paint docs:
Invoked by Swing to draw components.
Applications should not invoke paint directly, but should instead use the repaint method to schedule the component for redrawing.
So the canvas.paint() line at the end of Ball.move must go.
You want to call
Component.repaint
instead...
but just replacing the paint with repaint will reveal the second problem, which prevents the ball from even appearing.
Problem #2: Animating inside the ActionListener
The ideal ActionListener.actionPerformed method changes the program's state and returns as soon as possible, using lazy methods like repaint to let Swing schedule the actual work for whenever it's most convenient.
In contrast, your program does basically everything inside the actionPerformed method, including all the animation.
Solution: A Game Loop
A much more typical structure is to start a
javax.swing.Timer
when your GUI starts, and just let it run
"forever",
updating your simulation's state every tick of the clock.
public BounceFrame()
{
// Original code here.
// Then add:
new javax.swing.Timer(
10, // Your timeout from `addBall`.
new ActionListener()
{
public void actionPerformed(final ActionEvent ae)
{
canvas.moveBalls(); // See below for this method.
}
}
).start();
}
In your case, the most important
(and completely missing)
state is the
"Have we started yet?"
bit, which can be stored as a boolean in BallCanvas.
That's the class that should do all the animating, since it also owns the canvas and all the balls.
BallCanvas gains one field, isRunning:
private boolean isRunning = false; // new field
// Added generic type to `balls` --- see below.
private java.util.List<Ball> balls = new ArrayList<Ball>();
...and a setter method:
public void setRunning(boolean state)
{
this.isRunning = state;
}
Finally, BallCanvas.moveBalls is the new
"update all the things"
method called by the Timer:
public void moveBalls()
{
if (! this.isRunning)
{
return;
}
for (final Ball b : balls)
{
// Remember, `move` no longer calls `paint`... It just
// updates some numbers.
b.move();
}
// Now that the visible state has changed, ask Swing to
// schedule repainting the panel.
repaint();
}
(Note how much simpler iterating over the balls list is now that the list has a proper generic type.
The loop in paintComponent could be made just as straightforward.)
Now the BounceFrame.addBall method is easy:
public void addBall()
{
Ball b = new Ball(canvas);
canvas.add(b);
this.canvas.setRunning(true);
}
With this setup, each press of the space bar adds another ball to the simulation.
I was able to get over 100 balls bouncing around on my 2006 desktop without a hint of flicker.
Also, I could exit the application using the 'X' button or Alt-F4, neither of which responded in the original version.
If you find yourself needing more performance
(or if you just want a better understanding of how Swing painting works),
see
"Painting in AWT and Swing:
Good Painting Code Is the Key to App Performance"
by Amy Fowler.
I would suggest you to use 'Timer' class for running your gameloop.It runs infinitely and you can stop it whenever you want using timer.stop()
You can also set its speed accordingly.

Approach on exploding components in swing?

I'm working on the old multi-threaded bouncing balls problem in swing. I've got everything set up so far, but I'd like to add an explosion animation when two balls collide. I've got collision detection and I can display text where the collision took place, but I was wondering on the best modular approach to creating a small animation (for example, pixels exploding 360 degrees around the point, fading out over time)
Class structure:
Ball
public class Ball {
private double x,y,dx,dy;
private static final int XSIZE = 15;
private static final int YSIZE = 15;
public Ball(){
// make x,y,dx,dy random
}
public int getX(){//}
public int getY(){//}
public Point position(){
return new Point(x,y);
}
public void move(Rectangle2D bounds){
//do movement (change x,y,dx,dy)
}
public Ellipse2D getShape(){
return new Ellipse
}
public boolean collide(Ball other){
if (this.position().distance(other.position()) < XSIZE)
return true;
return false;
}
}
BallComponent
public class BallComponent extends JPanel {
public ArrayList<Ball> balls = new ArrayList<Ball>();
private ArrayList<Color> colors = new ArrayList<Color>();
private ArrayList<Point> explosions = new ArrayList<Point>();
Random rnd = new Random();
private boolean exploding = false;
public void add(Ball b) {
balls.add(b);
colors.add(new Color(rnd.nextFloat(),rnd.nextFloat(),rnd.nextFloat()));
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for(int i=0; i<balls.size(); i++){
for(int j=0; j<i; j++){
if (balls.get(i).collide(balls.get(j))){
exploding = true;
explosions.add(balls.get(i).position());
balls.remove(i);
colors.remove(i);
balls.remove(j);
colors.remove(j);
return;
}
}
g2.setColor(colors.get(i));
g2.fill(balls.get(i).getShape());
if (exploding){
for (Point p : explosions){
g2.drawString("boom", p.x, p.y);
}
}
}
}
public void reset(){
balls = new ArrayList<Ball>();
colors = new ArrayList<Color>();
explosions = new ArrayList<Point>();
}
}
Thanks in advance
One thing you must do is get program logic out of the painting method, here the paintComponent method. You have collision detection within this method, your removing logical items from collections from within this method, you're even returning out of the method before it has fully done its primary job -- which is drawing all the components.
Instead I suggest that you re-arrange your program more along M-V-C or Model-View-Controller lines where the state of the balls is held by the model classes, the game loop controlled by the controller class, where collision detection is done in the controller using the model's state, and where the GUI classes, the "view" holds no program logic whatsoever and simply displays the state of the model.

LibGDX Bouncing ball

I want to create an infinite bouncing ball. For now I'm just trying to make the bouncing on Y (up & down).
This is my GameWorld class, you can see there is a method collides to detect the collision but How to make that "circle" go up?
public class GameWorld {
private Circle rond;
private Rectangle rect;
public GameWorld(int midPointY) {
rond = new Circle(100, midPointY - 5, 5);
rect = new Rectangle(0, 200, Gdx.graphics.getWidth(), 5);
}
public void update(float delta) {
if(collides(rond)){
}else
rond.y++;
}
public boolean collides(Circle rond) {
if (rect.y < rond.y + (rond.radius)*2) {
return (Intersector.overlaps(rond, rect));
}
return false;
}
public Circle getRond() {
return rond;
}
public Rectangle getRect() {
return rect;
}
}
Of course, I have another class GameRenderer that rendere these two objects
Typically with any kind of physics you want to store the speed of an object as well as its position. That way, each time though your update loop you just have to change the y position by the y speed. When the collision occurs, all you need to do is calculate the new yspeed and update rond.
public void update(float delta) {
if(collides(rond)){
rond.yspeed = -rond.yspeed;
}else{
rond.y+=rond.yspeed*delta;
}
}

In my 2d game, the camera is moving 1 extra pixel each time the player is at the left or the right limit of the screen

Please excuse my bad english. I am having a problem while implementing a 2d camera. I made the camera to follow the player until it reaches near the edge of the game-level, where only the player moves and the camera stops. I made this easily but my problem is that the camera is not proper. The camera continues to move 1 extra pixel every time you reach at the edge of the game-level limit in all four directions (The code I posted only shows horizontal movement. This I did for simplicity). This means if you move 40 times to and fro near the left edge of the game, camera will move 40 extra pixels right! I have no idea how to solve this.
I posted a very simplified version from my original code below and made it as small as i could to show how the program works. Following just moves the player and camera horizontally across the screen.
This is 'theGamePanel' class (it is the main class) :-
public class TheGamePanel extends JPanel implements Runnable, KeyListener
{
private boolean left, right;
private float cameraX, cameraY;
private World world = new World();
private Player player = new Player();
public TheGamePanel()
{
//setting the size of panel
}
public static void main(String[] args)
{
//setting the window
}
public void paint(Graphics g)
{
super.paint(g);
// drawing the game-level and player
g.translate((int)cameraX, (int)cameraY);
world.paint(g);
player.paint(g);
g.translate(-(int)cameraX, -(int)cameraY);
}
public void upd()
{
player.update(left, right, this);
}
#Override
public void run()
{
// game-loop
}
#Override
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if(code == KeyEvent.VK_LEFT)
{
left = true;
}
if(code == KeyEvent.VK_RIGHT)
{
right = true;
}
}
#Override
public void keyReleased(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_LEFT)
{
left = false;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
{
right = false;
}
}
#Override
public void keyTyped(KeyEvent e)
{
}
//to set camera position
public void setCameraX(float cameraDx)
{
cameraX += cameraDx;
}
}
This is the 'Player' class. This class is where the player and camera movement takes place. The camera's x and values are then returned to 'TheGamePanel' :-
public class Player
{
private float x, y;
private float dx = 1;
private int width = 32, height = 32;
private float leftLimit, rightLimit;
public Player()
{
//player's initial x and y coordinates
x = 320;
y = 240;
//camera's limit (where the camera needs to stop following player)
leftLimit = x;
rightLimit = 960;
}
public void paint(Graphics g)
{
//for painting the player
g.setColor(Color.GREEN);
g.fillRect((int)x, (int)y, width, height);
}
//to move player and camera
public void update(boolean left, boolean right, TheGamePanel panel)
{
if(left == true)
{
x -= dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(dx);
}
}
if(right == true)
{
x += dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(-dx);
}
}
}
}
And lastly, the 'World' class. This class is used to simply paint a big map(level) in the background :-
public class World
{
private BufferedImage map;
private int tileWd = 32, tileHi = 32;
public World()
{
try
{
map = ImageIO.read(new File("map1.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void paint(Graphics g)
{
//simply paints a game-level in the background
}
}
If anything not understandable please tell. I will add more details.
Consider the case where the player is standing near the right edge of the map. One quick tap on the "right" key moves him out of the camera-follow area so the camera doesn't move. One quick tap on the "left" key moves him back into the camera-follow area. The camera will be moved "dx" units to the left. This will have the effect of the player slowly creeping closer to the right edge of the playing field, if I'm correct.
(To find bugs like this, I generally litter the code with System.out.println messages. If there's a lot of messages, I write them to a file and do text searches on keywords)
you have a location for your camera (cameraX,cameraY) but nothing for the player?
just create a location for player (playerX,playerY)
change the paint like:
public void paint(Graphics g)
{
super.paint(g);
// drawing the game-level and player
g.translate((int)cameraX, (int)cameraY);
world.paint(g);
g.translate((int)playerX, (int)playerY);
player.paint(g);
g.translate(-(int)(playerX+cameraX), -(int)(playerY+cameraY));
}
and when player come near borders don't move camera and only player.
I believe the following change fixes the problem:
Player class:
//to move player and camera
public void update(boolean left, boolean right, TheGamePanel panel)
{
if(left == true)
{
x -= dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(dx);
}
}
if(right == true)
{
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(-dx);
}
x += dx; // Only change: moved this line AFTER the if block
}
}
By testing x after changing it when moving left and before changing it when moving right you compensate for the error that was otherwise accumulating every time you reached one of the boundaries.
Anyway I suggest you to change your approach to the problem in order to make your code easier to maintain and more flexible. One way to do that is to calculate the camera position based on current player's position on every frame.
Note: The line g.translate(-(int)cameraX, -(int)cameraY); in the paint() method of TheGamePanel class is unnecessary once the method translate(int, int) is not incremental.
Regards

Categories