I have an array of candy images which are randomly chosen. There are candies falling and I want to make a new one fall every 5 seconds, and I know I have to use millis() - but how would I implement it into my program? I tried using millis() like so:
int time = millis();
if (time<5*1000)
{
image(goodCandy[rand], randX, goodY, randCandyW, randCandyH);
goodY = goodY + (candySpeed * yDirCandy);
time = millis();
}
But it only appears for 5 seconds then goes away.
I also tried:
int time = millis();
if (millis() - time >= 5000)
{
image(goodCandy[rand], randX, goodY, randCandyW, randCandyH);
goodY = goodY + (candySpeed * yDirCandy);
time = millis();
}
But it didn't work.
Here's the simplified code:
PImage [] goodCandy = new PImage [3];
int candySpeed = 20;
int yDirCandy = 1;
int candyY = 10;
int candyX = 200;
int candyW = 187;
int candyH = 121;
int randCandyW = 100;
int randCandyH = 100;
int goodY = -200;
int rand=(int) (2*Math.random()) +1;
int randX = (int) (1500*Math.random())+20;
void setup() {
for (int i=0; i<goodCandy.length; i++) {
goodCandy[i] = loadImage("goodCandy" + i + ".png");
}
void draw() {
if (current=="play") {
loadStuff();
}
}
void loadStuff() {
image(candy, candyX, candyY, candyW, candyH); //original candy
candyY = candyY + (candySpeed * yDirCandy);
int time = millis();
if (millis() - time >= 5000)
{
image(goodCandy[rand], randX, goodY, randCandyW, randCandyH);
goodY = goodY + (candySpeed * yDirCandy);
time = millis();
}
//for (int i=0; i<time; i++) {
// image(goodCandy[rand], randX, goodY, randCandyW, randCandyH);
// goodY = goodY + (candySpeed * yDirCandy);
// time = millis();
//}
}
Any ideas how I could make millis() work so I can have a random candy falling every 5 seconds?
Thanks
Please try to get into the habit of breaking your problem down into smaller pieces and only taking on those pieces one at a time. For example, you should probably start with a simpler sketch that just shows a random circle every 5 seconds.
Here's a small example that shows how you would use the millis() function to draw something every 5 seconds:
int lastCircleTime = 0;
void draw() {
if (millis() > lastCircleTime + 5*1000) {
ellipse(random(width), random(height), 20, 20);
lastCircleTime = millis();
}
}
If you're still having trouble, please post a MCVE showing exactly which step you're stuck on. Note that this should not be your whole sketch. It should be a small example like this one. Good luck.
Related
I am currently working on trying to make enemies shoot a projectile in a straight line at the player. The projectiles are not showing on the playstate.
public class Ghost {
private Texture topGhost, bottomGhost;
private Vector2 postopGhost;
private Vector2 posBotGhost;
private Random rand;
private static final int fluct = 130;
private int GhostGap;
public int lowopening;
public static int width;
private Texture bullet;
private Vector2 bulletpos;
private Vector2 botbulletpos;
public Ghost(float x) {
GhostGap = 120; // the gap between the top and bottom ghost
lowopening = 90; //
bullet = new Texture("Bird.png");
topGhost = new Texture("Bird.png");
// middletude = new Texture("sipkemiddle.png"); //spelling mistake
bottomGhost = new Texture("Bird.png");
rand = new Random();
width = topGhost.getWidth();
posBotGhost = new Vector2(x + 120, rand.nextInt(fluct));
postopGhost = new Vector2(x + 113, posBotGhost.y + bottomGhost.getHeight() + GhostGap - 50);
bulletpos = new Vector2(postopGhost);
botbulletpos = new Vector2(posBotGhost);
}
public void repostition(float x) {
postopGhost.set(x + 75, rand.nextInt(fluct) + 200);
posBotGhost.set(x + 75, postopGhost.y + GhostGap - bottomGhost.getHeight() - 247);
}
public void timer(float dt) {
int ticker = 0;
ticker += dt;
if(ticker > 5) {
ticker = 0;
shoot();
}
}
public void shoot(){
setBulletpos(postopGhost);
bulletpos.x = (bulletpos.x + 40);
bulletpos. y = bulletpos.y;
}
So far I had no luck with spawning bullets visually that move across the X-axis of my game. Any suggestions?
You are using timer to determine when the bullet is shot i.e the shot begins, but also in there is the continuing increment for the flight of the bullet. So whenever your timer triggers from delta, the bullet resets position to postopGhost.
i.e. the bullet doesn't have any method to proceed during flight. Try this maybe. Also you need to refer to dt (in some fashion as you like) against the 40 increment because you don't know how much time has elapsed since the last render.
public void timer(float dt) {
int ticker = 0;
ticker += dt;
if(ticker > 5) {
ticker = 0;
shoot();
} else {
processBulletFlight(dt);
}
}
public void shoot(){
setBulletpos(postopGhost);
}
public processBulletFlight(dt) {
bulletpos.x = (bulletpos.x + (40*dt));
}
I'm working on a java 2d game, using this simple game loop to cap the FPS and UpdatesPS to 60:
public void run() {
final int MAX_FPS = 60;
final int MAX_UPS = 60;
final double fOPTIMAL_TIME = 1000000000 / MAX_FPS;
final double uOPTIMAL_TIME = 1000000000 / MAX_UPS;
double uDeltaTime = 0, fDeltaTime = 0;
int frames = 0, updates = 0;
long startTime = System.nanoTime();
long timer = System.currentTimeMillis();
// GameLOOP starts here
while (running) {
long currentTime = System.nanoTime();
uDeltaTime += (currentTime - startTime);
fDeltaTime += (currentTime - startTime);
startTime = currentTime;
if (uDeltaTime >= uOPTIMAL_TIME) {
gameUpdate();
updates++;
uDeltaTime -= uOPTIMAL_TIME;
}
if (fDeltaTime >= fOPTIMAL_TIME) {
gameRender();
gameDraw();
frames++;
fDeltaTime -= fOPTIMAL_TIME;
}
if (System.currentTimeMillis() - timer >= 1000) {
fps = frames; //saves the current FPS
ups = updates; //saves the current UPS
updates = 0;
frames = 0;
timer += 1000;
}
}
}
The loop works, but I get only 30 FPS for the first ~10 Seconds after starting the game.
After I wait, the FPS raises up to the wanted 60. I don't have a problem to wait a few seconds to let the program stabilize and reach the wanted framerate. But I can't find the reason like a methode who drops the FPS because it's fetching a big file after startup.
Do you have any idea why my engine needs so long to stabilize the framerate?
Thanks for your help!
I think this should do the trick:
public static void run()
{
final int desiredFPS = 60;
final int desiredUPS = 60;
final long updateThreshold = 1000000000 / desiredUPS;
final long drawThreshold = 1000000000 / desiredFPS;
long lastFPS = 0, lastUPS = 0, lastFPSUPSOutput = 0;
int fps = 0, ups = 0;
loop:
while(true)
{
if((System.nanoTime() - lastFPSUPSOutput) > 1000000000)
{
System.out.println("FPS: " + (double)fps);
System.out.println("UPS: " + (double)ups);
fps = 0;
ups = 0;
lastFPSUPSOutput = System.nanoTime();
}
if((System.nanoTime() - lastUPS) > updateThreshold)
{
lastUPS = System.nanoTime();
updateGame();
ups++;
}
if((System.nanoTime() - lastFPS) > drawThreshold)
{
lastFPS = System.nanoTime();
drawGame();
fps++;
}
// Calculate next frame, or skip if we are running behind
if(!((System.nanoTime() - lastUPS) > updateThreshold || (System.nanoTime() - lastFPS) > drawThreshold))
{
long nextScheduledUP = lastUPS + updateThreshold;
long nextScheduledDraw = lastFPS + drawThreshold;
long minScheduled = Math.min(nextScheduledUP, nextScheduledDraw);
long nanosToWait = minScheduled - System.nanoTime();
// Just in case
if(nanosToWait <= 0)
continue loop;
try
{
Thread.sleep(nanosToWait / 1000000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
Edit: I fixed the issue now! The issue was that I was saving the lastFPS/lastUPS after the scene was updated/drawn, and when I set both lastUPS/lastFPS before the scene is drawn/updated, we get the desired fps!Another neat thing about this code is that it doesn't consume a whole cpu core(I measured the difference, your code was consuming 100%, whilest my code only consumed about 10%. If you want to measure it yourself, please note that for some reason, the core on which the code is executed regularly switches(at least this was the case when I measured the code))By the way if you use LWJGL (or have direct access to a windowing library like GLFW) you can activate V-Sync, which would cut your fps down to 60 fps.
I am doing an assignment from the Java Exposure textbook, which was written in 2007. This book includes some code that I usually update to use some of the more recent features (just basic stuff). However, in this one I am running into a problem. All I tried to do is replace the show with setVisible(true) and change the Frame to a JFrame and add a gfx.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. However, I noticed that this wouldn't actually cause the window to close. If I clicked many times, maybe 1/30 tries it would close. If I reduced the delay from 10 to 1, it usually closed within 2 tries. This of course led me to believe that the delay method is causing this erratic behavior. I tried Thread.sleep, but of course that didn't work. Is there any simply way to get this code so that the frame will close when I hit the close button? If there isn't, what would be the less simple way of doing it?
Here is the code:
// Lab30st.java
// The Screen Saver Program
// Student Version
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.JOptionPane;
public class Lab30st
{
public static void main(String args[])
{
GfxApp gfx = new GfxApp();
gfx.setSize(800,600);
gfx.addWindowListener(new WindowAdapter() {public void
windowClosing(WindowEvent e) {System.exit(0);}});
gfx.show();
}
}
class GfxApp extends Frame
{
private int circleCount, circleSize;
public GfxApp()
{
circleCount = 50;
circleSize = 30;
}
class Coord
{
private int xPos;
private int yPos;
public Coord(int x, int y)
{
xPos = x;
yPos = y;
}
}
public void paint(Graphics g)
{
int incX = 5;
int incY = 5;
int diameter = 30;
int timeDelay = 10;
Circle c = new Circle(g,diameter,incX,incY,timeDelay);
for (int k = 1; k <= 2000; k++)
{
c.drawCircle(g);
c.hitEdge();
}
}
}
class Circle
{
private int tlX; // top-left X coordinate
private int tlY; // top-left Y coordinate
private int incX; // increment movement of X coordinate
private int incY; // increment movement of Y coordinate
private boolean addX; // flag to determine add/subtract of increment for X
private boolean addY; // flag to determine add/subtract of increment for Y
private int size; // diameter of the circle
private int timeDelay; // time delay until next circle is drawn
public Circle(Graphics g, int s, int x, int y, int td)
{
incX = x;
incY = y;
size = s;
addX = true;
addY = false;
tlX = 400;
tlY = 300;
timeDelay = td;
}
public void delay(int n)
{
long startDelay = System.currentTimeMillis();
long endDelay = 0;
while (endDelay - startDelay < n)
endDelay = System.currentTimeMillis();
}
public void drawCircle(Graphics g)
{
g.setColor(Color.blue);
g.drawOval(tlX,tlY,size,size);
delay(timeDelay);
if (addX)
tlX+=incX;
else
tlX-=incX;
if (addY)
tlY+=incY;
else
tlY-=incY;
}
public void newData()
{
incX = (int) Math.round(Math.random() * 7 + 5);
incY = (int) Math.round(Math.random() * 7 + 5);
}
public void hitEdge()
{
boolean flag = false;
if (tlX < incX)
{
addX = true;
flag = true;
}
if (tlX > 800 - (30 + incX))
{
addX = false;
flag = true;
}
if (tlY < incY + 30) // The +30 is due to the fact that the title bar covers the top 30 pixels of the window
{
addY = true;
flag = true;
}
if (tlY > 600 - (30 + incY))
{
addY = false;
flag = true;
}
if (flag)
newData();
}
}
You are "freezing" the Event Dispatch Thread with
public void delay(int n)
{
long startDelay = System.currentTimeMillis();
long endDelay = 0;
while (endDelay - startDelay < n)
endDelay = System.currentTimeMillis();
}
This means that all the other stuff that is trying to happen (like closing the window) has to wait until the thread comes out of the "sleep".
basically you shouldn't be doing the delay in the EDT, it should be on a different thread and then ask the EDT thread to update.
Your "busy wait" delay may cause other problems too. You can improve the behavior by using Thread.sleep()
See Java Event-Dispatching Thread explanation
That's terrible.
You need to restructure the whole code.
Let's start with the really bad:
delay is (almost) a busy wait, I haven't seen busy waits since BASIC was modern. It basically holds the CPU hostage to the thread, not only does it do nothing, no other thread (almost) can use the time slice. The reason I say almost is that calling the system time function causes a context switch that could allow other threads to run, but it is still bad.
The still pretty bad:
Replacing with Thread.sleep. Better yes, no busy wait, but you are still holding the one and only UI thread. This means no other UI work can happen up to and including closing the main window.
What needs to happen:
Get an external timer (e.g. javax.swing.Timer) to trigger the draw event and do next part of the animation.
Search for "Java smooth animation" there are many examples of how to do this, double buffer and all.
I'm writing a fairly simple app that will, in real-time, tell the user how many pixels there are above a certain color value in an image.
That is, it takes preview images from the camera and analyses them as the user move the camera around.
Right now, I have this code, which technically works:
mRgba = inputFrame.rgba();
Rect sample = new Rect();
Mat sampleRegionRgba;
numPixs = 0;
boundary.add(100); boundary.add(100);boundary.add(100);
int cols = mRgba.cols();
int rows = mRgba.rows();
double yLow = (double)mOpenCvCameraView.getHeight() * 0.2401961;
double yHigh = (double)mOpenCvCameraView.getHeight() * 0.7696078;
double xScale = (double)cols / (double)mOpenCvCameraView.getWidth();
double yScale = (double)rows / (yHigh-yLow);
int tmpX;
int tmpY;
for (int x = 0; x < cols-6; x++) {
for (int y = (int)yLow; y < yHigh-6; y++){
tmpX = (int)((double)x * xScale);
tmpY = (int)((double)y * yScale);
sample.x = tmpX+3;
sample.y = tmpY+3;
sample.width = 2;
sample.height = 2;
sampleRegionRgba = mRgba.submat(sample);
Mat sampleRegionHsv = new Mat();
Imgproc.cvtColor(sampleRegionRgba, sampleRegionHsv, Imgproc.COLOR_RGB2HSV_FULL);
mBlobColorHsv = Core.sumElems(sampleRegionHsv);
int pointCount = sample.width * sample.height;
for (int i = 0; i < mBlobColorHsv.val.length; i++){
mBlobColorHsv.val[i] /= pointCount;
}
mBlobColorRgba = convertScalarToRgba(mBlobColorHsv);
// System.out.println(mBlobColorRgba.toString());
if (mBlobColorRgba.val[0] > boundary.get(0)
&& mBlobColorRgba.val[1] > boundary.get(1)
&& mBlobColorRgba.val[2] > boundary.get(2)){
numPixs += 1;
}
// System.out.println(sampleRegionRgba.toString());
}
}
System.out.println("number of pixels above boundary: "+Integer.toString(numPixs));
massflow = m*(Math.pow(numPixs,.25))+b;
runOnUiThread(new Runnable() {
#Override
public void run() {
massflow_text.setText("Massflow: "+Double.valueOf(massflow));
}
});
While this code works, it takes about 6 seconds to run for each image.
I'd like it to have a much more reasonable frame rate. I know this can be done with numpy (I've done it with np.where()). Is it possible with Java/OpenCv/Android Studio ?
I have a JScrollPane with a moderately high block increment (125). I would like to apply smooth/slow scrolling to it so it doesn't jump (or skip) when scrolling. How can I do this?
I was thinking of scrolling like Windows 8.
Any help would be greatly appreciated!
You could use a javax.swing.Timer during the scroll to achieve the smooth scrolling effect. If you are triggering this from outside the component, somthing like this will work (where component is the component within the JScrollPane):
final int target = visible.y;
final Rectangle current = component.getVisibleRect();
final int start = current.y;
final int delta = target - start;
final int msBetweenIterations = 10;
Timer scrollTimer = new Timer(msBetweenIterations, new ActionListener() {
int currentIteration = 0;
final long animationTime = 150; // milliseconds
final long nsBetweenIterations = msBetweenIterations * 1000000; // nanoseconds
final long startTime = System.nanoTime() - nsBetweenIterations; // Make the animation move on the first iteration
final long targetCompletionTime = startTime + animationTime * 1000000;
final long targetElapsedTime = targetCompletionTime - startTime;
#Override
public void actionPerformed(ActionEvent e) {
long timeSinceStart = System.nanoTime() - startTime;
double percentComplete = Math.min(1.0, (double) timeSinceStart / targetElapsedTime);
double factor = getFactor(percentComplete);
current.y = (int) Math.round(start + delta * factor);
component.scrollRectToVisible(current);
if (timeSinceStart >= targetElapsedTime) {
((Timer) e.getSource()).stop();
}
}
});
scrollTimer.setInitialDelay(0);
scrollTimer.start();
The getFactor method is a conversion from linear to an easing function and would be implemented as one of these depending on how you want it to feel:
private double snap(double percent) {
return 1;
}
private double linear(double percent) {
return percent;
}
private double easeInCubic(double percent) {
return Math.pow(percent, 3);
}
private double easeOutCubic(double percent) {
return 1 - easeInCubic(1 - percent);
}
private double easeInOutCubic(double percent) {
return percent < 0.5
? easeInCubic(percent * 2) / 2
: easeInCubic(percent * -2 + 2) / -2 + 1;
}
This could probably be adapted to work within a component too so when the user scrolls it does something along these lines.
Or, if possible, you could use JavaFX which has much better support for animation than Swing.