I can't translate points in my 3D graphics engine (java) - java

I'm following javidx9's tutorial on youtube about making a 3D graphics engine (I'm doing it in java, rather than C++, but I'm pretty closely following his steps), and I'm at the point where we move the cube away from the 'camera' to better see it (35:49, if you're curious), but as soon as I add the relevant lines of code and run it, nothing shows up. When I take them away, it comes back, and I have no idea what's happening. Code is below, sorry it's kind of long and probably poorly written (using Graphics2D for display):
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
static Frame frame;
static double FOV = Math.PI / 2;
static int w = 400;
static int h = 400;
static double a = h / w;
static double f = 1 / Math.tan(FOV / 2);
static double zFar = 1000;
static double zNear = 0.1;
static double q = zFar / (zFar - zNear);
static double[][] matProj = new double[4][4];
public static void main(String[] args) {
frame = new Frame();
}
static void draw() {
Mesh cubeMesh = new Mesh();
//south
cubeMesh.addTri(0, 0, 0, 0, 1, 0, 1, 1, 0);
cubeMesh.addTri(0, 0, 0, 1, 1, 0, 1, 0, 0);
//east
cubeMesh.addTri(1, 0, 0, 1, 1, 0, 1, 1, 1);
cubeMesh.addTri(1, 0, 0, 1, 1, 1, 1, 0, 1);
//north
cubeMesh.addTri(1, 0, 1, 1, 1, 1, 0, 1, 1);
cubeMesh.addTri(1, 0, 1, 0, 1, 1, 0, 0, 1);
//west
cubeMesh.addTri(0, 0, 1, 0, 1, 1, 0, 1, 0);
cubeMesh.addTri(0, 0, 1, 0, 1, 0, 0, 0, 0);
//top
cubeMesh.addTri(0, 1, 0, 0, 1, 1, 1, 1, 1);
cubeMesh.addTri(0, 1, 0, 1, 1, 1, 1, 1, 0);
//bottom
cubeMesh.addTri(1, 0, 1, 0, 0, 1, 0, 0, 0);
cubeMesh.addTri(1, 0, 1, 0, 0, 0, 1, 0, 0);
matProj[0][0] = a * f;
matProj[1][1] = f;
matProj[2][2] = q;
matProj[3][2] = -1 * q * zNear;
matProj[2][3] = 1;
matProj[3][3] = 0;
frame.graphics.g2D.setColor(Color.WHITE);
frame.graphics.g2D.setStroke(new BasicStroke(2));
for(TrianglePoints i : cubeMesh.triangles) {
TrianglePoints translated = i;
translated.p1[2] = i.p1[2] + 3; //when I comment out these lines, it works, but then of course the cube isn't translated
translated.p2[2] = i.p2[2] + 3;
translated.p3[2] = i.p3[2] + 3;
int[] xPoints = {(int) MultiplyMatrixVector(translated.p1, matProj)[0], (int) MultiplyMatrixVector(translated.p2, matProj)[0], (int) MultiplyMatrixVector(translated.p3, matProj)[0]};
int[] yPoints = {(int) MultiplyMatrixVector(translated.p1, matProj)[1], (int) MultiplyMatrixVector(translated.p2, matProj)[1], (int) MultiplyMatrixVector(translated.p3, matProj)[1]};
for(int j = 0; j < xPoints.length; j++) {
xPoints[j] += 1;
xPoints[j] *= (0.5 * w);
yPoints[j] += 1;
yPoints[j] *= (0.5 * w);
}
frame.graphics.g2D.drawPolygon(xPoints, yPoints, 3);
}
}
private static double[] MultiplyMatrixVector(double[] i, double[][] m) {
double[] o = new double[3];
o[0] = i[0] * m[0][0] + i[1] * m[1][0] + i[2] * m[2][0] + m[3][0];
o[1] = i[0] * m[0][1] + i[1] * m[1][1] + i[2] * m[2][1] + m[3][1];
o[2] = i[0] * m[0][2] + i[1] * m[1][2] + i[2] * m[2][2] + m[3][2];
double w = i[0] * m[0][3] + i[1] * m[1][3] + i[2] * m[2][3] + m[3][3];
if(w != 0) { //I think this might be where the issue is, when I translate it w won't be 0, but I don't know how that would make it not work, I have to divide by w here.
o[0] /= w;
o[1] /= w;
o[2] /= w;
}
return o;
}
}
class Frame extends JFrame {
private static final long serialVersionUID = 1L;
GraphicsC graphics = new GraphicsC();
Frame(){
this.setSize(Main.w, Main.h);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(graphics);
this.setVisible(true);
}
}
class GraphicsC extends JPanel {
private static final long serialVersionUID = 1L;
Graphics2D g2D;
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLACK);
g2D = (Graphics2D) g;
Main.draw();
}
}
class TrianglePoints {
double[] p1 = new double[3];
double[] p2 = new double[3];
double[] p3 = new double[3];
TrianglePoints(double[] p1, double[] p2, double[] p3) {
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
}
class Mesh {
List<TrianglePoints> triangles = new ArrayList<TrianglePoints>();
void addTri(double a, double b, double c, double d, double e, double f, double g, double h, double i) {
double[] p1 = {a, b, c};
double[] p2 = {d, e, f};
double[] p3 = {g, h, i};
triangles.add(new TrianglePoints(p1, p2, p3));
}
}

I highly suspect your issue to be that in C++, doing (timestamp)
triTranslated = tri;
will in fact make a copy of the triangle, whereas your code merely gets a reference, therefore your triangles drift away at pace of 3 units per render, likely vanishing out of view before you could see anything.

Related

How to draw a cube with a coordinate system in Swing

I have a cube and there is a need to add a 3D coordinate system to it.
There is an example my coordinate system with a cube should approximtely look like:
Unfortunately, my progress seems so far from this example:
Maybe, I can find out how to draw X and Y axis, but I have no idea how to add the Z axis.
So, how to build the right coordinate sytem?
My code:
import java.awt.*;
import static java.lang.Math.*;
import javax.swing.*;
public class Cube extends JPanel {
double[][] nodes = {{-1, -1, -1}, {-1, -1, 1}, {-1, 1, -1}, {-1, 1, 1},
{1, -1, -1}, {1, -1, 1}, {1, 1, -1}, {1, 1, 1}};
int[][] edges = {{0, 1}, {1, 3}, {3, 2}, {2, 0}, {4, 5}, {5, 7}, {7, 6},
{6, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}};
public Cube() {
setPreferredSize(new Dimension(640, 640));
setBackground(Color.white);
scale(50);
rotateCube(Math.toRadians(60), Math.toRadians(10), Math.toRadians(0));
}
final void scale(double s) {
for (double[] node : nodes) {
node[0] *= s;
node[1] *= s;
node[2] *= s;
}
}
final void rotateCube(double angleX, double angleY, double angleZ) {
double sinX = sin(angleX);
double cosX = cos(angleX);
double sinY = sin(angleY);
double cosY = cos(angleY);
double sinZ = sin(angleZ);
double cosZ = cos(angleZ);
for (double[] node : nodes) {
double x = node[0];
double y = node[1];
double z = node[2];
node[0] = x * cosX - z * sinX;
node[2] = z * cosX + x * sinX;
z = node[2];
node[1] = y * cosY - z * sinY;
node[2] = y * sinY + z * cosY;
x = node[0];
y = node[1];
node[0] = x * cosZ + y * sinZ;
node[1] = y * cosZ - x * sinZ;
}
}
void drawCube(Graphics2D g) {
g.translate(getWidth() / 2, getHeight() / 2);
g.setColor(Color.BLACK);
for (int[] edge : edges) {
double[] xy1 = nodes[edge[0]];
double[] xy2 = nodes[edge[1]];
g.drawLine((int) round(xy1[0]), (int) round(xy1[1]),
(int) round(xy2[0]), (int) round(xy2[1]));
}
for (double[] node : nodes)
g.fillOval((int) round(node[0]) - 4, (int) round(node[1]) - 4, 8, 8);
}
void drawAxis(Graphics2D g) {
int x_c = getWidth() / 2;
int y_c = getHeight() / 2;
// X - axis
g.setColor(Color.green);
g.drawLine(round(x_c + 300), round(y_c), round(x_c), round(y_c));
// Y- axis
g.setColor(Color.blue);
g.drawLine(round(x_c), round(y_c), round(x_c), round(y_c) + 300);
}
#Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawAxis(g);
drawCube(g);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Rotating Cube");
f.setResizable(false);
f.add(new Cube(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}

How do I change the code to have it output the whole array instead of only the first line?

The output of the code at the moment is the rectangle design and the first line of the array repeated. The wanted output is the rectangle design and the whole array rather than just the first line.
public class design
{
public static void main (String[] args)
{
JFrame window = new JFrame ("Game Screen");
window.getContentPane ().add (new drawing ());
window.setSize (500, 500);
window.setVisible (true);
window.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
}
class drawing extends JComponent
{
public void paint (Graphics g)
{
int[] [] word = {{5, 3, 0, 0, 7, 0, 0, 0, 0},
{6, 0, 0, 1, 9, 5, 0, 0, 0},
{0, 9, 8, 0, 0, 0, 0, 6, 0},
{8, 0, 0, 0, 6, 0, 0, 0, 3},
{4, 0, 0, 8, 0, 3, 0, 0, 1},
{7, 0, 0, 0, 2, 0, 0, 0, 6},
{0, 6, 0, 0, 0, 0, 2, 8, 0},
{0, 0, 0, 4, 1, 9, 0, 0, 5},
{0, 0, 0, 0, 9, 0, 0, 7, 9}};
int r = 0;
int c = 0;
Graphics2D g2 = (Graphics2D) g;
Rectangle rect;
for (int x = 5 ; x < 450 ; x += 50)
{
for (int y = 5 ; y < 450 ; y += 50)
{
rect = new Rectangle (x, y, 50, 50);
g2.draw (rect);
g.drawString (Integer.toString (word [r] [c]), x + 25, y + 25);
}
c++;
if (c == 9)
{
c = 0;
r++;
}
}
rect = new Rectangle (150, 5, 150, 450);
g2.draw (rect);
rect = new Rectangle (5, 150, 450, 150);
g2.draw (rect);
}
}
Try to put r++; in the second for loop after calling g.drawString. r must also be set to 0 inside the first for loop and before entering the second one.
for (int x = 5 ; x < 450 ; x += 50){
r = 0;
for (int y = 5 ; y < 450 ; y += 50){
rect = new Rectangle (x, y, 50, 50);
g2.draw (rect);
g.drawString (Integer.toString (word [r] [c]), x + 25, y + 25);
r++;
}
c++;
}
It would be more readable (and logical in my opinion) to use only two variables for the loops, x and y in your case, and increment them only by one. You can use them to calculate the positions of your rectangles and place your numbers:
for (int x = 0 ; x < 9 ; x++){
for (int y = 0 ; y < 9 ; y++){
rect = new Rectangle (5+x*50, 5+y*50, 50, 50);
g2.draw (rect);
g.drawString (Integer.toString (word [y] [x]), 5+x*50 + 25, 5+y*50 + 25);
r++;
}
c++;
}
Avoid using magic numbers, it's better to define constant variables and give them an appropriate name. You can then easily change their values, and your code is clearer.
What are "magic numbers" in computer programming?
The issue with your logic is that increment of c doesn't follow increment of y(y-axis). i.e. as per your logic c represents y axis in your 2-dimensional array, but you are incrementing it in the for loop of x axis. Solution to this is, move your logic of c increment in inner for loop
for (int x = 5; x < 450; x += 50) {
for (int y = 5; y < 450; y += 50) {
rect = new Rectangle(x, y, 50, 50);
g2.draw(rect);
g.drawString(Integer.toString(word[r][c]), x + 25, y + 25);
c++;
}
if (c == 9) {
c = 0;
r++;
}
}
As your loop will only increment 9 times, moving of if condition along with c++ is not required.

Processing. Particle sytem - how to make particles come in one by one

I am trying to make my particle system generate particles one by one, rather than all at the same time. My code currently will generate all 100 particles instantly.
I have not tried much as I am new to coding.
I have a setup where I call and updated my particle class, and a class that has all my parameters of the particle system.
int num = 100;
Particle[] p = new Particle[num];
void setup() {
size(1080, 720);
colorMode(HSB);
for (int i = 0; i < num; i ++) {
p[i] = new Particle(new PVector(random(width), random(height)), 100, 150);
}
stroke(255);
}
void draw() {
background(0);
for (int i = 0; i < num; i ++) {
p[i].update(p, i);
}
}
class Particle {
PVector pos;
PVector vel;
float r, mr;
float spd = 0.1;
float max = 2;
Particle(PVector pos, float r, float mr) {
this.pos = pos;
this.r = r;
this.mr = mr;
vel = new PVector(random(-1, 1), random(-1, 1));
}
void update(Particle[] p, int i) {
float h = map(mouseX, 0, width, 0, 255);
pos.add(vel);
if (pos.x < -10) pos.x = width;
if (pos.x > width + 10) pos.x = 0;
if (pos.y < -10) pos.y = height;
if (pos.y > height + 10) pos.y = 0;
vel.x = constrain(vel.x + random(-spd, spd), -max, max);
vel.y = constrain(vel.y + random(-spd, spd), -max, max);
for (int j = i + 1; j < p.length; j ++) {
float ang = atan2(pos.y - p[j].pos.y, pos.x - p[j].pos.x);
float dist = pos.dist(p[j].pos);
if (dist < r) {
stroke(h, 255, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, p[j].pos.x, p[j].pos.y);
float force = map(dist, 0, r, 4, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
}
float ang = atan2(pos.y - mouseY, pos.x - mouseX);
float dist = pos.dist(new PVector(mouseX, mouseY));
if (dist < r) {
stroke(0, 0, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, mouseX, mouseY);
float force = map(dist, 0, r, 30, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
noStroke();
fill(h, 255, 255);
ellipse(pos.x, pos.y, 5, 5);
}
}
Create an ArrayList of particles, but don't add any particle in setup():
ArrayList<Particle> paticles = new ArrayList<Particle>();
void setup() {
size(400, 400);
colorMode(HSB);
stroke(255);
}
Consecutively add the particles in draw(). The function millis() is used to get the time since the program was started:
void draw() {
int num = 100;
int interval = 100; // 0.5 seconds
int time = millis(); // milliseconds since starting the program
if (paticles.size() < num && paticles.size()*interval+5000 < time) {
paticles.add(new Particle(new PVector(random(width), random(height)), 100, 150));
}
background(0);
for (int i = 0; i < paticles.size(); i ++) {
Particle p = paticles.get(i);
p.update(paticles, i);
}
}
Note, the class Particle has to be adapted, because it has to operate with the ArrayList of variable length rather than the array with fixed length:
class Particle {
PVector pos;
PVector vel;
float r, mr;
float spd = 0.1;
float max = 2;
Particle(PVector pos, float r, float mr) {
this.pos = pos;
this.r = r;
this.mr = mr;
vel = new PVector(random(-1, 1), random(-1, 1));
}
void update(ArrayList<Particle> paticles, int i) {
float h = map(mouseX, 0, width, 0, 255);
pos.add(vel);
if (pos.x < -10) pos.x = width;
if (pos.x > width + 10) pos.x = 0;
if (pos.y < -10) pos.y = height;
if (pos.y > height + 10) pos.y = 0;
vel.x = constrain(vel.x + random(-spd, spd), -max, max);
vel.y = constrain(vel.y + random(-spd, spd), -max, max);
for (int j = i + 1; j < paticles.size(); j ++) {
Particle pj = paticles.get(j);
float ang = atan2(pos.y - pj.pos.y, pos.x - pj.pos.x);
float dist = pos.dist(pj.pos);
if (dist < r) {
stroke(h, 255, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, pj.pos.x, pj.pos.y);
float force = map(dist, 0, r, 4, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
}
float ang = atan2(pos.y - mouseY, pos.x - mouseX);
float dist = pos.dist(new PVector(mouseX, mouseY));
if (dist < r) {
stroke(0, 0, map(dist, 0, r, 255, 0));
strokeWeight(map(dist, 0, r, 3, 0));
line(pos.x, pos.y, mouseX, mouseY);
float force = map(dist, 0, r, 30, 0);
vel.x += force * cos(ang);
vel.y += force * sin(ang);
}
noStroke();
fill(h, 255, 255);
ellipse(pos.x, pos.y, 5, 5);
}
}

cube shrinks successively, when i rotate it with mouse..

i write the following code for a cube, that rotates on mouse motion,
but when i rotate the cube, or resize the Frame, the cube shrinks successively.
Is this the code or Frame, that is to be changed..
Pls Help,,
public class Cube extends javax.swing.JPanel implements MouseMotionListener {
int node0[] = {-100, -100, -100};
int node1[] = {-100, -100, 100};
int node2[] = {-100, 100, -100};
int node3[] = {-100, 100, 100};
int node4[] = {100, -100, -100};
int node5[] = { 100, -100, 100};
int node6[] = {100, 100, -100};
int node7[] = {100, 100, 100};
int nodes[][] = {node0, node1, node2, node3, node4, node5, node6, node7};
int edge0[] = {0, 1};
int edge1[] = {1, 3};
int edge2[] = {3, 2};
int edge3[] = {2, 0};
int edge4[] = {4, 5};
int edge5[] = {5, 7};
int edge6[] = {7, 6};
int edge7[] = {6, 4};
int edge8[] = {0, 4};
int edge9[] = {1, 5};
int edge10[] = {2, 6};
int edge11[] = {3, 7};
int edges[][] = {edge0, edge1, edge2, edge3, edge4, edge5, edge6, edge7, edge8, edge9, edge10, edge11};
// Rotate shape around the z-axis
public void rotateZ3D(int theta) {
double sinTheta = Math.sin(theta);
double cosTheta = Math.cos(theta);
for (int n=0; n<8; n++) {
int[] node = nodes[n];
int x = node[0];
int y = node[1];
node[0] = (int) (x * cosTheta - y * sinTheta);
node[1] = (int) (y * cosTheta + x * sinTheta);
}
};
public void rotateX3D(int theta) {
double sinTheta = Math.sin(theta);
double cosTheta = Math.cos(theta);
for (int n=0; n<8; n++) {
int[] node = nodes[n];
int y = node[1];
int z = node[2];
node[1] = (int) (y * cosTheta - z * sinTheta);
node[2] = (int) (z * cosTheta + y * sinTheta);
}
};
public void rotateY3D(int theta) {
double sinTheta = Math.sin(theta);
double cosTheta = Math.cos(theta);
for (int n=0; n<8; n++) {
int[] node = nodes[n];
int x = node[0];
int z = node[2];
node[0] = (int) (x * cosTheta - z * sinTheta);
node[2] = (int) (z * cosTheta + x * sinTheta);
}
};
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw edges
g.translate(150, 150);
rotateZ3D(60);
rotateY3D(60);
rotateX3D(60);
for (int e=0; e<12; e++) {
int n0 = edges[e][0];
int n1 = edges[e][1];
int node0[] = nodes[n0];
int node1[] = nodes[n1];
g.drawLine(node0[0], node0[1], node1[0], node1[1]);
}
// Draw nodes
for (int n=0; n<8; n++) {
int node[] = nodes[n];
g.drawOval(node[0], node[1], 5,5);
g.drawString(n+"", node[0], node[1]);
}
};
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
JFrame j = new JFrame();
Cube p = new Cube();
j.add(p);
j.addMouseMotionListener(p);
j.setSize(500,500);
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.show();
// TODO code application logic here
}
#Override
public void mouseDragged(MouseEvent me) {
int x0 = me.getX();
int y0 = me.getY();
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
Logger.getLogger(Cube.class.getName()).log(Level.SEVERE, null, ex);
}
int x1 = me.getX();
int y1 = me.getX();
rotateY3D(x1 - x0);
rotateX3D(y1 - y0);
repaint();
}
#Override
public void mouseMoved(MouseEvent me) {
}
}
suggest the solution code for it..
It's working fine , except that the cube is shrinking
You're storing the coordinates as ints.
Each time you do a rotation, you do a calculation which doesn't yield an integer; when you cast, you truncate the integer, rounding towards zero. Hence the shrinkage.
Use double instead, or, better, simply calculate a rotation matrix and apply that to the coordinates when you are rendering it.

Repaint() not called

I'm developing a game for a school project, a Bomberman-like game.
I'm using swing and I was using Canvas to draw my graphics but the KeyListener was not working, so I quitted using Canvas and started using paintComponent(Graphics g). The KeyListener is responding now, but my graphics don't refresh when my while loop calls the repaint() methods.
My code:
dispose();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
board b = new board();
b.setSize(630, 650);
b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.setVisible(true);
direction dessin = new direction();
b.add(dessin);
b.setVisible(true);
dessin.setBackground(Color.BLACK);
}
});
Then:
package Bm;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import javax.swing.JComponent;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class direction extends JPanel implements Runnable {
static float bmx = 35;
static float bmy = 35;
static float ex = 520;
static float ey = 520;
static float v = 0.03f;
static boolean gauche;
static boolean droite;
static boolean haut;
static boolean bas;
static void movEnnemi() {
int r = 1 + (int) (Math.random() * ((4 - 1) + 1));
Ennemi.droite = false;
Ennemi.gauche = false;
Ennemi.bas = false;
Ennemi.haut = false;
switch (r) {
case 1:
Ennemi.droite = true;
break;
case 2:
Ennemi.gauche = true;
break;
case 3:
Ennemi.bas = true;
break;
case 4:
Ennemi.haut = true;
break;
}
try {
Thread.sleep(5);
} catch (Exception e) {
}
;
}
public direction() {
super();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int ligne = 0; ligne < board.gridHauteur; ligne++) {
for (int colonne = 0; colonne < board.gridLargeur; colonne++) {
switch (board.plateau1[ligne][colonne]) {
case 0:
g.setColor(Color.lightGray);
g.fillRect(30 * ligne, 30 * colonne, 30, 30);
break;
case 1:
g.setColor(Color.black);
g.fillRect(30 * ligne, 30 * colonne, 30, 30);
board.plateau1[ligne][colonne] = board.BLOCKED;
break;
case 2:
g.setColor(Color.darkGray);
g.fillRect(30 * ligne, 30 * colonne, 30, 30);
board.plateau1[ligne][colonne] = board.BLOCKED;
break;
}
}
}
g.setColor(Color.blue);
g.fillRect((int) ex, (int) ey, 20, 20);
g.setColor(Color.red);
g.fillRect((int) bmx, (int) bmy, 21, 21);
g.dispose();
}
public void run() {
long dernierTempsLoop = System.currentTimeMillis();
while (true) {
long delta = (System.currentTimeMillis() - dernierTempsLoop);
dernierTempsLoop = System.currentTimeMillis();
movEnnemi();
for (int i = 0; i < delta / 5; i++) {
logic(5);
Ennemi.logic(5);
}
if ((delta % 5) != 0) {
logic(delta % 5);
Ennemi.logic(delta % 5);
}
System.out.println((int) (bmx / 30) + " - " + (int) (bmy / 30));
try {
Thread.sleep(20);
} catch (Exception e) {
}
;
repaint(); // <== HERE
}
}
public static void logic(long delta) {
float dx = 0;
float dy = 0;
if (gauche) {
dx--;
}
if (droite) {
dx++;
}
if (haut) {
dy--;
}
if (bas) {
dy++;
}
if ((dx != 0) || (dy != 0)) {
joueur.mouvement(dx * delta * v, dy * delta * v);
if (joueur.mouvement((dx * delta * v), (dy * delta * v)) == false) {
if (joueur.mouvement(0, dy * delta * v)) {
joueur.mouvement(0, dy * delta * v);
}
if (joueur.mouvement(dx * delta * v, 0)) {
joueur.mouvement(dx * delta * v, 0);
}
}
}
}
}
And :
package Bm;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import javax.swing.*;
#SuppressWarnings("serial")
class board extends JFrame implements KeyListener {
static JPanel p;
public Timer fpstimer;
public direction g;
static final int BLOCKED = 1;
static int gridLargeur = 21;
static int gridHauteur = 21;
int fenLargeur = 630;
int fenHauteur = 650;
public static int plateau1[][] = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
public board() {
super("Bomberman");
g = new direction();
addKeyListener(this);
threadLoop p = new threadLoop("loop");
p.start();
}
public static boolean blocked(double d, double e) {
return plateau1[(int) d][(int) e] == BLOCKED;
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
direction.gauche = true;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
direction.droite = true;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
direction.bas = true;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
direction.haut = true;
}
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
System.exit(0);
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
direction.gauche = false;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
direction.droite = false;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
direction.bas = false;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
direction.haut = false;
}
}
public void keyTyped(KeyEvent e) {
}
}
class threadLoop extends Thread {
public direction g;
threadLoop(String name) {
super(name);
}
public void run() {
g = new direction();
g.run();
}
}
public class Jouer {
}
I hope you understand my problem, and will be able to help me, thank you :)
You are creating different instances of your class direction, hence the issue you are seeing
You should not use static like this. It goes against good OO-programming
Use Swing key-bindings instead of using KeyListener
Follow java naming conventions (your code is really hard to read for now): Classes start with an Upper case letter, methods and variables with a lower-case letter. Use CamelCase to concatenate words.
Don't extend when not needed (JFrame, Thread, etc...)
Try to separate the various concepts of your program (one part should be responsible for the display (displaying the board, the enemies, the player), another one to react on user input (left-key pressed, right-key pressed, etc...) and a third one to handle the logic of your game (player location, enemies location, the board, etc...)).
Here is a very lame attempt to explain those various advices:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Game {
private static final String ICON_URL = "http://images2.wikia.nocookie.net/__cb20100515002803/fanon/images/a/a2/Bomberman_sprite.png";
private static final int GRID_SIZE = 24;
private static final int SQUARE_SIZE = 30;
private JFrame frame;
private Board board;
private static class Board extends JPanel {
private int[][] grid;
private int playerX;
private int playerY;
private ImageIcon playerIcon;
public Board() throws MalformedURLException {
// Some code to generate a random pseudo-board
Random random = new Random();
grid = new int[GRID_SIZE][];
for (int i = 0; i < GRID_SIZE; i++) {
grid[i] = new int[GRID_SIZE];
for (int j = 0; j < GRID_SIZE; j++) {
int r = random.nextInt(10);
grid[i][j] = r > 8 ? 2 : r > 6 ? 1 : 0;
}
}
playerIcon = new ImageIcon(new URL(ICON_URL));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(GRID_SIZE * SQUARE_SIZE, GRID_SIZE * SQUARE_SIZE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// pseudo-board painting
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
switch (grid[i][j]) {
case 1:
g.setColor(Color.GREEN);
g.fillRect(i * SQUARE_SIZE, j * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE);
break;
case 2:
g.setColor(Color.RED);
g.fillRect(i * SQUARE_SIZE, j * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE);
break;
default:
break;
}
}
}
// Player painting
int x = playerX * SQUARE_SIZE + (SQUARE_SIZE - playerIcon.getIconWidth()) / 2;
int y = playerY * SQUARE_SIZE + (SQUARE_SIZE - playerIcon.getIconHeight()) / 2;
g.drawImage(playerIcon.getImage(), x, y, this);
}
public int getPlayerX() {
return playerX;
}
public int getPlayerY() {
return playerY;
}
public void setPlayerX(int playerX) {
if (playerX >= 0 && playerX < GRID_SIZE && grid[playerX][playerY] == 0) {
this.playerX = playerX;
repaint();
}
}
public void setPlayerY(int playerY) {
if (playerY >= 0 && playerY < GRID_SIZE && grid[playerX][playerY] == 0) {
this.playerY = playerY;
repaint();
}
}
}
private class MoveLeftAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
board.setPlayerX(board.getPlayerX() - 1);
}
}
private class MoveRightAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
board.setPlayerX(board.getPlayerX() + 1);
}
}
private class MoveUpAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
board.setPlayerY(board.getPlayerY() - 1);
}
}
private class MoveDownAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
board.setPlayerY(board.getPlayerY() + 1);
}
}
private class ExitAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
int i = JOptionPane.showConfirmDialog(board, "Are you sure you want to exit?");
if (i == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
}
protected void initUI() throws MalformedURLException {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
board = new Board();
board.setBackground(Color.BLACK);
board.registerKeyboardAction(new MoveLeftAction(), KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), JComponent.WHEN_FOCUSED);
board.registerKeyboardAction(new MoveRightAction(), KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), JComponent.WHEN_FOCUSED);
board.registerKeyboardAction(new MoveUpAction(), KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), JComponent.WHEN_FOCUSED);
board.registerKeyboardAction(new MoveDownAction(), KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), JComponent.WHEN_FOCUSED);
board.registerKeyboardAction(new ExitAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
frame.add(board);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new Game().initUI();
} catch (MalformedURLException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Could not load icon from Internet", "Unable to start", JOptionPane.ERROR_MESSAGE);
}
}
});
}
}
Please note that the display and the logic of the games are here completely intertwined, so I don't quite follow advice nr 6.
The direction you assign to the frame/board is not the same you a trying to paint to. You create a new reference in your main loop
I'd also suggest you use key bindings over key listeners
Updated
You construct a initial direction and then add that to the screen. This is actually what will be rendered.
direction dessin = new direction();
b.add(dessin);
But in your threadLoop you create a new (disconnected) direction and start trying to update it...
public void run() {
g = new direction();
g.run();
}
...this will never paint as it has no connection to the screen.
You also create a third reference in board...
g = new direction();
All these disconnected direction classes have no one to paint or communicate with each and are unnecessary.
I would create a single reference in board, add it to the frame and pass that reference to the threadLoop
Updated
You could take a look at this. It's a basic example demonstrating a simple threaded animation engine and key bindings for the movement of a game asset

Categories

Resources