I'm back with another Processing question. This time it's about animation. I'm trying to make a simple animation for my group's character sprite, but it's not working too well.
I tried to fix it by watching tutorials but they weren't helpful. Most of them were general animations that weren't for games (such as making circles float like bubbles or fall like balls) and the game-related tutorials were few and far in between. Most involved spritesheets, something we're not using, and the ones my friends and I watched and implemented didn't work either.
The animation is supposed to be a simple three-frame walk cycle. At the moment, the code is close to what we're trying to do, it's displaying the character, but the frames are overlapping instead of running an animation. Here is the code that is dedicated to the animation:
public void keyPressed() {
if (key == CODED) {
if (keyCode == LEFT) {
inMotion = true;
System.out.println("Left");
posX = posX - 5;
} else if (keyCode == RIGHT) {
inMotion = true;
posX = posX + 5;
System.out.println("Right");
} else {
inMotion = false;
}
}
}
public void draw() {
background(bg_game);
fill(50, 10, 10, 150);
if (inMotion) {
//System.out.println("CHar is in motion");
for (int i = 0; i < 3; i++) {
System.out.println(i);
image(playerImages[i], posX, posY, width, height);
if (!(i < 3)) {
i=0; //restarts for loop
}
}
} else {
image(playerImages[1], posX, posY, width, height);
}
}
If there's a better way for us to handle this, let us know!
In Processing, the draw() block is run between each frame. The computer does something like this:
run contents of the setup() block
display the result on the screen
run the draw() block
display the result on the screen
repeat steps 3 and 4
So when you put the for loop inside of draw(), it does this:
render the first walking frame
render the second walking frame (on top of the first)
render the third walking frame (on top of the others)
display the result on the screen
This clearly displays all three frames simultaneously, without cycling between them on different frames. You might do something like this:
int motionFrameStart = 0;
float walkSpeed = 20;//number of frames in a full cycle of walking
public void keyPressed() {
if (key == CODED) {
motionFrameStart = frameCount;
//... the rest of your keyPressed() code
}
}
public void draw() {
background(bg_game);
fill(50, 10, 10, 150);
if (inMotion) {
image(playerImages[(playerImages.length/walkSpeed)*((frameCount - motionFrameStart)%walkSpeed)], posX, posY, width, height);
} else {
image(playerImages[1], posX, posY, width, height);
}
}
In this version, when you press a key, the computer saves the frame when the walking started on, and then calculates which walking picture to use based on how many frames have been displayed since the button was pressed.
Related
I have to make a box move zig-zag all the way to the bottom of the screen. I figured out how to have the box start at the top left corner, move to the top right corner, then it moves down (one complete box of (x,y,90,90)). I'm stuck now because I realize that the next if-statement I want to write is fighting with the first if-statement to glide the box to the left end of the screen. I've tried while and for loops to overcome the problem but I honestly don't know what to do or where to do. I need the program to do this all the way down the screen and stop at rest(810,810,90,90) and stop. Any suggestions?
Here's my main code:
WBox v1;
int a = 0;
float x=0;
float y=0;
void setup() {
size(900, 900);
frameRate(1000);
v1 = new WBox();
}
void draw(){
background(255);
fill(0);
rect(x,y,90,90);
if(x<810){
x+=1;
} else if(y < 90){
y+=1;
} else if (x<=0){
x-=1;
}
}
Here's the class:
**class WBox{
PVector wb;
void box(int tempX, int tempY) {
wb = new PVector(tempX, tempY);
wb.mult(a);//
rect(wb.x, wb.y, 90, 90);
}
}
Full disclaimer: it would be better practice to use the WBox class differently to achieve this, but as you seem to be a beginner, I'm going to stick to easy stuff. You can ask me questions if you feel like it, I'll hang around for a while.
Instead of having a hardcoded number for movement speed, let's try it with a variable:
float boxSpeedX = 1;
The we just have to figure out an algorithm to get it to go down. The best way to do this is to use pseudocode.
In other words: write the logic behind the machine code. Something like this:
Rectangle must move horizontally until it reaches a border
When it reaches a border, it must go down 90 pixels
Then it moves horizontally toward the other side
When it reaches (810, 810) it should stop and rest.
Seems easy enough. Let's go closer to the code:
if (reached a border)
box move horizontally toward the other border
else
box move downward 90 pixels
if (box reached (810, 810)
stop
Closer!
// let's start with the stop condition
if (box reached 810, 810)
do nothing
else
if (box is on an horizontal line)
x += speed
if (box reached right side)
speed = -1 // so next time it'll go left
y +=1 // this way the box isn't on an horizontal line anymore
else if (box reached left side)
speed = 1
y += 1
else
y += 1
Now let's elaborate on some of the details:
(box is on an horizontal line):
horizontal lines are multiples of 90 pixels
(box reached right side)
x == 810
(box reached left side)
x == 0
We'll use the modulo operator to know if the y number is a multiple or 90. Take some time to understand this operator, it's really, really useful. In short, it will give you the remains of an integer division (for example, if you do 13/5, instead of having a number with decimals the integer division will say "2" and the modulo will say "3" because there's 2 times 5 in 13, not more "full 5", and there's 3 units left after this operation).
I feel like we're close enough, now. The rest is just translating this in code. I did it for you, and I've left comments in the code. You can copy and paste it into a Processing IDE and it'll run. You can build on this example to get your box to do whatever you want.
WBox v1;
int a = 0;
float x=0;
float y=0;
float boxSpeedX = 1;
void setup() {
size(900, 900);
frameRate(1000);
v1 = new WBox();
}
void draw() {
background(255);
fill(0);
rect(x, y, 90, 90);
moveBox();
}
void moveBox() {
// first check for the stop condition:
if (x != 810 || y != 810) { // the box will move only while the stop condition isn't met
// if the box is on a horizontal line, let's move it
if (y % 90 == 0) { // the '%' operator's name is 'modulo', it's awesome and useful
x += boxSpeedX;
// once the box has moved, let's check if we need to steer it down:
if (x == 0) { // if the box reaches the left side
boxSpeedX = 1; //next time the box moves horizontally, it'll go right
y += 1; // let's move down
} else if (x == 810) {
boxSpeedX = -1;
y += 1;
}
} else { // if the box isn't on an horizontal line, let's move it downward until it reaches a new line
y += 1;
}
}
}
class WBox {
PVector wb;
void box(int tempX, int tempY) {
wb = new PVector(tempX, tempY);
wb.mult(a);//
rect(wb.x, wb.y, 90, 90);
}
}
Have fun!
I have the following code (in Processing Software) which I want to stop the particles before they leave the screen…
So I dont know how to stop them near the edges of the screen…
Please advice…
Thanks
Particle [] pickles = new Particle [100];
void setup () {
size (500, 500);
smooth ();
for (int i=0; i<pickles.length; i++) {
pickles [i] = new Particle ();
}
}
void draw () {
background (0); //clear the background
for (int i=0; i<pickles.length; i++) {
pickles[i].update();
}
}
class Particle {
float x;
float y;
float velX ; // speed or velocity
float velY;
Particle () {
//x and y position to be in middle of screen
x = width/2;
y = height/2;
velX = random (-10, 10);
velY = random (-10, 10);
}
void update () {
x+=velX;
y+=velY;
fill (255);
ellipse (x, y, 10, 10);
}
}
You can check whether a particle is going outside the bounds of the screen by comparing its x and y values to the screen dimensions. For example:
if(x < 0){
// particle is off left edge of screen
}
else if(x > width){
// particle is off right edge of screen
}
When you detect one of these conditions, you can do a number of things:
Remove the particle from the array so it stops using system resources after it leaves the screen
Wrap the value around to the other side of the screen
Have it bounce off the edge by reversing its velocity
Which approach you take depends on exactly what you want to happen.
Shameless self-promotion: here is a tutorial on collision detection in Processing, which includes the above approaches.
I am working on creating a weighted US map and I have broken the zip codes down into 3 digit zip zones. I then use a for loop that iterates 1000 times to color each 3 digit zip zone a random color.
This works every time with out issue. My current issue is coming in if I start my for loop count above 310. Anything less than 310 and it loops through perfectly. So since raising the initial count would mean that it would run the recursive code less, then this does make any sense to me.
The code that calls the for loop:
private void GUI()
{
JFrame frame = new JFrame();
frame.setLayout(new MigLayout());
try
{
mapImg = ImageIO.read(new File("Res/Zipzone map of the US.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
g = mapImg.createGraphics();
for(int i = 311; i < 1001; i++)
{
Random rand = new Random();
String count = "";
int red = rand.nextInt(220) + 25;
int green = rand.nextInt(220) + 25;
int blue = rand.nextInt(220) + 25;
if(i < 100)
{
count = "0" + i;
}
else
{
count = i + "";
}
if(i <= 512)
{
ApplyColor(count, new Color(red, blue, green));
}
else if( i > 909)
{
ApplyColor3(count, new Color(red, blue, green));
}
else
{
ApplyColor2(count, new Color(red, blue, green));
}
}
frame.add(new JLabel("", new ImageIcon(GetScaledImage(new ImageIcon(mapImg).getImage(), 1400, 875)), JLabel.CENTER), "GROW, PUSH");
frame.setTitle("US Map");
frame.setSize(1500,900);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
Small example of the apply color function:
private void ApplyColor(String zip, Color color)
{
int x;
int y;
if(zip.equals("010"))
{
try
{
x = 3339;
y = 672;
FloodFill(x, y, new Color(mapImg.getRGB(x, y)), color);
x = 3361;
y = 681;
FloodFill(x, y, new Color(mapImg.getRGB(x, y)), color);
}
catch(AWTException e)
{
e.printStackTrace();
}
}
}
And the FloodFill function:
public void FloodFill(int x, int y, Color targetColor, Color replacementColor) throws AWTException
{
if(new Color(mapImg.getRGB(x, y)).equals(replacementColor))
{
return;
}
g.setColor(replacementColor);
g.fillRect(x, y, 1, 1);
if(new Color(mapImg.getRGB(x-1, y)).equals(targetColor))
{
FloodFill(x-1, y, targetColor, replacementColor);
}
if(new Color(mapImg.getRGB(x+1, y)).equals(targetColor))
{
FloodFill(x+1, y, targetColor, replacementColor);
}
if(new Color(mapImg.getRGB(x, y-1)).equals(targetColor))
{
FloodFill(x, y-1, targetColor, replacementColor);
}
if(new Color(mapImg.getRGB(x, y+1)).equals(targetColor))
{
FloodFill(x, y+1, targetColor, replacementColor);
}
}
I don't really know why you receive this error when you start from 310 or more, because the part of your code that deals with what you are referring to as "zip codes" is too bizarre to try and make sense of, and because in any case, making sense out of that would not benefit any other visitors of the site, only you.
What I suspect is happening is that by starting at 310 or above the arrangement of zip codes is such that your recursive flood-fill algorithm is required to do more painting than if you did not.
Which brings us to your recursive flood-fill algorithm.
That's not the right way to do flood-fill.
It might be considered right in the academia, but not in the real world.
If your algorithm is given a long stretch of pixels to paint, it will recurse for every single one of them. In your initialization code I see you setting the width of your frame to 1500, and elsewhere I see you using coordinates in excess of 3000, which means that you do in fact give your algorithm long stretches of pixels to paint. Which means that it recurses a lot. That's why you get a stack overflow exception.
To correct your problem, you need to rewrite your recursive flood-fill algorithm so that it does not recurse so much. For example, instead of recursing each time you visit a pixel to the left, have it loop to the left for as long as there are pixels to paint, and only recurse for the pixel above and the pixel below each painted pixel. The same holds for visiting pixels to the right. That's an easy way to reduce the recursion depth of your algorithm by orders of magnitude.
It also has the benefit of performing much better, because once you know all the pixels that you need to paint in a row, you can paint them all with a single drawing call, instead of performing one fillRect() per pixel. We are talking about orders of magnitude better performance here.
If that is not enough to solve your stack overflow problems, then you might want to consider replacing your algorithm with one which uses a stack data structure instead of actually invoking itself. Conversion of a recursive algorithm to a non-recursive that uses a stack data structure is something that you can look up and find plenty of solutions to.
I am trying to move an image that I have drawn onto a Jpanel using g.drawImage(). I need to know why this code isn't working (I am trying to reposition the image using the w key to move it up)
int CharX = 1;
int CharY = 30;
public void keyPressed(KeyEvent w) {
CharY = CharY + 1;
repaint();
}
public void keyReleased(KeyEvent w) {
CharY = CharY + 1;
repaint();
}
You're not actually checking for the w key just by naming the KeyEvent w. You need to check if (w.getKeyCode() == KeyEvent.VK_W)
Y-coordinates in Java start with 0 at the top, so you might want to subtract from CharY to make it go up.
This will update twice, once when the key is pressed, and again when you let it go. Not sure if that's what you actually want.
Without knowing what's inside your paint function, or if you even implemented it, it's hard to say if the problem isn't actually in there, but it should look something like
public void paint(Graphics g) {
g.drawImage(yourImage, CharX, CharY, null);
}
You should not call repaint() inside the keyPressed() or keyReleased() method.
public void keyPressed(w.getKeyCode() == KeyEvent.VK_W) {
CharY = CharY + 1;
}
Call repaint() later.
I am working with disabled children, who have cerebral palsy. One child has limited fine motor control, so she currently uses a joystick to control the mouse, and it's traverse rate is set very low. This works well for her, as she can click all buttons on the screen, but I think we could do better - when she wants to traverse the whole screen it takes an age to do so (about 10 seconds).
My hypothesis is that her brain is fine, and only her motor control is poor. If that's true, I believe that a mouse that started at a low speed, but experienced a constant acceleration, would be better for her, as it would pick up speed and become quick when traversing the whole screen.
If this works, then we could be tweaking PID control, and velocity/acceleration setting for a great number of disabled people, speeding up their access and hence their learning and development.
But I do not know the best way to build this - all suggestions, thoughts, links and tips welcome.
To begin with I have tried using Processing and Java, and using a mouseListener, and a Robot to control the cursor. I'm not convinced that this is the best way though, as I'm reading the cursor position and then writing to it, so my best attempts still make the cursor jump around, and there is not smooth movement. Is it achievable in Java? Do I need to read the mouse input from the USB using some kind of driver, and then replace the plotting of the cursor on screen with my own?
I've made a couple of videos to illustrate the effect I am trying to bring about.
The Status quo (my illustration is driving the cursor off the arrow keys)
http://www.youtube.com/watch?v=3ZhQCg5DJt8
The new behaviour I want (mouse accelerates)
http://www.youtube.com/watch?v=JcBK_ZCFGPs
if it's any use, the Processing code I used to make those demos is copied in below:
Status quo demo:
import java.awt.AWTException;
import jav
a.awt.Robot;
Robot robot;
int i = 0;
int j = 0;
void setup() {
setupDotgame();
try {
robot = new Robot();
}
catch (AWTException e) {
e.printStackTrace();
}
robot.mouseMove(screenWidth/2, screenHeight/2);
}
void draw() {
//println(frameCount);
robot.mouseMove(screenWidth/2+8*i, screenHeight/2+8*j);
drawDotgame();
}
void keyPressed() {
if (keyCode == UP) {
j--;
}
else if (keyCode == DOWN) {
j++;
}
else if (keyCode == RIGHT) {
i++;
}
else if (keyCode == LEFT) {
i--;
}
}
Desired behaviour:
import java.awt.AWTException;
import java.awt.Robot;
Robot robot;
int i = 0;
int j = 0;
int delta = 8;
int time = 0;
void setup() {
setupDotgame();
try {
robot = new Robot();
}
catch (AWTException e) {
e.printStackTrace();
}
robot.mouseMove(screenWidth/2, screenHeight/2);
}
void draw() {
//println(frameCount);
robot.mouseMove(screenWidth/2+i, screenHeight/2+j);
drawDotgame();
}
void keyPressed() {
if (millis() - time < 90) {
delta += 8;
}
else { delta = 8; }
time = millis();
if (keyCode == UP) {
j-=delta;
}
else if (keyCode == DOWN) {
j+=delta;
}
else if (keyCode == RIGHT) {
i+=delta;
}
else if (keyCode == LEFT) {
i-=delta;
}
}
And the DotGame code they both reference:
void setupDotgame() {
size(1000, 600);
background(255);
fill(255, 0, 0);
noStroke();
smooth();
drawCircle();
}
void drawDotgame() {
if (get(mouseX, mouseY) != color(255)) {
background(255);
drawCircle();
}
}
void drawCircle() {
int x = round(random(50, width-50));
int y = round(random(50, height-50));
int rad = round(random(20, 80));
ellipse(x, y, rad, rad);
}
Thanks in advance
as Carl suggested, I believe the best answer short of making the mouse actually have this behavior, is some sort of jumping behavior that will get the mouse fairly close to where you need to go, then use the joystick from there.
I happen to know that a program called AutoItv3 can do this sort of thing. You could set it up to recognize special hotkeys, then have that hotkey move the mouse to whatever region you wish.
Commands useful for this are HotKeySet, MouseMove, and Func/EndFunc.