I am currently building Space Invaders in Processing and I do not absolutely understand why this happens, it is hard to explain, so here is all the code that goes with the game:
SpaceInvaders.pde:
/* Jordan Green
April 11th, 2018
This is the main class for the game
Space Invaders.
This is what sets up the game.
*/
//My objects declared.
Alien aliens;
Player player;
Score score;
PImage img;
//sets up the variables and gives them values.
void setup() {
aliens = new Alien();
player = new Player();
score = new Score();
size (600, 600);
img = loadImage("Space Background.jpg");
}
//draws out the program.
void draw() {
background(0);
image(img, 0, 0, height, width);
player.show();
player.move();
player.playerLives();
player.alienDie();
aliens.show();
aliens.move();
score.show();
if (player.playerLife == 0) {
}
}
void keyPressed() {
if (key == ' ') {
player.shoot();
}
}
My question is why does an object.variable work on Processing? It's something I do not understand.
Jordan
Why wouldn't it work?
This is a fundamental feature of objects in Java, which Processing is built on top of. If you have a class that contains variables or functions, you can reference those variables or functions using the . dot operator.
Here's an example:
class MyClass{
int x = 42;
void sayHello(){
println("hello");
}
}
MyClass myInstanceOfMyClass = new MyClass();
println(myInstanceOfMyClass.x);
myInstanceOfMyClass.sayHello();
In Java you can mark variables and functions as private to restrict access, but this is less common in Processing.
You can read more about classes in the reference or in this tutorial.
I'm currently working on a project in which I want an image to pop up after 3 seconds. Once that image has popped up the user has to click on the image to make a "done" image pop up that will disappear automatically after 3 seconds.
I've got most of it working except for the disappearing part. Does anyone know how I can time the image to disappear after 3 seconds?
PImage medic;
PImage medicD;
float time;
float startTime;
final int waitpopup = 3000;
final int DISPLAY_DURATION = 3000;
boolean showimage = true;
boolean showclock = true;
boolean showimagedone = true;
boolean hasClicked;
Clock clock;
void setup (){
size (1080, 1920);
medic = loadImage("medic.png");
medicD = loadImage("medicD.png");
clock = new Clock(width /2, height /2);
time = millis();
}
void draw() {
background (0);
imageMode(CENTER);
if (showclock) clock.display();
if (showimage && millis() - time > waitpopup) {
image(medic, width/2, height/2, 540, 540);
} if (hasClicked == true) {
showimage = false;
image(medicD, width/2, height/2, 540, 540);
} if (millis() > startTime + DISPLAY_DURATION) {
showimagedone = false;
}
}
void mousePressed() {
hasClicked = true;
startTime = time;
}
You can use the millis() function or the frameCount variable to check how much time has gone by, then do something after X seconds or after X frames.
You're already doing some of the work with the showimagedone variable, but you need to use that variable to conditionally draw your image.
I recommend starting with a simpler example and getting that working. Here's one example:
int clickedFrame;
boolean on = false;
int duration = 60;
void draw(){
if(on){
background(255);
if(frameCount > clickedFrame + duration){
on = false;
}
}
else{
background(0);
}
}
void mousePressed(){
clickedFrame = frameCount;
on = true;
}
This code show a white background for one second whenever the user clicks the mouse. You need to do something similar with your images.
Related posts:
How to make a delay in processing project?
How can I draw only every x frames?
Removing element from ArrayList every 500 frames
Timing based events in Processing
How to add +1 to variable every 10 seconds in Processing?
How to create something happen when time = x
making a “poke back” program in processing
Processing: How do i create an object every “x” time
Timer using frameRate and frame counter reliable?
Adding delay in Processing
Please also consult the Processing reference for more information.
If you still can't get it working, please post a MCVE (not your full project!) in a new question and we'll go from there. Good luck.
I just made my image generator work with PNG files. For now, it's divided into 3 categories (backgrounds, objects & texts). These are now all combined, and with every mouse click it randomises these PNGs.
I made three toggles, where you could to choose to show either the background and the objects on top, all of them, or all separate. Whenever I run the sketch, it shows the "grey" background, but when I use the toggles, it doesn't show anything, or shows a flickering image, where the mouse-click can't be used to go to the next image. I can't seem to find the problem. Hopefully, you can help. :)
import controlP5.*;
boolean showBackground = false;
boolean showObjects = false;
boolean showGrids = false;
ControlP5 cp5;
PImage[] myImageArray = new PImage[8];
PImage[] myImageArray2 = new PImage[15];
PImage[] myImageArray3 = new PImage[15];
void setup() {
size(1436, 847);
background(211, 211, 211);
for (int i=0; i<myImageArray.length; i++) {
myImageArray[i] = loadImage ( "o" + i + ".png");
myImageArray2[i] = loadImage ( "g" + i + ".png");
myImageArray3[i] = loadImage( "b" + i + ".jpg");
cp5 = new ControlP5(this);
// create a toggle and change the default look to a (on/off) switch look
cp5.addToggle("showBackground")
.setPosition(40, 250)
.setSize(50, 20)
.setValue(true)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showObjects")
.setPosition(40, 400)
.setSize(50, 20)
.setValue(true)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showGrid")
.setPosition(40, 600)
.setSize(50, 20)
.setValue(true)
.setMode(ControlP5.SWITCH);
}
display();
}
void display() {
image(myImageArray3[(int)random(myImageArray.length)], 0, 0, 1436, 847); // b
image(myImageArray2[(int)random(myImageArray.length)], 0, 0, 1436, 847); // g
image(myImageArray[(int)random(myImageArray.length)], 0, 0, 1436, 847); // o
}
void mousePressed() {
display();
}
void draw() {
pushMatrix();
if (showBackground==false) {
image(myImageArray3[(int)random(myImageArray.length)], 0, 0, 1436, 847); // b
} else {
background(211, 211, 211);
}
if (showGrids==false) {
image(myImageArray2[(int)random(myImageArray.length)], 0, 0, 1436, 847); // g
} else {
background(211, 211, 211);
}
if (showObjects==false) {
image(myImageArray[(int)random(myImageArray.length)], 0, 0, 1436, 847); // o
} else {
background(211, 211, 211);
}
popMatrix();
}
Here are a couple of things where the logic your wrote in your code might not match what you had in mind:
When you call display() on mouse it renders those 3 images once (also it will be different images within those since it's using a randomised index). Similarly in draw(), when an does get picked to be rendered, frames will be flickering fast as a random index is generated multiple times per second(each frame). You may want to randomise indices in a different event (e.g. mouse or key press) and store this value in a variable you can re-use.
the conditions you use in draw(): you probably meant to check if the values are true(toggled enabled/turned on in controlP5) ? (e.g. e.g. if (showBackground==true) and initialise the toggles with false, instead of true?)
a big one: in draw() , after each condition(showBackground,showGrids,showObjects), if it's false, you're clearing the the whole frame (so a previous image would be erased)
you have 3 arrays, but you use the size of the first(myImageArray.length) only, which means, even though you may have more images for myImageArray2 and myImageArray3, you're not loading, nor displaying them.
The third grid is labeled "showGrid" when it should be "showGrids": if you aren't consistent with the toggle labels and variable names, toggles won't update the variable names.
you should use more descriptive names for the arrays: it will make it easier to scan/follow your code on the long run.
there's no need to add toggles multiple times in the for loop where you load images: once will do.
Here's what I mean:
import controlP5.*;
boolean showBackground = false;
boolean showObjects = false;
boolean showGrids = false;
ControlP5 cp5;
PImage[] objects = new PImage[8];
PImage[] grids = new PImage[15];
PImage[] backgrounds = new PImage[15];
int currentImage = 0;
void setup() {
size(1436, 847);
//load objects
for (int i=0; i<objects.length; i++) {
objects[i] = loadImage ( "o" + i + ".png");
}
//load grids
for(int i = 0 ; i < grids.length; i++){
grids[i] = loadImage ( "g" + i + ".png");
}
//load backgrounds
for(int i = 0 ; i < grids.length; i++){
backgrounds[i] = loadImage( "b" + i + ".jpg");
}
//setup UI
cp5 = new ControlP5(this);
// create a toggle and change the default look to a (on/off) switch look
cp5.addToggle("showBackground")
.setPosition(40, 250)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showObjects")
.setPosition(40, 400)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showGrids")
.setPosition(40, 600)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH);
}
void mousePressed() {
//go to next image index
currentImage = currentImage + 1;
//check if the incremented index is still valid, otherwise, reset it to 0 (so it doesn't go out of bounds)
if (currentImage >= objects.length) {
currentImage = 0;
}
}
void draw() {
//clear current frame
background(211);//for gray scale value you can just use one value: the brightness level :)
if (showBackground==true) {
image(backgrounds[currentImage], 0, 0, 1436, 847); // b
}
if (showGrids==true) {
image(grids[currentImage], 0, 0, 1436, 847); // g
}
if (showObjects==true) {
image(objects[currentImage], 0, 0, 1436, 847); // o
}
}
Note that currently the same index is used for all 3 arrays.
You may want to add a separate index variable for each array (e.g. currentObjectIndex, currentBackgroundIndex, currentGridIndex) that you can increment independently of each other.
I recommend having a bit more patience and double checking your code first.
Visualise what each line of code will do, then check if it actually does what you expect it to do. Either you will learn something new or improve your logic.
Also, if mentally joggling 3 arrays is tricky (and it can be), go one step back: try your logic with one array only until you get the hang of it, then move on.
A step backwards is sometimes a step forward when you're going in the wrong direction.
As creative as you'd like to be with Processing, bare in mind, the interface to plugging your ideas to it is still a series of one instruction at a time, each precisely tuned to do exactly what you want it to do. There's room for fun, but unfortunately you need to get past the boring parts first
I'm using Adobe Flash Professional CS6 to create the game. I'll post the code under. Be noticed that there are two symbol I've created using Flash that are not made by code. These symbols are the Crosshair symbol, and the Hitbox symbol. Basically, the objective of the game is to click the Hitbox symbol. My issue is that I am experiencing what seems to be bottlenecking issues. When I click the Hitbox symbol a lot of times with a fast timer the score doesn't register. I am pressuming that this comes from the (maybe) ineffective movement algorithm. But I can't really seem to find room for improvement. Some help would be appreciated.
Be noticed, I had to change the timer from Timer(1) to Timer(30). This made the bottlenecking issue a little bit better, but made the game less fluent.
Aah, and the reason as to why I am using the directionCheckerY and directionCheckerX variables is that I will later in the development add random movement. A random timer will change these to either 0 and 1, creating random movement.
import flash.events.MouseEvent;
import flash.events.TimerEvent;
// Variables
var directionCheckerX:int=0;
var directionCheckerY:int=0;
var pointChecker:int=0;
// Croshair
var crosshair:Crosshair = new Crosshair();
addChild(crosshair);
Mouse.hide();
function moveCrossEvent (evt: MouseEvent) {
crosshair.x = mouseX;
crosshair.y = mouseY;
evt.updateAfterEvent();
}
// Hitbox
var hitbox:Hitbox = new Hitbox();
addChild(hitbox);
hitbox.x=50;
hitbox.y=50;
// Timer
var myTimer:Timer = new Timer(30);
myTimer.addEventListener(TimerEvent.TIMER, timerEvent);
myTimer.start();
function timerEvent(evt:TimerEvent) {
// Border code (Keeps the Hitbox away from out of bounds)
if (hitbox.x <= 0) {
directionCheckerX = 1;
} else if (hitbox.x >= 550) {
directionCheckerX = 0;
}
if (directionCheckerX == 0) {
hitbox.x-=2;
} else {
hitbox.x+=2;
}
if (hitbox.y <= 0) {
directionCheckerY = 1;
} else if (hitbox.y >= 400) {
directionCheckerY = 0;
}
if (directionCheckerY == 0) {
hitbox.y-=2;
} else {
hitbox.y+=2;
}
}
// EventListeners
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveCrossEvent);
hitbox.addEventListener(MouseEvent.CLICK, hitboxEvent);
stage.addEventListener(MouseEvent.CLICK, stageEvent);
function hitboxEvent (evt:MouseEvent) {
pointChecker+=1;
outputTxt.text = String(pointChecker);
evt.stopImmediatePropagation();
//evt.updateAfterEvent();
}
function stageEvent(evt:MouseEvent) {
pointChecker-=1;
outputTxt.text = String(pointChecker);
}
To be clear, I'm not a game developer.
Actually, sometimes there is no big difference between a Timer with 1 millisecond interval and another one with 30 milliseconds interval because it's depending on the SWF file's framerate or the runtime environment ... but here, what about using an Event.ENTER_FRAME event instead of a Timer ? because as Adobe said here about Timers versus ENTER_FRAME events :
Choose either timers or ENTER_FRAME events, depending on whether content is animated.
Timers are preferred over Event.ENTER_FRAME events for non-animated content that executes for a long time.
and in your case the content is animated (even if your game is still basic).
Then you can use a var to set the speed of your hitbox which you can update at any time :
var speed:int = 2;
function timerEvent(evt:TimerEvent): void
{
// ...
if (directionCheckerX == 0) {
hitbox.x -= speed;
} else {
hitbox.x += speed;
}
// ...
}
Hope that can help.
I've written this code which creates a sketchbook.
I'm sure that there's a simple error, but why won't it stop playing at the end of the images?
Here is the code
import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
Minim minim;
AudioPlayer sou; //variable name;
final int NUMBER_IMAGES = 27;
PImage[] images; //sets PImage array
int framerate = 10;
int currentImage = 0;
String getImageName(int image_number) {
if (image_number == 0) { // == double equals checks for equality
return "title.gif"; //missing k0.gif and k26.gif until this line //added
} else if (image_number == 26) {
return "title2.gif";
} else {
return "data/K" + image_number + ".gif";
}
}
void setup () {
minim = new Minim(this); //define construction
sou = minim.loadFile("ambience.mp3");
sou.loop();
size (300, 300);
background (255);
frameRate(framerate);
imageMode (CENTER); // Tells the images to display relative to CENTRE
images = new PImage[NUMBER_IMAGES]; // initialises the array (not images)
for (int image_number = 0; image_number < NUMBER_IMAGES; image_number++) {
String filename; // Declared a String called filename
filename = getImageName(image_number);
images[image_number] = loadImage(filename);
}
}
void draw () {
// Set framerate
frameRate(framerate);
// Draws first image
image(images[currentImage], width/2.0, height/2.0);
currentImage++;
currentImage = currentImage % NUMBER_IMAGES;
}
void keyPressed() {
if (keyCode == UP) { // up arrow increases frame rate by one
framerate ++;
}
if (keyCode == DOWN) { //down arrow decreases framerate by one
framerate --;
}
}
I can't think of more details to add although I'm being told I can't post this as it is mostly code.
This line is the one that achieves the recurrent number loop.
currentImage = currentImage % NUMBER_IMAGES
What the % (Modulo) operator does is to calculates the remainder when one number is divided by another. So lets say for example that your NUMBER_IMAGES is 10, at first you'll have 1 & 10 and the value stored in currentImage would be 1. This continues until you reach 10 % 10 the value stored would be 0 and there you'll start all over again.
Here you can find more about the (Module) in Processing: https://www.processing.org/reference/modulo.html
Perhaps a more simple approach to achieve what you'll looking for would be to add a condition to stop when you reach the number of images.
void draw () {
// Set framerate
frameRate(framerate);
// Draws images
image(images[currentImage], width/2.0, height/2.0);
if(currentImage < NUMBER_IMAGES){
currentImage++;
}
}
Hope this helps.
Regards
Jose
Because you have this line inside your code it will show images forever
currentImage = currentImage % NUMBER_IMAGES
If you want stop drawing nex image simply change this line into something like this:
if(currentImage == NUMBER_IMAGES) noLoop()
noLoop() will stop whole draw() animation so it will display your last image. If you want then exit the animation you can add this to your keyPressed():
if (keyCode == ESC){
exit();
}
exit() will correctly exit your program. You can use this function instead of noLoop to end after last image.