I'm using processing (java) and I'm trying to use an array called input to easily handle keypresses. Here's my code for that:
boolean input[] = {};
void keyPressed() {
input[keyCode] = true;
}
void keyReleased() {
input[keyCode] = false;
}
And so, if this code worked, I could just call this
if (input[32]) { //32 == SPACE
//Do something
}
And the conditional would result to true if the key were pressed, and the statement would get executed, otherwise, it would result to false if the key were released.
However, I'm getting this error:
main.pde:1:1:1:1: Syntax Error - You may be mixing static and active modes.
Why is this?
Thanks for any help.
The following demo will trap spacebar presses. If you want to trap presses for multiple keys you would need to use an array of integers instead of booleans, eg int input[] = new int[4]; then iterate the array when keys are pressed (see second example). Keep in mind that some keys are coded and others are not, eg arrow keys are coded and it takes different code to trap them.
boolean spaceBarPressed = false;
void setup(){
}
void draw(){
if(spaceBarPressed){
println("Space bar pressed.");
} else {
println("Space bar released.");
}
}
void keyPressed() {
if(key == 32){
spaceBarPressed = true;
}
}
void keyReleased() {
if(key == 32){
spaceBarPressed = false;
}
}
Second Example for key array:
/*
Will trap key presses for an array of ascii keys
*/
int input[] = new int[2];
int keySelected;
boolean keyDwn = false;
void setup() {
input[0] = 32;
input[1] = 65;
}
void draw() {
switch(keySelected) {
case 32:
if (keyDwn) {
println("spacebar dwn.");
} else {
println("spacebar up.");
}
break;
case 65:
if (keyDwn) {
println("key A down.");
} else {
println("key A up.");
}
break;
}
}
void keyPressed() {
for (int x = 0; x < input.length; x++) {
if (input[x] == 32 || input[x] == 65) {
keySelected = keyCode;
keyDwn = true;
}
}
}
void keyReleased() {
for (int x = 0; x < input.length; x++) {
if (input[x] == 32 || input[x] == 65) {
keySelected = keyCode;
keyDwn = false;
}
}
}
I'm having an issue and I'm not certain if it's recursion-based. I created a GUI maze that solves itself but the curser jumps over any recursion-traveled square instead of re-traveling the square. Even though it ultimately finds the goal, I want to show it's entire path but I can't stop the curser from jumping around.
I'm using Runnable to track the maze in real-time so I can see it bounce but without the recursion-travel keeping it bound, the recursive functions cease to work (it just bounces back and forth which, again, I don't quite understand.) I started java about three months ago in an accelerated program so I'm not sure if the issue is my understanding of recursion, or a simple addition to a method, or if I'll have to rewrite a large portion of code.
I included the whole code just in case but really it's an issue that's within the travel method or the visited method. Would the answer be to write an entirely new method that re-travels the changed "visited" string maze? I've been struggling with this for a bit and I just need some direction toward an answer.
import java.awt.*;
import javax.swing.*;
class extraCreditMaze extends JPanel implements Runnable { //uses Runnable to execute jPanel
private String [][] ratMaze = //string maze
{{"blocked","blocked","blocked","blocked","blocked","blocked","blocked","blocked"},
{"blocked","open","blocked","blocked","blocked","blocked","blocked","blocked"},
{"blocked","open","open","open","open","open","open","blocked"},
{"blocked","blocked","open","blocked","open","blocked","open","blocked"},
{"blocked","blocked","open","blocked","open","blocked","open","goal"},
{"blocked","open","open","open","blocked","open","open","blocked"},
{"blocked","blocked","blocked","open","open","open","blocked","blocked"},
{"blocked","blocked","blocked","blocked","blocked","blocked","blocked","blocked"}};
final private int SquareSize = 15;
final private int BoardSize = 17;
private boolean free = false;
int axisX = 1, axisY = 1;
public void paintComponent(Graphics color) //paint components for char
{
super.paintComponent(color);
for(int row = 0; row < ratMaze.length; row++)
{
for(int col = 0; col< ratMaze.length; col++)
{
if(row==axisX && col==axisY) //traveling curser = blue
{
color.setColor(Color.blue);
color.fillOval(col*15,row*15,15,15);
}
else if(ratMaze[row][col]=="blocked") //empty = black
{
color.setColor(Color.black);
color.fillRect(col*SquareSize,row*SquareSize,BoardSize,BoardSize);
}
else if(ratMaze[row][col]=="goal")
{
color.setColor(Color.red); //goal = red
color.fillOval(col*15,row*15,15,15);
}
else if(ratMaze[row][col]=="visited")
{
color.setColor(Color.green); //path traveled = green
color.fillOval(col*15,row*15,15,15);
}
else
{
color.setColor(Color.white); //empty space = white
color.fillRect(col*SquareSize,row*SquareSize,BoardSize,BoardSize);
}
}
}
}
public void run () //starts run at (1,1)
{
travel(1,1);
}
public boolean goal(int x, int y){ //method to check goal (true/false)
if(ratMaze[x][y]=="goal")
return true;
else
return false;
}
public void changedVisited(int x, int y) //method to change traveled
{
ratMaze[x][y] = "visited";
axisX = x;
axisY = y;
}
public boolean boundaries(int x, int y) //check boundaries
{
if(ratMaze[x][y]=="blocked")
return true;
else
return false;
}
public boolean visited(int x, int y) //check if visited
{
if(ratMaze[x][y]=="visited")
return true;
else
return false;
}
private void travel(int x, int y)
{
if(boundaries(x,y)) //makes sure it's within bounds
return;
if(visited(x,y)) //makes sure it hasn't already been visited
return;
if(goal(x,y)) //checks if it's the goal/changes boolean
{
free = true;
JOptionPane.showMessageDialog(this, "You did it, Dr. Cui!"); //fun message!
}
if(!free) //all recursion functions if free=false
{
changedVisited(x,y); //changes traveled block to "visited"
repaint(); //repaints visited
try {Thread.sleep(300); } catch (Exception e) { }//slows down the traveling curser
//I do not understand catch (Exception e)
travel(x-1,y); //recursive travel functions
travel(x+1,y);
travel(x,y-1);
travel(x,y+1);
}
}
}
public class runExtraCreditMaze {
public static void main (String [] args) { //JFrame panel and perimeters
JFrame output = new JFrame();
output.setSize(115, 150);
output.setTitle("The Rat Maze");
output.setLocationRelativeTo(null);
extraCreditMaze Maze = new extraCreditMaze();
output.setContentPane(Maze);
output.setVisible(true);
Thread runnable = new Thread(Maze); //Creates Runnable thread for Maze object
runnable.start(); //Starts Runnable thread of Maze object
}
}
Problem is, as you wrote with the "visited". You are missing an decision tree on what to do, when there is no valid move and you are not in the goal. You will need to allow your rat to back track itself. You will probably need to "free" the visited cells when returning from no valid move.
I will try to add some code samples when I get to IDE :)
update: this is very badly written, and it is a bit lagging. but it should work. It needs a bit of cleaning and verification... I reused your boolean variable, which is bad .. :) and switched the true/false. I will do a bit of cleaning up tomorrow just to leave a nicer answer, but I think you will manage to understand what is going on.
update2:I have cleaned it a bit. Important lessons here are as follows:
1) backtracking needs to be done when all 4 steps fails. When your rat have nowhere to go, you need to disqualify the cell from your shortest path (ratMaze[x][y]="open")
2) You need to change position of your rat, when you return from recursion call, but before you continue with next step into. You will also need to let your program know that you are returning from recursion (thus the isBacktracking)
private void repaintMaze(int x, int y) {
changedVisited(x, y); //changes traveled block to "visited"
repaint(); //repaints visited
isBacktracking = false;
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
private boolean travel(int x, int y) {
if (goal(x, y)) //checks if it's the goal/changes boolean
{
JOptionPane.showMessageDialog(this, "You did it, Dr. Cui!");//fun message!
return true;
}
if (boundaries(x, y) || visited(x, y)) //makes sure it's within bounds
return false;
repaintMaze(x, y);
boolean result; //recursive travel functions
result = travel(x - 1, y);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x + 1, y);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x, y - 1);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x, y + 1);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
ratMaze[x][y] = "open";
isBacktracking = true;
return false;
}
you should also add exit on close to your JFrame :) It will stop the application once you click the X button on the window itself
output.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
I am working on my first java project, one that simulates the behaviour of a neutrophil catching a bacterium (So random/semirandom particle behaviour). At the beginning of this program I have several variables (such as the radii of the organisms, etc) and right now they are fixed to the value I hardcoded in there. I want to create a user interface so that before the program starts, a screen pops up in which you can type in the values you want to use, and it uses those to run to program. Now I have used a swing script to create such a window and that looks a bit like this:
Now I'm wondering how I could implement it such that I can take the values used in those text boxes and assign them to my variables in my program.
This is the program I am referring to:
package nanocourse;
import java.awt.Color;
import nano.*;
import java.util.Random;
import prescreen.PreScreen;
public class Exercise3_final {
public Exercise3_final() {
int xSize = 1000;
int ySize = 800;
Canvas myScreen = new Canvas(xSize, ySize);
Pen myPen = new Pen(myScreen);
Random random = new Random();
int frame=0; //how many frames have passed since start program
//properties bacterium
int xPosBacterium=random.nextInt(xSize); //random starting position of bacterium
int yPosBacterium=random.nextInt(ySize);
int K=1000; //how many points used to draw bacterium
double [] xValueBacterium = new double[K]; //
double [] yValueBacterium = new double[K];
double bacteriumRadiusInput=20;
double bacteriumRadius=bacteriumRadiusInput; //radius of bacterium
boolean bacteriumAlive=true;
//properties biomolecules
int amountBio=30000;
boolean [] bioExist = new boolean[amountBio];
int [] xPosBio = new int [amountBio];
int [] yPosBio = new int [amountBio];
int [] dXBio = new int [amountBio];
int [] dYBio = new int [amountBio];
int [] lifetimeBio = new int [amountBio];
double chanceDegrade=0.1; //chance that a biomolecule gets degraded per frame
double chanceSynthesize=100; //chance that a biomolecule gets synthesized per frame
for(int i=0;i<amountBio;i++)
{
bioExist[i]=false; //setting existing state to false
}
//properties Neutrophil
int xPosNeutrophil=random.nextInt(xSize);
int yPosNeutrophil=random.nextInt(ySize);
int L=1000;
double [] xValueNeutrophil= new double[L];
double [] yValueNeutrophil= new double[L];
double neutrophilRadius=40;
double xVector, yVector, xNormVector,yNormVector,magnitude,xSumVector,ySumVector;
double aggressiveness=1;
while(bacteriumAlive==true) //while program is running
{
frame++;
//1. Simulating a moving Bacterium
int dXBacterium=random.nextInt(11)-5; //random motion
int dYBacterium=random.nextInt(11)-5;
xPosBacterium=xPosBacterium+dXBacterium;
yPosBacterium=yPosBacterium+dYBacterium;
if(xPosBacterium<(bacteriumRadius/2+2*myPen.getSize())) //boundaries bacterium,accounting for size bacterium
{
xPosBacterium=(int)bacteriumRadius/2+2*myPen.getSize();
}
else if(xPosBacterium>xSize - (bacteriumRadius/2+2*myPen.getSize()))
{
xPosBacterium=xSize - ((int)bacteriumRadius/2+2*myPen.getSize());
}
else if(yPosBacterium<(bacteriumRadius/2+2*myPen.getSize()))
{
yPosBacterium=((int)bacteriumRadius/2+2*myPen.getSize());
}
else if(yPosBacterium>ySize - (bacteriumRadius/2+2*myPen.getSize()))
{
yPosBacterium=ySize - ((int)bacteriumRadius/2+2*myPen.getSize());
}
//2. Simulating synthesis and secretion of biomolecules by the bacterium.
for(int i=0;i<amountBio;i++)
{
double synthesizeNumber=Math.random()*100;
if(synthesizeNumber<chanceSynthesize && i==frame)
{
bioExist[frame]=true; //make the biomolecules exist
}
if(bioExist[i]==true && frame!=1) //if biomolecule exist apply motion
{
dXBio[i]=random.nextInt(41)-20;
dYBio[i]=random.nextInt(41)-20;
xPosBio[i]=xPosBio[i]+dXBio[i];
yPosBio[i]=yPosBio[i]+dYBio[i];
}
else //if biomolecule doesn't exist, make position equal bacterium position
{
xPosBio[i]=xPosBacterium;
yPosBio[i]=yPosBacterium;
}
if(xPosBio[i]>xSize) //boundaries biomolecules
{
xPosBio[i]=xSize;
}
if(xPosBio[i]<0)
{
xPosBio[i]=0;
}
if(yPosBio[i]>ySize)
{
yPosBio[i]=ySize;
}
if(yPosBio[i]<0)
{
yPosBio[i]=0;
}
if(bioExist[i]==true)
{
lifetimeBio[i]++;
double degradationNumber=Math.random()*100;
if(degradationNumber<chanceDegrade)
{
bioExist[i]=false;
}
}
if(bioExist[i]==true && lifetimeBio[i]<=100) //if biomolecule lives shorter than 100 frames==>green
{
myPen.setColor(Color.GREEN); //drawing biomolecules
myPen.setShape(Shape.CIRCLE);
myPen.setSize(5);
}
if(bioExist[i]==true && (lifetimeBio[i]>100 && lifetimeBio[i]<=500)) //if biomolecule lives 101-500 frames==>green
{
myPen.setColor(Color.yellow); //drawing biomolecules
myPen.setShape(Shape.CIRCLE);
myPen.setSize(5);
}
if(bioExist[i]==true && (lifetimeBio[i]>500 && lifetimeBio[i]<=1000)) //if biomolecule lives 501-1000 frames==>orange
{
myPen.setColor(Color.ORANGE); //drawing biomolecules
myPen.setShape(Shape.CIRCLE);
myPen.setSize(5);
}
if(bioExist[i]==true && (lifetimeBio[i]>1000 && lifetimeBio[i]<=1500)) //if biomolecule lives 1001-1500 frames==>red
{
myPen.setColor(Color.RED); //drawing biomolecules
myPen.setShape(Shape.CIRCLE);
myPen.setSize(5);
}
if(bioExist[i]==true && lifetimeBio[i]>1500) //if biomolecule lives 2001+ frames==>magenta
{
myPen.setColor(Color.magenta); //drawing biomolecules
myPen.setShape(Shape.CIRCLE);
myPen.setSize(5);
}
if(bioExist[i]==true)
{
myPen.draw(xPosBio[i],yPosBio[i]);
}
if(Math.sqrt(Math.pow(Math.abs(xPosBio[i]-xPosNeutrophil),2)+Math.pow(Math.abs(yPosBio[i]-yPosNeutrophil), 2))<neutrophilRadius)
{
bioExist[i]=false; //degrade if inside neutrophil
}
}
if(bacteriumAlive==true)
{
for(int i = 0; i <K ; i++) //defining circle, drawing points, placed here because it needs to be on top
{
xValueBacterium[i] = bacteriumRadius*Math.cos(2*Math.PI*i/K);
yValueBacterium[i] = bacteriumRadius*Math.sin(2*Math.PI*i/K);
myPen.setColor(Color.red);
myPen.setShape(Shape.CIRCLE);
myPen.setSize(5);
myPen.draw((int)xValueBacterium[i]+xPosBacterium,(int)yValueBacterium[i]+yPosBacterium);
}
}
//5. Simulating the neutrophil eating the bacteriun
xSumVector=0;
ySumVector=0;
for(int i=0;i<amountBio;i++)
{
if(Math.abs(xPosBio[i]-xPosNeutrophil)<(30+neutrophilRadius) && Math.abs(yPosBio[i]-yPosNeutrophil)<(30+neutrophilRadius) && bioExist[i]==true)
{
xVector=xPosBio[i]-xPosNeutrophil;
yVector=yPosBio[i]-yPosNeutrophil;
magnitude=Math.sqrt(Math.pow(xVector, 2)+Math.pow(yVector, 2));
xNormVector=xVector/magnitude;
yNormVector=yVector/magnitude;
xSumVector=xSumVector+xNormVector;
ySumVector=ySumVector+yNormVector;
}
}
//3. Simulating a moving neutrophil
int dXNeutrophil=random.nextInt(11)-5+(int)aggressiveness*(int)xSumVector; //random motion
int dYNeutrophil=random.nextInt(11)-5+(int)aggressiveness*(int)ySumVector;
xPosNeutrophil=xPosNeutrophil+dXNeutrophil;
yPosNeutrophil=yPosNeutrophil+dYNeutrophil;
myPen.setSize(8);
if(xPosNeutrophil<(neutrophilRadius/2+2*myPen.getSize())) //boundaries neutrophil
{
xPosNeutrophil=(int)neutrophilRadius/2+2*myPen.getSize();
}
else if(xPosNeutrophil>xSize - (neutrophilRadius/2+2*myPen.getSize()))
{
xPosNeutrophil=xSize - ((int)neutrophilRadius/2+2*myPen.getSize());
}
else if(yPosNeutrophil<(neutrophilRadius/2+2*myPen.getSize()))
{
yPosNeutrophil=((int)neutrophilRadius/2+2*myPen.getSize());
}
else if(yPosNeutrophil>ySize - (neutrophilRadius/2+2*myPen.getSize()))
{
yPosNeutrophil=ySize - ((int)neutrophilRadius/2+2*myPen.getSize());
}
for(int i = 0; i <L ; i++) //defining circle, drawing points, placed here because it needs to be on top
{
xValueNeutrophil[i] = neutrophilRadius*Math.cos(2*Math.PI*i/L);
yValueNeutrophil[i] = neutrophilRadius*Math.sin(2*Math.PI*i/L);
myPen.setColor(Color.blue);
myPen.setShape(Shape.CIRCLE);
myPen.draw((int)xValueNeutrophil[i]+xPosNeutrophil,(int)yValueNeutrophil[i]+yPosNeutrophil);
}
if(Math.abs(xPosNeutrophil-xPosBacterium)<2*bacteriumRadiusInput && Math.abs(yPosNeutrophil-yPosBacterium)<2*bacteriumRadiusInput && bacteriumRadius >=0)
{
bacteriumRadius=bacteriumRadius-1;
if(bacteriumRadius==0)
{
bacteriumAlive=false;
}
}
if(bacteriumAlive==false)
{
bacteriumAlive=true;
xPosBacterium=random.nextInt(xSize); //random starting position of bacterium
yPosBacterium=random.nextInt(ySize);
bacteriumRadius=bacteriumRadiusInput;
}
myScreen.update(); //updating/refreshing screen
myScreen.pause(10);
myScreen.clear();
}
}
public static void main(String[] args) {
Exercise3_final e = new Exercise3_final();
}
}
Any help would be appreciated!
Sounds like you need an action listener on the "Run!" button from your dialog:
_run.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// set the variables here by getting the text from the inputs
field1Var = Integer.parseInt(field1Input.getText());
field2Var = Integer.parseInt(field2Input.getText());
...
}
});
I would suggest creating a singleton class to save all the values that are captured from the first screen (options menu screen).
You can get the instance of this class anywhere in the application later on and use it.
Advantages would be:
- You will not have to carry forward the values everywhere in the application.
- The values captured will the persisted till the application is shut down.
Note: Make sure to add validations while fetching values from the options menu so that incorrect values are not set.
Hello I am working on a hangman game and almost finished. My last problem is making my virtual keyboard only clickable once. I either break the loop after if checks the letter true or false and that works but it only returns one letter even if the word has to of the same letters. or leave the loop open and it returns 4 - 5 tries depending on how many times the mouse clicked from on click if u know what i mean. can i make the Inputlistner only register one click??.. here is the image and its list
a = new Image(new Texture("Sprites/Keyboard/a.png"));
a.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
apressed = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
apressed = false;
}
});
and then here is the call method in my playstate... I tried to return a false boolean after the loop but still it registers too many clicks before ending the loop...
if (tries < 100) {
if (keyboard.apressed && abpressed == true) {
for (int i = 0; i < randomWordtoGuess.length; i++) {
if (a == randomWordtoGuess[i] ) {
playerGuess[i] = a;
currentWord = new String(playerGuess);
keyboard.a.setColor(0, 1, 0, 1);
abpressed = false;
}
if (a != randomWordtoGuess[i]) {
keyboard.a.setColor(1, 0, 0, 1);
tries++;
System.out.print(tries);
abpressed = false;
}
else{
}
// if i place a break; here it solves the problem
// but doesnt return more than one letter in the word..
// for example Concrete it will only show first C.
}
}
}
another way to solve the problem is to just add 1 to the int "tries" instead of tries++.. but i think that cant be done??
You can make a new boolean that will check if the keyboard has been clicked yet. Lets say we declare a global boolean keyClicked. Then, just add this to your InputListener:
a.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if (!keyClicked) {
apressed = true;
keyClicked = true;
return true;
}
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
if (!keyClicked) {
apressed = false;
keyClicked = true;
}
}
});
public class SnowflakeWallpaper extends WallpaperService {
// Limit of snowflakes per snowflake type; 4 types * 4 snowflake = 16 total
// Should keep memory usage at a minimal
static int SNOWFLAKE_AMOUNT = 4;
Drawable drawWall;
Rect wallBounds;
// Draw all snowflakes off screen due to not knowing size of canvas at creation
static int SNOW_START = -90;
ArrayList<Snowflakes> snow = new ArrayList<Snowflakes>();
private final Handler mHandler = new Handler();
#Override
public void onCreate() {
super.onCreate();
//WallpaperManager to pull current wallpaper
WallpaperManager wManager = WallpaperManager.getInstance(this);
drawWall = wManager.getFastDrawable();
wallBounds = drawWall.copyBounds();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public Engine onCreateEngine() {
return new SnowEngine();
}
class SnowEngine extends Engine {
private final Runnable mDrawSnow = new Runnable() {
public void run() {
drawFrame();
}
};
private boolean mVisible;
SnowEngine() {
if(snow.size() < 16){
//Back snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflakeback),
SNOW_START,
SNOW_START,
((float)(Math.random() * 2) + 1)) // Fall speed initial setup, back slowest to front fastest potentially
);
}
//MidBack snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflakemid),
SNOW_START,
SNOW_START,
((float)(Math.random() * 4) + 1)
));
}
// Mid snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflakemidfront),
SNOW_START,
SNOW_START,
((float)(Math.random() * 8) + 1))
);
}
// Front snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflake),
SNOW_START,
SNOW_START,
((float)(Math.random() * 16) + 1))
);
}
}
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mDrawSnow);
}
#Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
drawFrame();
} else {
mHandler.removeCallbacks(mDrawSnow);
}
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
drawFrame();
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mDrawSnow);
}
/*
* Update the screen with a new frame
*/
void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
/*
* if the snow goes too low or too right, reset;
*/
for(int i = 0; i < snow.size(); i++){
if(snow.get(i).getX() > holder.getSurfaceFrame().width()){
snow.get(i).setX(-65);
}
if(snow.get(i).getY() > holder.getSurfaceFrame().height()){
snow.get(i).setY(-69);
}
}
// Test if the array was just create; true - randomly populate snowflakes on screen
if(snow.get(1).getX() < -70){
for(int i = 0; i < snow.size(); i++){
snow.get(i).setX((int)(Math.random() * getSurfaceHolder().getSurfaceFrame().width() +1));
snow.get(i).setY((int)(Math.random() * getSurfaceHolder().getSurfaceFrame().height() + 1));
}
}
// Change snowflake x & y
for(int i = 0; i < snow.size(); i++){
snow.get(i).delta();
}
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// call to draw new snow position
drawSnow(c);
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
// Reschedule the next redraw
mHandler.removeCallbacks(mDrawSnow);
if (mVisible) {
mHandler.postDelayed(mDrawSnow, 1000 / 100);
}
}
/*
* Draw the snowflakes
*/
void drawSnow(Canvas c) {
c.save();
// Draw bg
//********** add code to pull current bg and draw that instead of black. Maybe set this in config?
if(drawWall == null){
c.drawColor(Color.BLACK);
}else{
drawWall.copyBounds(wallBounds);
drawWall.draw(c);
}
/*
* draw up the snow
*/
for(int i = 0; i < snow.size(); i++){
c.drawBitmap(snow.get(i).getImage(), snow.get(i).getX(), snow.get(i).getY(), null);
}
c.restore();
}
}
}
Same question as Gabe - what's the problem?
Some general thoughts:
* You should avoid doing lots of work in a constructor. Your constructor does a ton of work that should (imho) be in some init/setup method instead. Easier to benchmark / profile there independently from instance creation.
You're using Math.random in many places - I assume you are singly threaded, but Math.random is synchronized. Per the javadocs: " if many threads need to generate pseudorandom numbers at a great rate, it may reduce contention for each thread to have its own pseudorandom-number generator"
You're using Math.random which gets you a double, then multiplying, then adding, then casting. This looks wasteful. Any way to get fewer ops?
You seem to have some division - see line "mHandler.postDelayed(mDrawSnow, 1000 / 100);". Sure, that's probably compiled or JIT'd away, but you should avoid division in performance critical code (it's far slower than multiplying). So any div by a constant can be replaced by multiplying by 1 / C as a static.
You have lots of repeat accessor method calls (in some cases nearly all are repeat). See snippit:
for(int i = 0; i < snow.size(); i++){
if(snow.get(i).getX() > holder.getSurfaceFrame().width()){
snow.get(i).setX(-65);
}
if(snow.get(i).getY() > holder.getSurfaceFrame().height()){
snow.get(i).setY(-69);
}
}
You should store "holder.getSurfaceFrame().width() in a temporary / local var (perhaps once per draw loop assuming your surface is resizable by the user). You might also store snow.get(i) in a local var. Better yet (style) you can use the enhanced for loop as snow is an ArrayList. So use
for (Snow mySnow : snow) {
// Do something with mySnow
}
Hope this helps. Good luck!