I was able to write a code that draws different circles on a canvas and i need to find a way i could delete the leftmost circle when any key is pressed. i've been at this for hours and i feel like i am close to the answer. i am most klikely going to look for the array whenever a key is pressed and delete the array position.
float colour = random(256);
final int DIAM = 20;
final int MAX_NUM = 1000;
int numPointsX = 0;
int numPointsY = 0;
int [] xPos = new int[MAX_NUM];
int [] yPos = new int [MAX_NUM];
boolean start = false;
void setup() {
size (500, 500);
}
void draw() {
background(150);
fill(random(256), random(256), random(256));
for (int i=0; i<numPointsX; i++) {
circle(xPos[i], yPos[i], DIAM);
}
println(xPos[0]);
}
void mouseClicked() {
insertXandY();
}
void insertXandY() {
int x = mouseX;
int y = mouseY;
xPos[numPointsX] = x;
yPos[numPointsY] = y;
numPointsX += 1;
numPointsY += 1;
start = true;
}
void printArrays() {
println("X Positions");
for (int i = 0; i < 20; i++) {
println("\t" + xPos[i]);
}
}
void keyPressed() {
if (key == 'p') {
printArrays();
}
}
You are on the right track.
In broad terms you'd need two steps:
find the smallest X
delete the data associated with the smallest X
The 1st part is trivial:
use a variable to keep track of the currently smallest value (initialised with a bigger than than your data has)
iterate through each value
compare each value with the current smallest:
if it's bigger ignore
if it's smallest: update the currently smallest value (and remember the index)
at the end of the iteration the currently smallest value is the smallest possible value and index can be used to associate between x,y arrays (which are incremented in sync)
Here's a slightly modified version of your code to illustrate this:
float colour = random(256);
final int DIAM = 20;
final int MAX_NUM = 1000;
int numPoints = 0;
int [] xPos = new int[MAX_NUM];
int [] yPos = new int [MAX_NUM];
void setup() {
size (500, 500);
}
void draw() {
background(150);
fill(random(256), random(256), random(256));
for (int i=0; i < numPoints; i++) {
circle(xPos[i], yPos[i], DIAM);
}
}
void mouseClicked() {
insertXandY();
}
void insertXandY() {
int x = mouseX;
int y = mouseY;
xPos[numPoints] = x;
yPos[numPoints] = y;
numPoints++;
}
void deleteLeftMost(){
// find leftmost index
// start with a large X value
int smallestX = width;
int smallestXIndex = -1;
// iterate through each X
for(int i = 0 ; i < numPoints; i++){
// if xPos[i] is smaller than the smallest value so far...
if (xPos[i] < smallestX){
// ...remember it's value and index
smallestX = xPos[i];
smallestXIndex = i;
}
}
// delete the item at this index: fake it for now: move coordinates offscreen (to the right so left search still works)
xPos[smallestXIndex] = width * 2;
}
void printArrays() {
println("X Positions");
for (int i = 0; i < 20; i++) {
println("\t" + xPos[i]);
}
}
void keyPressed() {
if (key == 'p') {
printArrays();
}
if (keyCode == DELETE || keyCode == BACKSPACE){
deleteLeftMost();
}
}
I've made a few of other minor adjustments:
deleted start since it was assigned but not used (when debugging delete anything that isn't necessary)
renamed numPointsX to numPoints and deleted numPointsY: you are using two arrays indeed, however there is only one index for each point that could be re-used to access each array
numPoints++ is shorthand for numPoints = numPoints + 1;
Also, I've used a hacky placeholder for the remove a point just visually.
This means in terms of memory the xPos/yPos for deleted points will still be allocated.
To actually delete the array is a bit tricker since the array datatype does not change size, however you could manually put something together using subset() and concat(). You can achieve a similar effect to deleting an element by concatenating two subset array: from the start to the index to delete and from the index next to the one to delete to the end of the array.
Something like this:
void setup(){
println(deleteIndex(new int[]{1,2,3,4,5,6},-1));
println(deleteIndex(new int[]{1,2,3,4,5,6},2));
println(deleteIndex(new int[]{1,2,3,4,5,6},6));
}
int[] deleteIndex(int[] sourceArray, int indexToDelete){
if(sourceArray == null){
System.err.println("can't process null array");
return null;
}
if(indexToDelete < 0){
System.err.println("invalid index " + indexToDelete + "\nit's < 0");
return null;
}
if(indexToDelete >= sourceArray.length){
System.err.println("invalid index " + indexToDelete + "\nmax index = " + sourceArray.length);
return null;
}
return concat(subset(sourceArray, 0, indexToDelete),
subset(sourceArray, indexToDelete + 1, sourceArray.length - indexToDelete - 1));
}
It's a good idea to check arguments to a method to ensure they are valid and test with at least a few edge cases.
Here's a version of the above sketch using this delete method:
float colour = random(256);
final int DIAM = 20;
final int MAX_NUM = 1000;
int numPoints = 0;
int [] xPos = new int[MAX_NUM];
int [] yPos = new int [MAX_NUM];
void setup() {
size (500, 500);
}
void draw() {
background(150);
fill(random(256), random(256), random(256));
for (int i=0; i < numPoints; i++) {
circle(xPos[i], yPos[i], DIAM);
}
}
void mouseClicked() {
insertXandY();
}
void insertXandY() {
int x = mouseX;
int y = mouseY;
xPos[numPoints] = x;
yPos[numPoints] = y;
numPoints++;
}
void deleteLeftMost(){
// find leftmost index
// start with a large X value
int smallestX = width;
int smallestXIndex = -1;
// iterate through each X
for(int i = 0 ; i < numPoints; i++){
// if xPos[i] is smaller than the smallest value so far...
if (xPos[i] < smallestX){
// ...remember it's value and index
smallestX = xPos[i];
smallestXIndex = i;
}
}
// delete xPos item at this index
xPos = deleteIndex(xPos, smallestXIndex);
// delete yPos as well
yPos = deleteIndex(yPos, smallestXIndex);
// update size counter
numPoints--;
}
int[] deleteIndex(int[] sourceArray, int indexToDelete){
if(sourceArray == null){
System.err.println("can't process null array");
return null;
}
if(indexToDelete < 0){
System.err.println("invalid index " + indexToDelete + "\nit's < 0");
return null;
}
if(indexToDelete >= sourceArray.length){
System.err.println("invalid index " + indexToDelete + "\nmax index = " + sourceArray.length);
return null;
}
return concat(subset(sourceArray, 0, indexToDelete),
subset(sourceArray, indexToDelete + 1, sourceArray.length - indexToDelete - 1));
}
void printArrays() {
println("X Positions");
for (int i = 0; i < xPos.length; i++) {
println("\t" + xPos[i]);
}
}
void keyPressed() {
if (key == 'p') {
printArrays();
}
if (keyCode == DELETE || keyCode == BACKSPACE){
deleteLeftMost();
}
}
If manually deleting an item from an array looks tedious it's because it is :)
Array is meant to be fixed size: deleting an item actually allocates 3 arrays: two subset arrays and one for concatenation.
A better option is to use a dynamic sized array data structure like ArrayList. Speaking of data structures, to represent a point you can use the PVector class (which has x,y properties, but can also do much more).
You might have not encountered ArrayList and PVector yet, but there are plenty of resources out there (including CodingTrain/NatureOfCode videos).
Here's an example using these:
final int DIAM = 20;
final int MAX_NUM = 1000;
ArrayList<PVector> points = new ArrayList<PVector>();
void setup() {
size (500, 500);
}
void draw() {
background(150);
fill(random(256), random(256), random(256));
for (PVector point : points) {
circle(point.x, point.y, DIAM);
}
}
void mouseClicked() {
insertXandY();
}
void insertXandY() {
if(points.size() < MAX_NUM){
points.add(new PVector(mouseX, mouseY));
}
}
void deleteLeftMost(){
// find leftmost index
// start with a large X value
float smallestX = Float.MAX_VALUE;
int smallestXIndex = -1;
// iterate through each X
for(int i = 0 ; i < points.size(); i++){
PVector point = points.get(i);
// if xPos[i] is smaller than the smallest value so far...
if (point.x < smallestX){
// ...remember it's value and index
smallestX = point.x;
smallestXIndex = i;
}
}
// remove item from list
points.remove(smallestXIndex);
}
void keyPressed() {
if (key == 'p') {
println(points);
}
if (keyCode == DELETE || keyCode == BACKSPACE){
deleteLeftMost();
}
}
Hopefully this step by step approach is easy to follow.
Have fun learning !
Related
I have tried many methods, and can't seem to grasp the idea of extracting an index from my array of strings to help me generate my desired number of building with a desired height, please help, here is my example
edit: Hi, i saw your feedback and posted my code below, hopefully it helps with the idea overall, as much as it is just creating rects, its more complicated as i need to involve arrays and string splitting along with loops. i more or less got that covered but i as i said above, i cannot extract the values from my array of string and create my facades at my own desired number and height
String buffer = " ";
String bh = "9,4,6,8,12,2";
int[] b = int(split(bh, ","));
int buildingheight = b.length;
void setup () {
size(1200, 800);
background(0);
}
void draw () {
}
void Textbox() {
textSize(30);
text(buffer, 5, height-10);
}
void keyTyped() {
if (key == BACKSPACE) {
if (buffer.length() > 0) {
buffer = buffer.substring(0, buffer.length() - 1);
}
} else if (key == ENTER) {
background(0);
stroke(0);
GenerateFacade();
println(buffer);
}
else {
buffer = buffer + key;
Textbox();
}
}
void GenerateFacade() {
fill(128);
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b.length; j++) {
if (int(b[j]) > buildingheight) {
buildingheight = int(b[j]);
}
}
rect(i*width/b.length, height - (int(b[i])*height/buildingheight), width/b.length, int(b[i])*height/buildingheight);
}
}
For the next time it would be great if you provide us with some code so we know what you tried and maybe can point you to the problem you have.
You need just the keyPressed function and some variables
int x = 0;
int buildingWidth = 50;
int buildingHeight = height / 6;
void setup(){
size(1000, 500);
background(255);
}
void draw(){
}
void keyPressed(){
if(key >= '0' && key <= '9'){
int numberPressed = key - '0' ;
fill(0);
rect(x, height - buildingHeight * numberPressed,
buildingWidth, buildingHeight * numberPressed);
x += buildingWidth;
}
}
This is my result
I am making an asteroid game using Processing 3.5.3. As you will see the collision detection is very buggy. When it detects collision between ship/asteroid sometimes it is greater than the asteroid size, sometimes it is smaller. Also, when the asteroids get smaller, the collision detect still seems to be calling the larger size asteroid. The collision between bullet and asteroid seems to only be a hit when the bullet is in the center of the asteroid.
Apologies for all the comments - they are required for my internal documentation.
Here is my code, it is broken up into classes.
Ship
class Ship {
PVector shipAcceleration;
PVector shipVelocity;
PVector shipPosition;
PShape shipShape;
float shipDirection;
int shipLastFire; //holds the time in millis that the last bullet was fired
int shipDelayTime;
Ship() {
shipAcceleration = new PVector();
shipVelocity = new PVector();
shipPosition = new PVector(width/2, height/2); // player starts in middle of screen
shipDirection = 0; // set to 0 to so "up" is a sense of direction
shipLastFire = 0;
shipDelayTime = 300;
keys = new boolean[5];
shipShape = createShape();
shipShape.beginShape();
shipShape.fill(255, 0, 0);
shipShape.vertex(0, -4);
shipShape.vertex(2, 0);
shipShape.vertex(2, 2);
shipShape.vertex(0, 1);
shipShape.vertex(-2, 2);
shipShape.vertex(-2, 0);
shipShape.vertex(0, -4);
shipShape.endShape();
}
void moveShip() {
shipShape.resetMatrix();
// reset.Matrix sourced from https://processing.org/reference/resetMatrix_.html
shipShape.rotate(radians(shipDirection)); // rotates ship
shape(shipShape, shipPosition.x, shipPosition.y, 10, 10);
}
void updateShip() {
// motion sourced from Chapter 22 of 'Processing: A programming handbook
// for visual designers and asrtists' by Casey Reas and Ben Fry
shipAcceleration.x = 0;
shipAcceleration.y = 0;
if (keys[0]) {
shipAcceleration.x = 0.5 * cos(radians(shipDirection) - PI/2);
shipAcceleration.y = 0.5 * sin(radians(shipDirection) - PI/2);
}
if (keys[1] && !keys[2])
{
shipDirection -= 5;
}
if (keys[2] && !keys[1])
{
shipDirection += 5;
}
shipVelocity.add(shipAcceleration);
// add sourced from https://processing.org/reference/PVector_add_.html
shipPosition.add(shipVelocity);
shipVelocity.mult(.95);
// mult sourced from https://processing.org/reference/PVector_mult_.html
shipPosition.x %= width;
if (shipPosition.x < -10)
{
shipPosition.x = width;
}
shipPosition.y %= height;
if (shipPosition.y < -10)
{
shipPosition.y = height;
}
if (keys[4]) {
if (millis() - shipLastFire > shipDelayTime) {
shipLastFire = millis();
fireBullet(shipPosition, shipVelocity, shipDirection);
}
}
}
}
Bullet
class Bullet {
PVector bulletPosition;
PVector bulletVelocity;
boolean bulletHidden; // used if lifespan is max and to help recycle
int bulletSize;
int bulletCreationTime;
int bulletLifespan; //the time in milli seconds that bullets last
int bulletSpeed;
Bullet() {
bulletHidden = true;
bulletSize = 5;
bulletPosition = new PVector();
bulletVelocity = new PVector();
bulletCreationTime = 0;
bulletLifespan = 3000;
bulletSpeed = 5;
}
void updateBullet() {
if (!bulletHidden) {
bulletPosition.add(bulletVelocity);
if (millis() - bulletCreationTime > bulletLifespan)
// millis sourced from https://processing.org/reference/millis_.html
{
bulletHidden = true;
}
bulletPosition.x %= width;
if (bulletPosition.x < -1)
{
bulletPosition.x = width;
}
bulletPosition.y %= height;
if (bulletPosition.y < -1)
{
bulletPosition.y = height;
}
}
}
void drawBullet() {
if (!bulletHidden) {
updateBullet();
ellipse(bulletPosition.x, bulletPosition.y, bulletSize, bulletSize);
}
}
void reset(PVector pos, PVector spe, float direct) {
bulletPosition = new PVector(pos.x + (20 * cos(radians(direct) - PI/2)), pos.y + (20 * sin(radians(direct) - PI/2)));
bulletVelocity.x = bulletSpeed * cos(radians(direct) - PI/2) + spe.x;
bulletVelocity.y = bulletSpeed * sin(radians(direct) - PI/2) + spe.y;
bulletCreationTime = millis();
bulletHidden = false;
}
}
Asteroid
class Asteroid {
float asteroidSize = (width/80*12);
float x;
float y;
float velocityX;
float velocityY;
PVector[] vertices = new PVector[8];
boolean active = true; //false after collision
int level = 1; // how many times has it been shot. Level 1 is not yet shot
Asteroid(float xPos, float yPos, int aLevel) {
if (xPos == 0 && yPos == 0) { //if begin level asteroids
x = random(width) ; // set random start positions
y = random (height);
} else { // if collision generating 2 smaller asteroids
x = xPos; // set from asteroid x, y
y = yPos;
}
velocityX = random(-2, 2);
velocityY = random(-2, 2);
level = aLevel; //sets asteroid level (how many times shot)
//create polygon. /aLevel generates smaller polygons with each collision.
vertices[0] = new PVector(random (width/80*3/aLevel), random(height/80*3/aLevel) );
vertices[1] = new PVector(random((width/80*4/aLevel), (width/80*8/aLevel)), random(height/80*3/aLevel) );
vertices[2] = new PVector(random((width/80*9/aLevel), (width/80*12/aLevel)), random(height/80*3/aLevel) );
vertices[3] = new PVector(random((width/80*9/aLevel), (width/80*12/aLevel)), random((height/80*4/aLevel), (height/80*8/aLevel)) );
vertices[4] = new PVector(random((width/80*9/aLevel), (width/80*12/aLevel)), random((height/80*9/aLevel), (height/80*12/aLevel)) );
vertices[5] = new PVector(random((width/80*4/aLevel), (width/80*8/aLevel)), random((height/80*9/aLevel), (height/80*12/aLevel)) );
vertices[6] = new PVector(random(width/80*3/aLevel), random((height/80*9/aLevel), (height/80*12/aLevel)) );
vertices[7] = new PVector(random(width/80*3/aLevel), random((height/80*4/aLevel), (height/80*8/aLevel)) );
}
void moveAsteroid() {
x = x + velocityX; //asteroids to move with a random velocity
y = y + velocityY;
if ( x < -1 * asteroidSize ) {
x = width + asteroidSize;
} //if off screen left, come back in right
if ( x > width + asteroidSize ) {
x = -1 * asteroidSize;
} // if off screen right, come back in left
if ( y < -1 * asteroidSize ) {
y = height + asteroidSize;
} //if off top of screen, come back in bottom
if ( y > height + asteroidSize ) {
y = -1 * asteroidSize ;
} //if off bottom of screen, come back in top
}
void asteroidDraw() {
if (active == false) { // If not active don't draw
return;
}
stroke(150);
fill(255);
// this was how I orginally coded. Have kept commented out for now, so I can see what I did, but will delete before submission.
/*beginShape();
vertex(vertices[0].x, vertices[0].y );
vertex(vertices[1].x, vertices[1].y );
vertex(vertices[2].x, vertices[2].y );
vertex(vertices[3].x, vertices[3].y );
vertex(vertices[4].x, vertices[4].y );
vertex(vertices[5].x, vertices[5].y );
vertex(vertices[6].x, vertices[6].y );
vertex(vertices[7].x, vertices[7].y );
endShape(CLOSE); */
beginShape();
for (PVector v : vertices) {
vertex(x+v.x, y+v.y);
}
endShape(CLOSE);
}
void manDown() {
active = false; //sets to in active so will stop drawing
// add 2 new asteroids to array
asteroids = (Asteroid[]) append( asteroids, new Asteroid( x+20, y+20, level + 1 ) ); // Appends asteroid to array. Changing level makes the asteroid smaller.
asteroids = (Asteroid[]) append( asteroids, new Asteroid( x-20, y-20, level + 1 ) ); // Appends two smaller asteroids to array.
}
}
Game Manager
class GameManager {
int scoreCount;
boolean gameState = true;
int lifeCount;
void newGame()
{
gameState = true; //sets game state to in play
scoreCount = 0; //set counter of flies killed to 0
lifeCount = 3;
}
void scoreUpdate()
{
textSize(width*3/100);
textAlign(LEFT);
fill(255);
text("Score " + scoreCount, (width*2/100), (height*4/100));
}
void lifeLost()
{
lifeCount = lifeCount - 1;
if (lifeCount <= 0) {
gameState = false;
gameOver();
}
}
void lifeUpdate()
{
textSize(height*3/100);
textAlign(LEFT);
fill(255);
text("Lives " + lifeCount, (width*2/100), ((height*4/100) + (height*3/100)) );
}
void gameOver()
{
background(0);
textSize(height*5/100);
textAlign(CENTER);
fill(255);
text("Game over", width/2, height/2.6);
//play again button
fill(255);
rect(((width/2)-(width/4)), (((height/2)- (height/12))), width/2, height/8);
fill(0);
text("Play Again", width/2, height/2);
//define area for play again button collision
if (mousePressed)
{
if (
(mouseX > width/4) &&
(mouseX < width/4 +width/2) &&
(mouseY > (height/2-height/10.5)) &&
(mouseY < ((height/2-height/10.5) + height/8))
)
{
setup(); //reset game
}
}
}
}
Main
Asteroid[] asteroids; //K Level 1 starts with 6, add 2 each level, 10 levels
Ship myShip;
GameManager gameManager;
ArrayList<Bullet> bullets;
// Array help sourced from chapter 28 of 'Processing: A programming handbook
// for visual designers and asrtists' by Casey Reas and Ben Fry
int bulletIndex; // used to recycle bullets
// index sourced from https://py.processing.org/reference/list_index.html
int startNum = 6; //K begin game with 6 asteroids in the level
boolean[] keys; // boolean for storing keypressed/released
void setup() {
size(800, 800);
gameManager = new GameManager();
gameManager.newGame();
bulletIndex = 0;
bullets = new ArrayList<Bullet>();
keys = new boolean[5];
myShip = new Ship();
asteroids = new Asteroid [startNum]; //K
for (int a = 0; a < startNum; a++) { //K create asteroids in array
asteroids[a] = new Asteroid(0, 0, 1); //K
}
for (int i = 0; i < 20; i++)
{
bullets.add(new Bullet()); // create bullets
}
}
void draw() {
background(0);
collisionDetect();
gameManager.gameState = true;
myShip.updateShip(); // E
myShip.moveShip(); // E
for (int a = 0; a < asteroids.length; a++) { //K for asteroids in array
asteroids[a].moveAsteroid(); //K
asteroids[a].asteroidDraw(); //K
}
gameManager.scoreUpdate();
gameManager.lifeUpdate();
for (int i = 0; i < bullets.size(); i++)
{
bullets.get(i).drawBullet(); // drawing bullets
}
}
void keyPressed() {
if (key == CODED) {
if (keyCode == UP)
keys[0] = true;
if (keyCode == LEFT)
keys[1] = true;
if (keyCode == RIGHT)
keys[2] = true;
if (keyCode == DOWN)
keys[3] = true;
} else {
if (key == 'w')
keys[0] = true;
if (key == 'a')
keys[1] = true;
if (key == 'd')
keys[2] = true;
if (key == 's')
keys[3] = true;
if (key == ' ')
keys[4] = true;
}
}
void keyReleased() {
if (key == CODED) {
if (keyCode == UP)
keys[0] = false;
if (keyCode == LEFT)
keys[1] = false;
if (keyCode == RIGHT)
keys[2] = false;
if (keyCode == DOWN)
keys[3] = false;
} else {
if (key == 'w')
keys[0] = false;
if (key == 'a')
keys[1] = false;
if (key == 'd')
keys[2] = false;
if (key == 's')
keys[3] = false;
if (key == ' ')
keys[4] = false;
}
}
void fireBullet(PVector pos, PVector spe, float dir) {
bullets.get(bulletIndex).reset(pos, spe, dir);
// set attributes of last used bullet
// get sourced from https://processing.org/reference/get_.html
bulletIndex++; //update index
bulletIndex %= bullets.size(); //keep index in range
}
void collisionDetect(){
Asteroid testHolder;
Bullet bulletHolder;
// asteroid and bullet objects to minimize creating new objects
for(int i = 0; i < asteroids.length; i++){
testHolder = asteroids[i];
if(dist(testHolder.x, testHolder.y, myShip.shipPosition.x,
myShip.shipPosition.y) < testHolder.asteroidSize)
// collision of player and the asteroid
{gameManager.gameOver();}
for(int j = 0; j < bullets.size(); j++){
bulletHolder = bullets.get(j);
// pull and store each bullet from the list
if(bulletHolder.bulletHidden){continue;}
// don't calculate anything if it is hidden
if(dist(testHolder.x, testHolder.y, bulletHolder.bulletPosition.x,
bulletHolder.bulletPosition.y) < testHolder.asteroidSize){
testHolder.manDown();
// used to detect collision and split if collided
bulletHolder.bulletHidden = true;
// hide the bullet so it won't go 'through' the asteroids
j++;
}
}
}
}
For the problem with the smaller asteroids, you need to make the asteroidSize dependent on the level. Currently they are all the same: float asteroidSize = (width/80*12);
As the to collision issue, the first thing is that you also have to take the size to the ship/bullet hitting the asteroid into account:
if(dist(testHolder.x, testHolder.y, myShip.shipPosition.x, myShip.shipPosition.y) < (testHolder.asteroidSize + myShip.size))
For clarity: size is in both cases the radius.
Second, there will always be some area's where this basic type of collision detection does not follow the visual, because your shapes are not circles. The randomness that you use for the asteroids does not help in that respect. A way to get more control over this is to define a couple of shapes per level, and pick one of those at random when creating an asteroid. This way you can tweak the shape/radius to make a good trade off between looks and function so it looks 'believable enough'.
I'm currently working on a school project and I'm trying to make a game similar to galaga. My problem is that whenever the bullet hits the enemy, another enemy would disappear. I believe this is because of the fact that I'm using a for loop and the enemies are being deleted in sequential order. Another problem I am having is with the bullets, I do not know why it slows down and eventually disappears as the number of the enemies decreases. Any help is appreciated.
ArrayList<enemy> e = new ArrayList<enemy>();
ArrayList<bullet> b = new ArrayList<bullet>();
boolean shoot = false;
void setup() {
fullScreen();
//enemy
for (int i = 0; i<5; i++) {
e.add(new enemy(50, 50));
}
//bullet
for (int i = 0; i<5; i++) {
b.add(new bullet(mouseX, mouseY));
}
}
void draw() {
background(255);
for (int p = 0; p<e.size(); p++) {
for (int i = 0; i<b.size(); i++) {
bullet a = b.get(i);
enemy o = e.get(p);
if (a.update()) {
b.remove(i);
}
if (o.col()) {
b.remove(i);
e.remove(i);
}
}
}
//enemy
for (int i = 0; i<e.size(); i++) {
enemy a = e.get(i);
a.display();
}
}
void mouseReleased() {
shoot = true;
b.add(new bullet(mouseX, mouseY));
}
class enemy {
int x, y, w, h;
int enemyX = int(random(width));
int enemyY = int(random(200));
public enemy(int tempenemyW, int tempenemyH) {
int tempenemyX = enemyX;
int tempenemyY = enemyY;
this.x = tempenemyX;
this.y = tempenemyY;
this.w = tempenemyW;
this.h = tempenemyH;
}
void display() {
fill(255, 0, 0);
rect(this.x, this.y, this.w, this.h);
}
boolean col() {
for (int i = 0; i<b.size(); i++) {
bullet a = b.get(i);
if (a.x+a.w>this.x && a.x<this.x+this.w && a.y+a.h+a.bulletSpeed>this.y && a.y+a.bulletSpeed<this.y+this.h) {
return true;
}
}
return false;
}
}
class bullet {
int x, y, w, h;
int bulletSpeed = 10;
public bullet(int tempx, int tempy) {
int tempw = 3;
int temph = 20;
this.x = tempx;
this.y = tempy;
this.w = tempw;
this.h = temph;
}
boolean update() {
this.y -= bulletSpeed;
fill(0, 255, 0);
rect(this.x, this.y, this.w, this.h, 100, 100, 100, 100);
if (x<0 || x>width || y<0 || y>height) {
return true;
} else {
return false;
}
}
}
Your removing the enemy that lives at the index of the bullet instead of the enemy at the index of the enemy. To fix this, try changing the line
e.remove(i);
to
e.remove(p);
I also recommend that you give better variable names. The reason that this was confusing for you is because "i" and "p" aren't very descriptive or helpful. It would have been easier to spot the mistake if the middle of the draw function looked like this:
for (int enemyIndex = 0; enemyIndex<e.size(); enemyIndex++) {
for (int bulletIndex = 0; bulletIndex<b.size(); bulletIndex++) {
bullet currentBullet = b.get(bulletIndex);
enemy currentEnemy = e.get(enemyIndex);
if (a.update()) {
b.remove(bulletIndex);
}
if (currentEnemy.col()) {
b.remove(bulletIndex);
e.remove(bulletIndex); // Clearly the wrong index!
}
}
}
Then you could go further by changing the names of your lists to "bullets" and "enemies" instead of just "b" and "e" :p
Teddy's answer is half the story. The other half of the story is that you're removing items from the list as you loop over it.
Let's say you have a loop like this:
for(int index = 0; index < list.size(); index++){
if(list.get(index).contains("remove me")){
list.remove(index);
}
}
And let's say your list looks like this:
0: "keep"
1: "remove me one"
2: "remove me two"
3: "keep"
Go through the loop with this list in mind. When index is 0, it sees "keep" and doesn't do anything. Now index is 1 and it sees "remove me one" so it removes the item at index 1 and every index after that shifts down one, making the list this:
0: "keep"
1: "remove me two"
2: "keep"
But index is still 1 at the end of the loop, so it increases to 2, and the next iteration sees "keep".
In other words, we skip over "remove me two" because we never check that index when it's shifted down by one.
The solution to this problem is to either use an Iterator or to loop backwards over the list.
Shameless self-promotion: I wrote a tutorial on using ArrayLists in Processing available here. See the section on removing items from an ArrayList.
I'm working on this code to manage and save data coming from the Microsoft kinect, the data are stored in the int array int[] depthValues, what I'd like to do is to store and save an average of more frames (let's say 10), in order to get smoother data, leaving the remaining part of the code as it is.
Here's the code:
import java.io.File;
import SimpleOpenNI.*;
import java.util.*;
SimpleOpenNI kinect;
void setup()
{
size(640, 480);
kinect = new SimpleOpenNI(this);
kinect.enableDepth();
}
int precedente = millis();
void draw()
{
kinect.update();
PImage depthImage = kinect.depthImage();
image(depthImage, 0, 0);
int[] depthValues = kinect.depthMap();
StringBuilder sb = new StringBuilder();
Deque<Integer> row = new LinkedList<Integer>();
int kinectheight = 770; // kinect distance from the baselevel [mm]
int scaleFactor = 1;
int pixelsPerRow = 640;
int pixelsToSkip = 40;
int rowNum = 0;
for (int i = 0; i < depthValues.length; i++) {
if (i > 0 && i == (rowNum + 1) * pixelsPerRow) {
fillStringBuilder(sb, row);
rowNum++;
sb.append("\n");
row = new LinkedList<Integer>();
}
if (i >= (rowNum * pixelsPerRow) + pixelsToSkip) {
row.addFirst((kinectheight - depthValues[i]) * scaleFactor);
}
}
fillStringBuilder(sb, row);
String kinectDEM = sb.toString();
final String[] txt= new String[1]; //creates a string array of 2 elements
int savingtimestep = 15000; // time step in millisec between each saving
if (millis() > precedente + savingtimestep) {
txt[0] = "ncols 600\nnrows 480\nxllcorner 0\nyllcorner 0\ncellsize 91.6667\nNODATA_value 10\n" +kinectDEM;
saveStrings("kinectDEM0.tmp", txt);
precedente = millis();
// delete the old .txt file, from kinectDEM1 to kinectDEMtrash
File f = new File (sketchPath("kinectDEM1.txt"));
boolean success = f.delete();
// rename the old .txt file, from kinectDEM0 to kinectDEM1
File oldName1 = new File(sketchPath("kinectDEM0.txt"));
File newName1 = new File(sketchPath("kinectDEM1.txt"));
oldName1.renameTo(newName1);
// rename kinectDEM0.tmp file to kinectDEM0.txt
File oldName2 = new File(sketchPath("kinectDEM0.tmp"));
File newName2 = new File(sketchPath("kinectDEM0.txt"));
oldName2.renameTo(newName2);
}
}
void fillStringBuilder(StringBuilder sb, Deque<Integer> row) {
boolean emptyRow = false;
while (!emptyRow) {
Integer val = row.pollFirst();
if (val == null) {
emptyRow = true;
} else {
sb.append(val);
val = row.peekFirst();
if (val != null) {
sb.append(" ");
}
}
}
}
You have an int[] array variable named depthValues. You can use this value just like you can use any other value. In other words, you can create an array or ArrayList that holds multiple int[] values.
Here's how you might use an ArrayList to hold previous values:
ArrayList<int[]> previousDepthValues = new ArrayList<int[]>();
void draw(){
//add current depth map to ArrayList
previousDepthValues.add(kinect.depthMap());
//limit the ArrayList to hold 10 values
if(previousDepthValues.size() == 11){
previousDepthValues.remove(0);
}
//create an array to hold the averaged values
int[] averageDepthValues = new int[previousDepthValues.get(0).length];
//loop over the 10 previous depth values in the ArrayList
for(int[] depthValue : previousDepthValues){
//loop over the ints in each previous depth values array
for(int i = 0; i < averageDepthValues.length; i++){
//add all of the values up
averageDepthValues[i] += depthValue[i];
}
}
//divide each number to get the average
for(int i = 0; i < averageDepthValues.length; i++){
averageDepthValues[i] /= averageDepthValues.length;
}
//averageDepthValues now holds the average of the last 10 frames
}
I'm trying to save an image after certain time, the problem is that the image size is bigger than the display so when I use the save or saveFrame function it only saves the image that I can see in the display. There is any other way to save the whole image?
This is my code:
PImage picture, pictureFilter, img;
int total, cont, current;
ArrayList<ArrayList<Position>> columns;
String[] fontList;
public class Position {
public int x;
public int y;
}
void setup() {
fontList = PFont.list();
picture = loadImage("DSC05920b.JPG");
pictureFilter = loadImage("filtrePort2.jpg");
frame.setResizable(true);
size(picture.width, picture.height);
columns = new ArrayList<ArrayList<Position>>();
for(int i = 0; i < picture.width; i++) {
ArrayList<Position> row = new ArrayList<Position>();
for(int j = 0; j < picture.height; j++){
Position p = new Position();
p.x = i;
p.y = j;
row.add(p);
}
columns.add(row);
}
total = picture.width * picture.height;
cont = total;
current = 0;
img = createImage(picture.width, picture.height, RGB);
}
float randomLetter() {
float value = 23;
boolean found = false;
while(!found) {
value = random(48, 122);
if(value >48 && value <58) found = true;
if(value >65 && value <91) found = true;
if(value >97 && value <123) found = true;
}
return value;
}
void draw() {
int x = int(random(0, columns.size()));
ArrayList<Position> rows = columns.get(x);
int y = int(random(0, rows.size()));
Position p = rows.get(y);
color c = pictureFilter.get(p.x, p.y);
int r = (c >> 16) & 0xFF; // Faster way of getting red(argb)
if(r < 240) {
PFont f = createFont(fontList[int(random(0,fontList.length))],random(5, 24),true);
textFont(f);
fill(picture.get(p.x,p.y));
char letter = (char) int(randomLetter());
text(letter, p.x, p.y);
}
if(rows.size() == 1) {
if(columns.size() == 1) {
saveFrame("lol.jpg");
columns.remove(x);
} else {
columns.remove(x);
}
} else {
println(rows.size());
rows.remove(y);
}
--cont;
float percent = float(total-cont)/float(total)*100;
if(int(percent) != current) {
current = int(percent);
save("image_" + current + ".jpg");
}
println("DONE: " + (total-cont) + "/" + total + " Progress: " + percent + "%");
}
The code do a lot of stuff but the part that its not working well is at the final when I check if the percentage have been increased in order to save the image
You can write this into a PGraphics context - aka a graphics buffer.
The buffer can be as big as you need it to be, and you can choose whether to draw it on the screen or not..
// Create the buffer at the size you need, and choose the renderer
PGraphics pg = createGraphics(myImage.width, myImage.height, P2D);
// Wrap all your drawing functions in the pg context - e.g.
PFont f = createFont(fontList[int(random(0,fontList.length))],random(5, 24),true);
textFont(f);
pg.beginDraw();
pg.fill(picture.get(p.x,p.y));
char letter = (char) int(randomLetter());
pg.text(letter, p.x, p.y);
pg.endDraw();
// Draw your PG to the screen and resize the representation of it to the screen bounds
image(pg, 0, 0, width, height); // <-- this wont actually clip/resize the image
// Save it
pg.save("image_" + current + ".jpg");
The PImage class contains a save() function that exports to file. The API should be your first stop for questions like this.