Hello and thank you for reading this. I am coding in java/LWJGL. My problem is that I keep getting a null pointer error with some code if I don't include this one thing. Basically there are 4 classes
A block class.
A blockGrid class
A blocktype class
And a boot class.
The boot class creates a display and in the game loop it runs the draw method that is inside the blockgrid class. To set where a block goes i would use the renderat(x,y) method inside the blockgrid method. The block class just creates a quad at a certain x,y.
Sorry if I'm not explaining good. Here is my code: This is where the error happens just read my comments to see where the error is.
// BlockGrid.java
package minecraft2d;
import java.io.File;
public class BlockGrid {
private Block[][] blocks = new Block[100][100];
public BlockGrid() {
for (int x = 0; x < 25 - 1; x++) {
for (int y = 0; y < 16 - 1; y++) {
blocks[x][y] = new Block(BlockType.AIR, -100, -100); //This is where my error happens! If I don't include this line i get a null pointer. Anything will help. I am really stuck and don't know whats happening
}
}
}
public void setAt(int x, int y, BlockType b) {
blocks[x][y] = new Block(b, x * 32, y * 32);
}
public void draw() {
for (int x = 0; x < 25 - 1; x++) {
for (int y = 0; y < 16 - 1; y++) {
blocks[x][y].draw();
}
}
}
}
The reason you get a NullPointerException when you don't have that line is that blocks[x][y] will be null for all x,y when draw() is called. draw() assumes you have valid Block objects because it's calling Block#draw.
Related
I'm working on a game, nothing serious, just for fun.
I wrote a class 'ImageBuilder' to help creating some images.
Everything works fine, except one thing.
I initialize a variabile like this:
// other stuff
m_tile = new ImageBuilder(TILE_SIZE, TILE_SIZE, BufferedImage.TYPE_INT_RGB).paint(0xff069dee).paintBorder(0xff4c4a4a, 1).build();
// other stuff
Then, in the rendering method, i have:
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
g.drawImage(m_tile, x * (TILE_SIZE + m_padding.x) + m_margin.x, y * (TILE_SIZE + m_padding.y) + m_margin.y, null);
}
}
Note: m_padding and m_margin are just two Vector2i
This draws on the screen a simple 16x16 table using that image, but the game is almost frozen, i can't get more than like 10 FPS.
I tried to creating the image without that class, by doing this (TILE_SIZE = 32):
m_tile = new BufferedImage(TILE_SIZE, TILE_SIZE, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < TILE_SIZE; x++) {
for (int y = 0; y < TILE_SIZE; y++) {
if (x == 0 || y == 0 || x + 1 == TILE_SIZE || y + 1 == TILE_SIZE)
m_tile.setRGB(x, y, 0x4c4a4a);
else
m_tile.setRGB(x, y, 0x069dee);
}
}
This time, i get 60 FPS.
I can't figure out with is the difference, i used to creating image using 'ImageBuilder' and all is fine, but not this time.
ImageBuilder class:
// Constructor
public ImageBuilder(int width, int height, int imageType) {
this.m_width = width;
this.m_height = height;
this.m_image = new BufferedImage(m_width, m_height, imageType);
this.m_pixels = ((DataBufferInt) m_image.getRaster().getDataBuffer()).getData();
this.m_image_type = imageType;
}
public ImageBuilder paint(int color) {
for (int i = 0; i < m_pixels.length; i++) m_pixels[i] = color;
return this;
}
public ImageBuilder paintBorder(int color, int stroke) {
for (int x = 0; x < m_width; x++) {
for (int y = 0; y < m_height; y++) {
if (x < stroke || y < stroke || x + stroke >= m_width || y + stroke >= m_height) {
m_pixels[x + y * m_width] = color;
}
}
}
return this;
}
public BufferedImage build() {
return m_image;
}
There are other methods, but i don't call them, so i don't think is necessary to write them
What am i doing wrong?
My guess is that the problem is your ImageBuilder accessing the backing data array of the data buffer:
this.m_pixels = ((DataBufferInt) m_image.getRaster().getDataBuffer()).getData();
Doing so, may (will) ruin the chances for this image being hardware accelerated. This is documented behaviour, from the getData() API doc:
Note that calling this method may cause this DataBuffer object to be incompatible with performance optimizations used by some implementations (such as caching an associated image in video memory).
You could probably get around this easily, by using a temporary image in your bilder, and returning a copy of the temp image from the build() method, that has not been "tampered" with.
For best performance, always using a compatible image (as in createCompatibleImage(), mentioned by #VGR in the comments) is a good idea too. This should ensure you have the fastest possible hardware blits.
(please don't mark this question as not clear, I spent a lot of time posting it ;) )
Okay, I am trying to make a simple 2d java game engine as a learning project, and part of it is rendering a filled polygon as a feature.
I am creating this algorithm my self, and I really can't figure out what I am doing wrong.
My though process is something like so:
Loop through every line, get the number of points in that line, then get the X location of every point in that line,
Then loop through the line again this time checking if the x in the loop is inside one of the lines in the points array, if so, draw it.
Disclaimer: the Polygon class is another type of mesh, and its draw method returns an int array with lines drawn through each vertex.
Disclaimer 2: I've tried other people's solutions but none really helped me and none really explained it properly (which is not the point in a learning project).
The draw methods are called one per frame.
FilledPolygon:
#Override
public int[] draw() {
int[] pixels = new Polygon(verts).draw();
int[] filled = new int[width * height];
for (int y = 0; y < height; y++) {
int count = 0;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
count++;
}
}
int[] points = new int[count];
int current = 0;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
points[current] = x;
current++;
}
}
if (count >= 2) {
int num = count;
if (count % 2 != 0)
num--;
for (int i = 0; i < num; i += 2) {
for (int x = points[i]; x < points[i+1]; x++) {
filled[x + y * width] = 0xffffffff;
}
}
}
}
return filled;
}
The Polygon class simply uses Bresenham's line algorithm and has nothing to do with the problem.
The game class:
#Override
public void load() {
obj = new EngineObject();
obj.addComponent(new MeshRenderer(new FilledPolygon(new int[][] {
{0,0},
{60, 0},
{0, 60},
{80, 50}
})));
((MeshRenderer)(obj.getComponent(MeshRenderer.class))).color = CYAN;
obj.transform.position.Y = 100;
}
The expected result is to get this shape filled up.(it was created using the polygon mesh):
The actual result of using the FilledPolygon mesh:
You code seems to have several problems and I will not focus on that.
Your approach based on drawing the outline then filling the "inside" runs cannot work in the general case because the outlines join at the vertices and intersections, and the alternation outside-edge-inside-edge-outside is broken, in an unrecoverable way (you can't know which segment to fill by just looking at a row).
You'd better use a standard polygon filling algorithm. You will find many descriptions on the Web.
For a simple but somewhat inefficient solution, work as follows:
process all lines between the minimum and maximum ordinates; let Y be the current ordinate;
loop on the edges;
assign every vertex a positive or negative sign if y ≥ Y or y < Y (mind the asymmetry !);
whenever the endpoints of an edge have a different sign, compute the intersection between the edge and the line;
you will get an even number of intersections; sort them horizontally;
draw between every other point.
You can get a more efficient solution by keeping a trace of which edges cross the current line, in a so-called "active list". Check the algorithms known as "scanline fill".
Note that you imply that pixels[] has the same width*height size as filled[]. Based on the mangled output, I would say that they are just not the same.
Otherwise if you just want to fill a scanline (assuming everything is convex), that code is overcomplicated, simply look for the endpoints and loop between them:
public int[] draw() {
int[] pixels = new Polygon(verts).draw();
int[] filled = new int[width * height];
for (int y = 0; y < height; y++) {
int left = -1;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
left = x;
break;
}
}
if (left >= 0) {
int right = left;
for (int x = width - 1; x > left; x--) {
if (pixels[x + y * width] == 0xffffffff) {
right = x;
break;
}
}
for (int x = left; x <= right; x++) {
filled[x + y * width] = 0xffffffff;
}
}
}
return filled;
}
However this kind of approach relies on having the entire polygon in the view, which may not always be the case in real life.
I am creating a 3D renderer in Java but I have a problem when trying to render the polygons with a solid color fill. It works perfectly fine but every so often it's tearing but I'm not sure whether it is because the algorithm is inefficient or if it's something else because it's only at the vertices's it is tearing. Here is a picture:
Wireframe:
You can see that near the vertices's or rather points of the polygons it tears. I'm storing the color of the pixels in a 2 dimensional array and then cycling through it and rendering them. It still tears even when I make the polygon's really small so I don't think it's a performance problem. I use the Bresham algorithm and store the pixels in a 2 dimensional array then in the polygon I get the pixels and make them into one big array which I cycle through down the y and then across the x until I hit a pixel. That is set as beginLine and then the last one is set as endLine. I then draw a line between the points.
public void render()
{
int tempPixels[][] = new int[(int) Math.max(vertex_1.getX(), Math.max(vertex_2.getX(), vertex_3.getX())) + 30][(int) Math.max(vertex_1.getY(), Math.max(vertex_2.getY(), vertex_3.getY())) + 30];
for (int x = 0; x < vector_1.getWidth(); x++)
{
for (int y = 0; y < vector_1.getHeight(); y++)
{
if (vector_1.getPixels()[x][y] == 1)
{
tempPixels[(int) (x + Math.min(vertex_1.getX(), vertex_2.getX()))][(int) (y + Math.min(vertex_1.getY(), vertex_2.getY()))] = 1;
}
}
}
for (int x = 0; x < vector_2.getWidth(); x++)
{
for (int y = 0; y < vector_2.getHeight(); y++)
{
if (vector_2.getPixels()[x][y] == 1)
{
tempPixels[(int) (x + Math.min(vertex_2.getX(), vertex_3.getX()))][(int) (y + Math.min(vertex_2.getY(), vertex_3.getY()))] = 1;
}
}
}
for (int x = 0; x < vector_3.getWidth(); x++)
{
for (int y = 0; y < vector_3.getHeight(); y++)
{
if (vector_3.getPixels()[x][y] == 1)
{
tempPixels[(int) (x + Math.min(vertex_3.getX(), vertex_1.getX()))][(int) (y + Math.min(vertex_3.getY(), vertex_1.getY()))] = 1;
}
}
}
for (int y = 0; y < (int) Math.max(vertex_1.getY(), Math.max(vertex_2.getY(), vertex_3.getY())) + 4; y++)
{
int beginLine = -1;
int endLine = -1;
for (int x = 0; x < (int) Math.max(vertex_1.getX(), Math.max(vertex_2.getX(), vertex_3.getX())) + 4; x++)
{
if (tempPixels[x][y] == 1)
{
if (beginLine == -1)
{
beginLine = x;
}
else
{
endLine = x;
}
}
}
for (int i = beginLine; i < endLine; i++)
{
pixels[i][y] = 1;
colors[i][y] = Color.PINK;
}
}
vector_1.render();
vector_2.render();
vector_3.render();
vertex_1.render();
vertex_2.render();
vertex_3.render();
}
So basically my questions are:
Is this algorithm inefficient, if so what would be a better way?
Why is it tearing near the vertices's only?
Out of the problem description one cannot conclude that the attached image does not show what you want. Technically, the pink zone could depict a set of triangles you have 'correctly' painted (i.e. exactly the way you intended to) :p You could mark the triangles that you intended to be in the image, as an update. I suspect there are 4 triangles, though there are more such possible combinations.
First of all, since the part that, for each y, determines the beginLine and endLine seems to be correct, you should probably iterate till endLine when drawing the associated vertical segment (and not till endLine-1).
But that is probably not the real problem. Try drawing one triangle at a time. If some triangles still render incorrectly also try to see what happens when you eliminate the last part (the one rendering the vectors and the vertices). Why this?! Considering your implementation, you expect just a segment on each y. The image you provided indicates that your implementation sometimes renders more than one segment. So the rendering of the vectors and the vertices might be incorrect, though rendering multiple 'not perfectly aligned' triangles could also cause it.
If this does not solve it either, there might be some small offset in between your triangles. Try to see why that is.
Related to efficiency, that is not at fault. Generally, efficiency and correctness are not related in this way.
EDIT
You should add endLine = x after beginLine = x. With your implementation if you only have one pixel on a vertical line you do not draw it (since endLine will stay -1). This is one way to correct this issue. Also check that beginLine is greater than -1 before starting drawing. And do not forget to iterate from beginLine to exactly endLine.
You can use the method fillPolygon.
Syntax
g.setColor(Color.*color you want*)
g.fillPolygon (new int[]{width Dimensions}, new int [] {Height Dimensions}, no. of co-ordinates);
Note: - The 1st Value is of right Co-Ordinate, 2nd is of mid point and the 3rd is of Left Co-Ordinate.
The final programming with class, variables and methods.
/*Import the following files: -*/
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.awt.Font;
public class Shapes extends JPanel
{
public Shapes()
{
this.addComponentListener(new ComponentListener(){
public void componentShown(ComponentEvent arg0) {
}
public void componentResized(ComponentEvent arg0) {
paintComponent(getGraphics());
}
public void componentMoved(ComponentEvent arg0) {
}
public void componentHidden(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
});
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.MAGENTA);
g.setColor(Color.BLUE);
g.fillPolygon (new int[]{250,135,10}, new int [] {160,15,160}, 3);
g.setFont(new Font("TimesRoman", Font.PLAIN, 35));
g.setColor(Color.GREEN);
g.drawString("Triangle", 75, 120);
}
public static void main(String[] args)
{
Shapes obj = new Shapes();
JFrame frame = new JFrame("Shapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(obj);
frame.setSize(600, 500);
frame.setVisible(true);
}
}
Ok so i am creating a Breakout game and i need to create a method that creates rectangle objects for each of the bricks so i can implement hit detection, i already have a method so the bricks can be drawn out like this:
public void drawBricks(Graphics g)
{
g.setColor(brickColor);
for(int i = 0; i<10; i++)
{
for(int a = 0; a<121; a+=30)
{
g.fillRect(x+(width*i)+(spacer*i), y +a, width, height);
// spacer = 10, x and y = 5, width = 50, height = 20, if you need this...
}
}
}
Now to the part I cant figure out. I want to create rectangle objects with the exact corresponding coordinates as drawn above and add them to an multidimensional array, but i need the y to start at 5 and increment by 30 for each row at a time. This is what i have so far:
* Also I'm not sure if this is actually possible or not so let me know if you have an idea for another way i could do it.
public void setBricks()
{
for(int i= 0; i<10;i++)
{
for(int a=0; a<5; a++)
{
bricks[i][a] = new Rectangle(x+(width*i)+(spacer*i), y +a, width, height);
} // any ideas how to get each y ^ coordinate equal to the one above
} // i need the int variables to stay at 10 and 5 because of the size of the array.
}
Well, if you want y to start at 5 and increment by 30, use 5+a*30 :
public void setBricks()
{
for(int i= 0; i<10;i++)
{
for(int a=0; a<5; a++)
{
bricks[i][a] = new Rectangle(x+(width*i)+(spacer*i), 5 + a*30, width, height);
}
}
}
Real quick question here. In an attempt to generate 20,000 random points, I wrote the following code:
import javax.swing.JApplet;
import java.awt.*;
public class Points extends JApplet {
int x, y;
public void paint (Graphics page) {
for (int i = 0; i < 20000; i++);
{
x = (int)(Math.random()*200);
y = (int)(Math.random()*200);
page.drawLine(x, y, x, y);
}
}
}
However, this resulted in only one point being (randomly) drawn. Can someone help me identify my mistake? Thank you in advance.
You have a semicolon just after your for. Erase it and your code will work.
for (int i = 0; i < 20000; i++) {
x = (int)(Math.random()*200);
y = (int)(Math.random()*200);
page.drawLine(x, y, x, y);
}
Further Explanation: When you use the semicolon after a for declaration, it will end the for statement, resulting in something like
for(int i = 0; i < 20000; i++) {
}
x = (int)(Math.random()*200);
//rest of the code...
That's why your code display only 1 point.