I am printing objects from an array outputting 8 image objects using a for loop, the code works without draw() method, but when I include it, only the background image is shown.
How do I call the draw method in the setup method to work?
public class FishPAppletTest {
private static PApplet processing; // PApplet object that represents the graphic interface of the JunglePark application
private static PImage backgroundImage; // PImage object that represents the background image
private static Fish[] fishes; // fishes object, reference to perfect size array storing fish objects in the fish tank. These fish can be of different species.
private static Random randGen; // Type random constructor when new, Generator of random numbers
public static void main(String[] args) {
Utility.startApplication();
System.out.println(fishes[0]); //null because it is not stored?
}
/**
* Defines the initial environment properties of this application
* #param processingObj a reference to the graphic display window of this application
*/
public static void setup(PApplet processing) { // PApplet is kept, processing is the variable as input
backgroundImage = processing.loadImage("images/background.png"); // loads image in background
fishes = new Fish[8];
processing.image(backgroundImage, processing.width / 2, processing.height /2); // draw background image
}
/**
* Draws and updates the application display window.
* This callback method called in an infinite loop.
*/
public static void draw() { // called by utility class
for (int i = 0; i < fishes.length; i++) {
fishes[i] = new Fish(processing, processing.width / 2, processing.height / 2);
randGen = new Random(); // WORKS UP
int x = randGen.nextInt(processing.width);
int y = randGen.nextInt(processing.height);
fishes[i] = new Fish(processing, x, y);
fishes[i].draw();
}
}
}
Without seeing what Utility and Fish do, it's hard to guess what the exact behaviour is.
If you're seing the background and not the fish it's likely setup() get's called, but not draw() for some reason.
Ideally you'd initialise the Fish instances once in setup() then re-use in draw() (otherwise you're instantiating multiple times per second).
I would try something simpler.
public class FishPAppletTest extends PApplet{
private PImage backgroundImage; // PImage object that represents the background image
private Fish[] fishes;
// fishes object, reference to perfect size array storing fish objects in the fish tank. These fish can be of different species.
public void setup() {
// wild guess about sketch dimensions
size(600, 600);
backgroundImage = loadImage("images/background.png");
//loads image in background
fishes = new Fish[8];
for (int i = 0; i < fishes.length; i++) {
fishes[i] = new Fish(this, width / 2, height / 2);
}
}
/**
* Draws and updates the application display window.
* This callback method called in an infinite loop.
*/
public void draw() {
image(backgroundImage, width / 2, height /2);
for (int i = 0; i < fishes.length; i++) {
// hopefully Fish has public x,y properties ?
fishes[i].x = (int)random(width);
fishes[i].y = (int)random(height);
fishes[i].draw();
}
}
// initialise PApplet (kicks off setup/draw Processing sketch lifecycle)
public static void main(String[] args) {
PApplet.main(FishPAppletTest.class.getCanonicalName());
}
}
and this is a placeholder class mimicking your structure a bit:
public class Fish{
private PAppet parent;
public float x, y;
public Fish(PApplet parent, float x, float y){
this.parent = parent;
this.x = x;
this.y = y;
}
public void draw(){
parent.ellipse(x, y, 20, 10);
}
}
Hopefully this helps restructure the program ?
The ingredients are there, the order was a bit off.
FWIW, this is the sketch version you can simply paste and run in the Processing IDE:
// PImage object that represents the background image
private PImage backgroundImage;
// fishes reference to perfect size array storing fish objects in the fish tank. These fish can be of different species.
private Fish[] fishes;
public void setup() {
size(600, 600);
//loads image in background
backgroundImage = loadImage("images/background.png");
fishes = new Fish[8];
// instantiate Fish once
for (int i = 0; i < fishes.length; i++) {
fishes[i] = new Fish(this, width / 2, height / 2);
}
}
/**
* Draws and updates the application display window.
* This callback method called in an infinite loop.
*/
public void draw() {
image(backgroundImage, 0, 0);
// reuse Fish instances
for (int i = 0; i < fishes.length; i++) {
// hopefully Fish has public x,y properties ?
fishes[i].x = (int)random(width);
fishes[i].y = (int)random(height);
fishes[i].draw();
}
}
public class Fish{
private PApplet parent;
public float x, y;
public Fish(PApplet parent, float x, float y){
this.parent = parent;
this.x = x;
this.y = y;
}
public void draw(){
parent.ellipse(x, y, 20, 10);
}
}
Related
I have some problem. I am learning to program games and I want to try to program some game on my own. But I hit a snag just at beginning. I have 2 classes. The main class (call Frame) is only for create game frame:
public class Frame extends JFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
Game game;
public Frame() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
game = new Game();
this.add(game.canvas);
this.pack();
this.setResizable(false);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Frame().setVisible(true);;
}
});
}
}
It goes correctly. But I have created a second class (call Game), that is supposed to provide game loop:
public class Game implements Runnable{
public Canvas canvas;
Thread thread;
BufferStrategy bs;
Graphics g;
//Variables for game loop
private int fps, timePerTick;
double now, lastTime;
private double delta;
Game(){
initVariables();
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(300, 300));
}
private void initVariables(){
//create and start thread
thread = new Thread(this);
thread.start();
}
private void tick(){
}
private void render(){
bs = canvas.getBufferStrategy();
if (bs == null){
canvas.createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
g.drawRect(0, 0, 50, 50);
bs.show();
g.dispose();
}
private void initRun(){
delta = 0;
lastTime = System.nanoTime();
fps = 30;
timePerTick = 1000000000/fps;
}
#Override
public void run() {
initRun();
int timer=0;
int ticks=0;
while(true){
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += (now - lastTime);
lastTime = now;
if(delta>=1){
tick();
render();
delta--;
ticks++;
}
if (timer>1000000000){
System.out.println("FPS: "+ticks);
timer = ticks = 0;
}
}
}
}
The problem was in value of variable call FPS. When I set FPS in method call initRun() to 10, everything goes correctly. (simply thanks to method run() program wrote "FPS: 60" every second, and in frame was draw a rectangle).
But when I set FPS to (for example) 30, there was the problem. There was exception call "Exception in thread "Thread-1" java.lang.IllegalStateException: Component must have a valid peer" in render() method, concretely at instruction "canvas.createBufferStrategy(3);".
(image of exception)
What can I do? Where is problem? I am not good in speaking english, so I don't understand this Exception and I don't know, what I can do...Please help me! Thanks.
I want to draw some balls and interact with them, but when I run my program I see my balls staying still and i get java.lang.NullPointerException error. Can u tell me what I'm doing wrong?
Main class:
public class Main extends JPanel {
// creating big ball
Big big = new Big(this);
// creating small balls
Small small_list = new Small(40);
// method for moving big ball
private void moveBig() throws InterruptedException{
big.move();
}
// same but small balls
private void moveSmall() throws InterruptedException{
// ERROR
small_list.move();
}
// paiting
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
big.paint(g2d);
big.paintLine(g2d);
small_list.paint(g2d);
}
public static void main(String[] args) throws InterruptedException {
// TODO code application logic here
JFrame window = new JFrame("test");
Main main = new Main();
window.add(main);
window.setSize(500,500);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while(true){
main.moveBig();
// ERROR
main.moveSmall();
main.repaint();
Thread.sleep(15);
}
}
}
Big ball class:
public class Big {
// coordinates of first apperence
int x = 200;
int y = 200;
int upAnddown = 1;
int leftAndright = 1;
private static final int sizeOfbig = 30;
// list to draw a line after ball
private List<Point> listofpoints = new ArrayList<>();
private Main main;
public Big(Main main){
this.main=main;
}
void move() throws InterruptedException{
if (x+upAnddown < 5) {
upAnddown=1;
}
if (x+upAnddown > main.getWidth()-14) {
upAnddown=-1;
}
if (y+leftAndright < 5) {
leftAndright=1;
}
if (y+leftAndright > main.getHeight()-14) {
leftAndright=-1;
}
(...)
Small ball class:
public class Small {
int x = 20;
int y=20;
private static final int sizeOfSmall = 10;
int upAnddown = 1;
int leftAndright = 1;
private Main main;
public Small(Main main){
this.main=main;
}
public Small(int j){
ArrayList<Small> my_array = new ArrayList<Small>(j);
for (int i = 0; i < my_array.size(); i++) {
i=j;
my_array.add(new Small(i));
}
}
void move() throws InterruptedException{
//////////////////////////////////////
if (x+upAnddown < 0) {
upAnddown=1;
}
// ERROR
if (x+upAnddown > main.getWidth()-30) {
upAnddown=-1;
}
if (y+leftAndright < 0) {
leftAndright=1;
}
if (y+leftAndright > main.getHeight()-30) {
leftAndright=-1;
}
(...)
ERROR:
Exception in thread "main" java.lang.NullPointerException
at test2.Small.move(Small.java:56)
at test2.Main.moveSmall(Main.java:34)
at test2.Main.main(Main.java:67)
The while(true) will take all UI thread time. You need to put it in a thread to avoid that.
That's why balls stay still.
new Thread(new Runnable(){
public void run(){
while(true) {
main.moveBig();
main.moveSmall();
main.repaint();
Thread.sleep(15);
}
}
}).Start();
The NullPointerException may be related to this issue, I'm not sure. I don't see anything else that could raise it.
how can I implement water 2D wave effect in JavaFX, I have image and want to when click on image a wave(or more) start expanding from that point, just like when we drop a piece rock into the calm water and we see the wave expanding.
This is a conversion of parts of old sun JavaFX 1 ripple generator to JavaFX 2.
It's not the most realistic water ripple effect, but maybe it's enough to get you started creating your own. You could add in a DisplacementMap effect to distort your image as a result of the "waves".
The code uses JavaFX animation timelines to generate expanding concentric circles that gradually fade away of time.
import javafx.animation.*;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.*;
import javafx.scene.shape.Circle;
import javafx.stage.*;
import javafx.util.Duration;
public class FishSim extends Application {
private static final Paint SCENE_FILL = new RadialGradient(
0, 0, 300, 300, 500, false, CycleMethod.NO_CYCLE,
FXCollections.observableArrayList(new Stop(0, Color.BLACK), new Stop(1, Color.BLUE))
);
#Override public void start(Stage stage) {
final RippleGenerator rippler = new RippleGenerator();
final Scene scene = new Scene(rippler, 600, 400, SCENE_FILL);
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.setGeneratorCenterX(event.getSceneX());
rippler.setGeneratorCenterY(event.getSceneY());
rippler.createRipple();
rippler.startGenerating();
}
});
scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.setGeneratorCenterX(event.getSceneX());
rippler.setGeneratorCenterY(event.getSceneY());
}
});
scene.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.stopGenerating();
}
});
stage.setTitle("Click, hold mouse button down and move around to create ripples");
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
/**
* Generates ripples on the screen every 0.5 seconds or whenever
* the createRipple method is called. Ripples grow and fade out
* over 3 seconds
*/
class RippleGenerator extends Group {
private class Ripple extends Circle {
Timeline animation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(radiusProperty(), 0)),
new KeyFrame(Duration.seconds(1), new KeyValue(opacityProperty(), 1)),
new KeyFrame(Duration.seconds(3), new KeyValue(radiusProperty(), 100)),
new KeyFrame(Duration.seconds(3), new KeyValue(opacityProperty(), 0))
);
private Ripple(double centerX, double centerY) {
super(centerX, centerY, 0, null);
setStroke(Color.rgb(200, 200, 255));
}
}
private double generatorCenterX = 100.0;
private double generatorCenterY = 100.0;
private Timeline generate = new Timeline(
new KeyFrame(Duration.seconds(0.5), new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
createRipple();
}
}
)
);
public RippleGenerator() {
generate.setCycleCount(Timeline.INDEFINITE);
}
public void createRipple() {
final Ripple ripple = new Ripple(generatorCenterX, generatorCenterY);
getChildren().add(ripple);
ripple.animation.play();
Timeline remover = new Timeline(
new KeyFrame(Duration.seconds(3), new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
getChildren().remove(ripple);
ripple.animation.stop();
}
})
);
remover.play();
}
public void startGenerating() {
generate.play();
}
public void stopGenerating() {
generate.stop();
}
public void setGeneratorCenterX(double generatorCenterX) {
this.generatorCenterX = generatorCenterX;
}
public void setGeneratorCenterY(double generatorCenterY) {
this.generatorCenterY = generatorCenterY;
}
}
The original JavaFX 1 fish simulator code that the conversion is based on came from a jfrog repository (which might no longer exist if you click it).
Robert Ladstätter created a 2D water effect sample animation for JavaFX 2 (using Scala). Roberts animation is like viewing the water from the side rather than above, but perhaps some of the concepts might help you.
In this tutorial you can find how to use custom GLSL/HLSL pixel shaders for JavaFX.
And the code for a simple distortion procedural wave in screenSpace in HLSL form:
uniform extern texture ScreenTexture;
sampler ScreenS = sampler_state
{
Texture = <ScreenTexture>;
};
float wave; // pi/.75 is a good default
float distortion; // 1 is a good default
float2 centerCoord; // 0.5,0.5 is the screen center
float4 PixelShader(float2 texCoord: TEXCOORD0) : COLOR
{
float2 distance = abs(texCoord - centerCoord);
float scalar = length(distance);
// invert the scale so 1 is centerpoint
scalar = abs(1 - scalar);
// calculate how far to distort for this pixel
float sinoffset = sin(wave / scalar);
sinoffset = clamp(sinoffset, 0, 1);
// calculate which direction to distort
float sinsign = cos(wave / scalar);
// reduce the distortion effect
sinoffset = sinoffset * distortion/32;
// pick a pixel on the screen for this pixel, based on
// the calculated offset and direction
float4 color = tex2D(ScreenS, texCoord+(sinoffset*sinsign));
return color;
}
technique
{
pass P0
{
PixelShader = compile ps_2_0 PixelShader();
}
}
I hope it helps.
I am trying to paint only one part of Image. The image human is 159x22 length.
In that image there is 8 human bodies (2 left, 2 right and etc.). If i try to set the Frame to humanSprite.setFrame(1); I will get an error since I specified in the Sprite constructor the size of an Image so there is only one frame.
Well I have tried to divide it by 8 and Ill getjava.lang.IllegalArgumentException`.
Here is the class :
package org.pack.rhynn;
import java.io.IOException;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import java.util.Random;
public class play extends GameCanvas implements Runnable{
int sleep = 30;
private Image map;
private Sprite mapSprite;
private Image human;
private Sprite humanSprite;
private int humanX = getWidth() /2;
private int humanY = getHeight() /2;
public play(){
super(false);
}
public void start(){
try {
map = Image.createImage("/mapas.png");
human = Image.createImage("/human.PNG");
} catch (IOException ioex) {
System.out.println(ioex);
}
mapSprite = new Sprite(map);
mapSprite.defineReferencePixel(100, 150);
mapSprite.setRefPixelPosition(0, 0);
humanSprite = new Sprite(human,159,22);
humanSprite.defineReferencePixel(1, 10);
humanSprite.setRefPixelPosition(humanX, humanY);
Thread thr = new Thread(this);
thr.start();
}
public void run(){
while(true){
updateScreen(getGraphics());
try{
Thread.sleep(sleep);
}catch(Exception e){}
}
}
private void createBackground(Graphics g){
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
}
private void updateScreen(Graphics g){
createBackground(g);
mapSprite.setRefPixelPosition(0, 0);
mapSprite.paint(g);
humanSprite.setRefPixelPosition(humanX, humanY);
humanSprite.setFrame(0);
humanSprite.setPosition(50,50);
humanSprite.paint(g);
flushGraphics();
}
}
The problem seems to be with your image. All frames must have the same width and height and the image final width and hight must be a multiple of them.
For example, let's say all your frames are in a single row. If the frame width is 19 and you have 8 frames, the final image width must be 152.
I want to show a progress bar indicating loading application at the beginning.
How can that be done? I have created a gauge but I think it cannot be implemented in LWUIT form..
Based on my comment, You can use progress bar. And also you can use slider component for instead of showing progress bar in LWUIT.
The best way is to use canvas. You can reuse the class in all your apps and it is very efficient. Create a class, say like a class named Splash:
public class Splash extends Canvas {
private final int height;
private final int width;
private int current = 0;
private final int factor;
private final Timer timer = new Timer();
Image AppLogo;
MayApp MIDlet;
/**
*
* #param mainMIDlet
*/
public Splash(MyApp mainMIDlet) {
this.MIDlet = mainMIDlet;
setFullScreenMode(true);
height = getHeight();
width = this.getWidth();
factor = width / 110;
repaint();
timer.schedule(new draw(), 1000, 01);
}
/**
*
* #param g
*/
protected void paint(Graphics g) {
try {//if you want to show your app logo on the splash screen
AppLogo = javax.microedition.lcdui.Image.createImage("/appLogo.png");
} catch (IOException io) {
}
g.drawImage(AppLogo, getWidth() / 2, getHeight() / 2, javax.microedition.lcdui.Graphics.VCENTER | javax.microedition.lcdui.Graphics.HCENTER);
g.setColor(255, 255, 255);
g.setColor(128, 128, 0);//the color for the loading bar
g.fillRect(30, (height / 2) + 100, current, 6);//the thickness of the loading bar, make it thicker by changing 6 to a higher number and vice versa
}
private class draw extends TimerTask {
public void run() {
current = current + factor;
if (current > width - 60) {
timer.cancel();
try {
//go back to your midlet or do something
} catch (IOException ex) {
}
} else {
repaint();
}
Runtime.getRuntime().gc();//cleanup after yourself
}
}
}
and in your MIDlet:
public class MyApp extends MIDlet {
Splash splashScreen = new Splash(this);
public MyApp(){
}
public void startApp(){
try{
Display.init(this);
javax.microedition.lcdui.Display.getDisplay(this).setCurrent(splashScreen);
//and some more stuff
} catch (IOException ex){}
}
//continue