I am new to libgdx.
This is what I know:
We can create a rectangular box with red color using this:
shapeRenderer.begin(ShapeType.FilledRectangle);
shapeRenderer.setColor(Color.RED);
shapeRenderer.filledRect(0, 0, 300, 20);
shapeRenderer.end();
What I want to know:
I want this rectangle to persist between different frames.what I want is to create a rectangle object, and increase its length after every 3 seconds or so.
How to do this esactly? as from what i gather, if i use this code in betwen batch.begin() and batch.end() of render, it will create a new box in every frame.
You could create an integer instance in your main class such as shape_length, and have it increase every every 3 second through storing a another variable that would be set to 0 after its accumulated delta time is more than or equal to 3 seconds.
//member functions
private int shape_length = 300;
private float total_time = 0f;
//inside render loop
public void render(float deltaTime){
total_time += deltaTime;
if(total_time >= 3.0f){
//add 1 to length every 3 seconds
shape_length += 1;
total_time = 0.f;
}
shapeRenderer.begin(ShapeType.FilledRectangle);
shapeRenderer.setColor(Color.RED);
shapeRenderer.filledRect(0, 0, shape_length, 20);
shapeRenderer.end();
//fun times here
}
Update: The author wanted a way to have the rectangle as a usable class and not something constantly drawn every frame, so here's an alternative solution:
What could work is that you create a class such as RectShape that could store relative information such as height, width, a Vector2 position, etc, and then have a method on your main class that would specifically render your RectShape as follows:
class RectShape {
private float width;
private float height;
private Vector2 pos;
private Color color;
public RectShape(float w, float h, Vector2 p){
width = w;
height = h;
pos = p;
}
public void increaseLength(){
width += 2.f;
}
//getters: getColor(), getPosition(), getWidth, getHeight()
}
Create a drawRectangle method that takes both the RectShape object and ShapeRenderer
public void drawRectangle(RectShape mainRect, ShapeRenderer renderer){
renderer.begin(ShapeType.FilledRectangle);
renderer.setColor(mainRect.getColor());
renderer.filledRect(mainRect.getPosition().x,mainRect.getPosition().y,mainRect.getWidth(),mainRect.getHeight());
Then, on your main file
//instantiate object
RectShape s = new RectShape(300.f,200.f,new Vector2(3,2));
//render loop
total_time += deltaTime;
if(total_time >= 3.0f){
//add 1 to length every 3 seconds
s.increaseLength();
total_time = 0.f;
}
shapeRenderer.begin();
drawRectangle(s,shapeRenderer);
shapeRenderer.end();
The box is redrawn every frame yes.
To increase the length (a.k.a width) of the rectangle over time you could work with a timer:
In your game class have a variable for length
int rectWidth = 300;
int counter = 0; // And a counter
In your update(float delta) method you can now modify the width of the rectangle.
If your games runs at 60 Frames per second ** , the render method is called 60times/second. So to update the width of the rectangle every 3 seconds do:
public void update(float delta) {
if(counter > 60 * 3) {
rectWidth++;
counter = 0;
}
}
public void render() {
[...]
shapeRenderer.filledRect(0, 0, rectWidth, 20);
[...]
counter++;
}
There are better methods to do time dependent tasks but this should give you a starting point.
** You can define the framerate by setting ForegroundFPS
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.foregroundFPS = 60;
In order to increase the rectangles length you need to replace the 300 and 20 with variables.
shapeRenderer.filledRect(0, 0, 300, 20);
should be
shapeRenderer.filledRect(0, 0, rWidth, rHeight);
Then declare those variables in your class
int rWidth,rHeight;
and put this in your default constructor
rWidth=300;
rHeight=20;
Then in your render class you will have a seperate method in the beginning of it that will increase the rWidth and rHeight. To make it grow very quickly you can just put this in the top of your render method.
rWidth++;
rHeight++;
try this for now so you get the idea then you can use Gdx.graphics.getDeltaTime() to adjust it based on time rather than rendering frames.
Related
When I run this app, it's a little bit shaking. I can't understand, why that happens? What I should to do to circle's pixels don't shake?
public class Main extends ApplicationAdapter {
ShapeRenderer shapeRenderer;
float x,y;
#Override
public void create() {
shapeRenderer = new ShapeRenderer();
x = Gdx.graphics.getWidth() / 2;
y = Gdx.graphics.getHeight() / 2;
}
#Override
public void render() {
//Gdx.gl.glClearColor(0, 0, 0, 1);
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(1, 0, 0, 1);
shapeRenderer.circle(x++, y, 100);
shapeRenderer.end();
}
#Override
public void dispose() {
shapeRenderer.dispose();
}
}
Your render is not being called with the same delta(time interval) between frames causing the perceived speed to judder. Normally with LibGDX the render method is called with the delta i.e. the time since the last render, however, you are using the ApplicationAdapter.
You can compensate though by just getting the delta time yourself and changing your increment from
shapeRenderer.circle(x++, y, 100);
to
x=x+ (Gdx.graphics.getDeltaTime()* incrementConstant);
Adjust the float incrementConstant as you like for speed.
Read this excellent article on adjusting for irregular time steps in games.
https://gafferongames.com/post/fix_your_timestep/
I have a large set of data I wish to plot on a graph that can range from 10k points to about 20 Million Points. At 10k points the plot happens at an ok speed(within a second), but at 20 Million points the plot seems to take minutes.
I'm using Java for the program and rewriting the code in another language just to improve the graphical plotting speed for one single plot that only occurs at at maximum data set is not in the cards.
Is this speed something I have to live with because a 20 Million point plot inherently will take this long due to the data size or am I missing out on some optimisation flag/method/etc?
My Data is in a 2d Array of 13,000 by 4096 called Data.
This is populated from outside the Plot Function in Main.java
//In Plot.java
public class PlotG extends JPanel
{
double xscale = 0.0;
double yscale = 0.0;
protected void paintComponent(Graphics g)
{
super.paintCompnent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHint.Key_ANTIALIASING, RenderingHint.VALUE_ANTIALIAS_ON);
//Scaling
int sizew = Data.size();
int sizeh = Data.get(0).size();
xscale = (getWidth()*1.0)/(sizew *1.0);
yscale = (getHeight()*1.0)/(sizeh *1.0);
//Set Colour
g2.setPaint(Color.GREEN);
//Plot
for(int j=0; j<sizew; j++)
{
for(int k=0;k<sizeh; k++)
{
if(Data.get(j).get(k) > MinimumValueToPlot) //I only plot points above the constant value MinimumValueToPlot
{
int x = xscale*j;
int y = yscale*k;
g2.fillOval(x,y,1,1);
}
}
}
return;
}
}
private Plot dataPlot = new Plot()
public PlotStuff(ArrayList<ArrayList<Double>> In)
{
Data = In;
InitPLot(getContentPane());
}
private void InitPlot(Container contentPane)
{
getContentPane().setBackground(Color.GRAY);
getContentPane().setLayout(new FlowLayout(FlowLayout.LEADING));
setMinimumSize(new Dimension(1650, 830));
pack();
GraphPanel = new JPanel();
GraphPanel.setBounds(6,11,1470,750);
GraphPanel.setBorder( BorderFactory.createTitleBorder( BorderFactory.createLineBorder(Color.GREEN, 2),
"Title",
TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION,
new Font("Tahoma", Font.BOLD, 18),
Color.WHITE));
getContentPanel().add(GraphPanel);
GraphPanel.setLayout(new BorderLayout());
dataPlot.setBackGround(Color.BLUE);
dataPlot.setForeGround(Color.WHITE);
dataPlot.setPreferredSize(new Dimension(1470, 750));
GraphPanel.add(dataPlot);
return;
}
//in Main.java
.
.
PlotStuff p = new PlotStuff(Data);
p.redrawGraph();
p.setVisible();
.
.
Is there anyway to improve the speed if the number of points above my constant MinimumValueToPlot reaches 20 Million and above? Given my maximum possible data set is 13k x 4096 = 53,248,000, it is possible, but the highest experienced number of points above MinimumValueToPlot is so far only 20 Million.
Am I doing something wrong in the JPanel declarations? I have seen some discussions say that setPreferredSize shouldn't be used? Is this the case?
Thanks.
You claim Data is a 2d array, but it is not. It is an ArrayList of ArrayLists. Work with an actual array instead.
Instead of ArrayList<ArrayList<Double>> you'd do double[][].
In your loop you are calling fillOval to set the color of a single pixel. That causes huge unneccessary overhead. You are basically telling your application to calculate the pixels for an oval shape of size 1x1 20 million times!
I suggest you create a BufferedImage, get its pixel array, and set the pixel values directly. Then, when done, draw that image to your Graphics2d object:
BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D imgGraphics2D = img.createGraphics();
imgGraphics2D.setColor(Color.white);
imgGraphics2D.fillRect(0, 0, getWidth(), getHeight());
imgGraphics2D.dispose();
byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
for(int j=0; j < sizew; j++)
{
for(int k=0; k < sizeh; k++)
{
if(data[j][k] > minimumValueToPlot)
{
int x = (int)(xscale * j);
int y = (int)(yscale * k);
int pixelindex = (y * getWidth() + x) * 3;
pixels[pixelindex + 1] = 255; // set the green byte
}
}
}
g2.setComposite(AlphaComposite.Src);
g2.drawImage(img, 0, 0, null);
Please take this with a grain of salt, as I wrote this from memory.
(Also I took the liberty of renaming Data to data and MinimumValueToPlot to minimumValueToPlot. Per convention variables in Java start with a lower case letter to distinguish them from classes.)
Plotting points like that in your paint components means that you paint that many points every time the component is repainted This means it is an expensive operation to resize the window, or click a button because it has to repaint every point.
In this version, I've made a method to redo the graphics, and and the paintComponent just repaints the backing buffer. Note, that painting to the backing buffer will be about as fast as you can accomplish paint, and it ignores the display properties of swing. That way you can use a profiler and see how fast you can make the painting routine go. For example using some of the suggestions of Max above.
public class PlotG extends JPanel
{
BufferedImage buffer;
double xscale = 0.0;
double yscale = 0.0;
public PlotG(){
buffer = new BufferedImage(1470, 750, BufferedImage.TYPE_INT_ARGB);
}
protected void paintComponent(Graphics g)
{
super.paintCompnent(g);
g.drawImage(buffer, 0, 0, this);
}
void updateBuffer(){
Graphics2D g2 = (Graphics2D)backing.getGraphics();
g2.setRenderingHint(RenderingHint.Key_ANTIALIASING, RenderingHint.VALUE_ANTIALIAS_ON);
//Scaling
int sizew = Data.size();
int sizeh = Data.get(0).size();
xscale = (getWidth()*1.0)/(sizew *1.0);
yscale = (getHeight()*1.0)/(sizeh *1.0);
//Set Colour
g2.setPaint(Color.GREEN);
//Plot
for(int j=0; j<sizew; j++)
{
for(int k=0;k<sizeh; k++)
{
if(Data.get(j).get(k) > MinimumValueToPlot) //I only plot points above the constant value MinimumValueToPlot
{
int x = xscale*j;
int y = yscale*k;
g2.fillOval(x,y,1,1);
}
}
}
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(buffer.getWidth(this), buffer.getHeight(this));
}
}
The problem with setPreferredSize, is not a performance issue, it can conflict with swings swings layout managers. When you have a component, such as your custom graphing panel, you do want to have it determine the size. I've added it to the PlotG class, so now it will try to layout according to the backing buffer.
The you have to update the buffer, I suggest doing it on the main thread after you've set your panel to visible. That way it won't block the edt.
I'm making simple spaceship game on JavaFX. I have class SpaceShip and i want to make random objects from this class in my main game loop on random starting position(in interval of 5 seconds for example). I try to use Timer schedule() method for the task. The problem is that i can't get clear image of the spaceship, it disappears and show in other point because of the constantly looping. Can someone help me with advice how to handle with this.
My game loop:
new AnimationTimer() {
#Override
public void handle(long currentNanoTime) {
double t = (currentNanoTime - startNanoTime) / 1000000000.0;
double xMoving = ((100 * t) % (canvas.getWidth() + 100));
double x = 232 + 128 * Math.cos(t);
double y = 232 + 128 * Math.sin(t);
//background image clears canvas
gc.drawImage(space, 0, 0);
gc.drawImage(earth, x, y);
gc.drawImage(sun, 196, 196);
// draw UFO
gc.drawImage(ufo.getFrame(t), 100, 25);
//draw spaceShip
SpaceShip.generate(new SpaceShip(spaceShipImageArr, 0.100, gc, t, xMoving - 100, (randomNum + 150)));
//timer schedule
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
SpaceShip.generate(new SpaceShip(spaceShipImageArr, 0.100, gc, t, xMoving - 100, (randomNum + 230)));
}
}, 5000);
}
}.start();
And the SpaceShip class:
package objectClasses;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
public class SpaceShip{
private final GraphicsContext gc;
private final double frame;
private final double y;
private final double x;
private AnimatedImage object;
public SpaceShip(Image[] arr, double duration, GraphicsContext gc, double frame, double x, double y) {
object = new AnimatedImage();
this.object.frames = arr;
this.object.duration = duration;
this.gc = gc;
this.frame = frame;
this.y = y;
this.x = x;
}
private void drawShip() {
this.gc.drawImage(this.object.getFrame(frame), x, y);
}
public static void generate(SpaceShip spaceShip) {
spaceShip.drawShip();
}
}
This is the culprit.
SpaceShip.generate(new SpaceShip(spaceShipImageArr, 0.100, gc, t, xMoving - 100, (randomNum + 150)));
Basically, in each frame you create a new instance of SpaceShip. The blinking images are caused by space ships being created over and over again. That won't work.
You need to create these objects outside the game loop and store their references:
SpaceShip mySpaceShip = new SpaceShip(spaceShipImageArr, 0.100, gc, t, xMoving - 100, (randomNum + 150));
In the game loop you just update the position of your actors (that part is missing) and keep drawing them at new positions.
SpaceShip.generate(mySpaceShip);
Side note: you can remove the generate method altogether, make drawShip public, rename it to draw and simply call mySpaceShip.draw() - it will be more evident what's the role of your methods. It's perfectly acceptable for an object to draw itself.
I am new to LWJGL but am slowly learning. I was wanting to make a square that rotated when you pressed the key. Like d rotates it 90 degrees as you can tell below, but when I use glRotatef(); it gives me an error and I don't know why. There error tells me I need to create a method for it, I know I don't need to though. Anything helps!
public class MainPlayer {
private Draw draw;
private int rotation;
private float WIDTH = (float) (Display.getWidth() * 0.1);
private float HEIGHT = (float) (WIDTH / 2);
private float x = Display.getWidth() / 2 - WIDTH / 2;
private float y = Display.getHeight() / 2 - HEIGHT / 2;
public MainPlayer(){
draw = new Draw(1.0f, 1.0f, 1.0f, WIDTH, HEIGHT);
}
public void update(){
}
public void render(){
glTranslatef(x, y, 0);
glRotatef(rotation,0,0,1);
draw.render();
}
public void getInput(){
if(Keyboard.isKeyDown(Keyboard.KEY_W)){
rotation = 0;
}
if(Keyboard.isKeyDown(Keyboard.KEY_S)){
rotation = 180;
}
if(Keyboard.isKeyDown(Keyboard.KEY_A)){
rotation = 270;
}
if(Keyboard.isKeyDown(Keyboard.KEY_D)){
rotation = 90;
}
}
}
You create an int rotation and I assume your render() loops the whole time, and you only set rotation in getInput().
So I am assuming that you should declare it as int rotation = 0.
glRotatef() is a OpenGL call to rotate objects, just like glTranslatef() moves them. glRotatef() does it in the same way.
glRotatef(AngleOfRotationf, 0, 1, 0) would rotate it horisontally, like in this video i just made: http://www.youtube.com/watch?v=SHsssrj9qr8& uses that line to rotate a ship.
Also in that video i demonstrated moving it with glTranslatef().
To use it you must use GL11.glRotatef(), or import static org.lwjgl.opengl.GL11.*;
That probably means that you haven't statically imported glRotatef
Either use
GL11.glRotatef(rotation, 0, 0, 1);
or import it at the beginning of your program with
import static org.lwjgl.opengl.GL11.glRotatef
I'm trying to build a pyramid in Java using GRect. I use getWidth() to position the pyramid in the center of the canvas but it tends to trip the left part of pyramid.
I'm learning programming through CS106A and using Java 1.6 so tried to get some other peoples code and they too showed the same bug. I tried to draw a simple rect and it works fine.
Is it some issue with Java applet as it tends to ignore getWidth() value at all. I used println(); to get getWidth() value and it works.
import acm.graphics.GRect;
import acm.program.GraphicsProgram;
public class Pyramid extends GraphicsProgram {
/**
* eclipse generated SVUID
*/
private static final long serialVersionUID = 5703830460071233096L;
/** Width of each brick in pixels */
private static final int BRICK_WIDTH = 30;
/** Width of each brick in pixels */
private static final int BRICK_HEIGHT = 12;
/** Number of bricks in the base of the pyramid */
private static final int BRICKS_IN_BASE = 14;
public void run() {
//centering the pyramid
int _canvasWidth = getWidth(); //canvas width
//println(_canvasWidth); //to check if getWidth returns a value
int _brickSpace = BRICKS_IN_BASE * BRICK_WIDTH; //space consumed by the base row
int _freeSpace = _canvasWidth - _brickSpace; //empty base level space
int _xOffset = _freeSpace / 2; //x for left most brick of base row
for(int row=0; row<BRICKS_IN_BASE; row++){ //the row number
int _rowTab = (BRICK_WIDTH/2) * row; //indentaion for each row
int _brickInRow = BRICKS_IN_BASE - row; //bricks as per row
for(int _brickNumber=0; _brickNumber<_brickInRow; _brickNumber++){ //placing bricks till _brickInRow
int x = (_xOffset + _rowTab) + (_brickNumber * BRICK_WIDTH);
int y = (BRICK_HEIGHT * (BRICKS_IN_BASE - row)); //y as per row num
GRect _brick = new GRect(x, y, BRICK_WIDTH, BRICK_HEIGHT); //creating brick instance
add(_brick);
}
}
}
}
I tried your code and it draws the pyramid at the centre at first, but the problem comes up when I resize the viewer window.
The point is Java applets have an inherited method called public void paint(Graphics g) that is called whenever the applet has to be painted. Resizing the viewer window is one of the cases that makes the paint method called.
So, to fix this you need to override the paint method, ie. add such a method:
public void paint(Graphics g) {
this.run();
super.paint(g);
}
This method will be called every time the window is resized. But remember you don't need multiple pyramids so add following line to your run method to remove all the previous bricks before adding the new ones.
removeAll();