We are about to switch to a new forum software. Until then we have removed the registration on this forum.
You could need more luck when it comes to naming variables.
better use streetLine1, streetLine2... instead of a,b,... or use an array. You might need a bit longer to type but you can read your code faster and find errors later on (like the collision problem you just had which was in fact a naming issue).
Also say obstacleX and obstacleY instead of j,z
Instead of noLoop()
you could have a lives counter and say lives=lives-1;
in case of a collision
Starting with int lives=3;
we would see game over after 3 collisions
Hello, I'm having problems with this collision thingy between the 2 rectangles, I know I'm supposed to use dist(), It worked when my object was controlled by mouse, but I can't make it work now with keys, any help would be appreciated! :)
Ship myShip;
int a=1;
int b=100;
int c=200;
int d=300;
int e=400;
int f=500;
int z=10;
int j=160;
boolean [] keys = new boolean[128];
void setup() {
size(500, 600);
smooth();
myShip = new Ship();
}
void gameOver() {
textAlign(CENTER);
text("GAME OVER", width / 2, height / 2);
}
void draw() {
background(0);
a=a+3;
b=b+3;
c=c+3;
d=d+3;
e=e+3;
f=f+3;
z=z+4;
rect(j,z+3,25,25);
rect(270,a+3,5,30);
rect(270,b,5,30);
rect(270,c,5,30);
rect(270,d,5,30);
rect(270,e,5,30);
rect(270,f,5,30);
rect(80,0,5,1500);
if (a>=600)
a=-10;
if (b>=600)
b=-10;
if (c>=600)
c=-10;
if (d>=600)
d=-10;
if (e>=600)
e=-10;
if (f>=600)
f=-10;
myShip.run();
}
void keyPressed() {
keys[key] = true;
}
void keyReleased() {
keys[key] = false;
}
class Ship {
PVector pos, vel;
float rotation;
Ship() {
pos = new PVector(160, height/2);
vel = new PVector(5, 5);
rotation = 0;
}
void run() { //generic function container
display();
move();
}
void display() {
pos.x=constrain(pos.x, 25, width);
pos.y=constrain(pos.y, 25, height);
pushMatrix();
translate(pos.x, pos.y);
rect(0, 0, 50, 50);
popMatrix();
if (pos.x>=260)
noLoop();
if (pos.x<=60)
noLoop();
if (pos.x>=260)
gameOver();
if (pos.x<=60)
gameOver();
if (dist(pos.x,pos.y,50,a+1)<25)
noLoop();
}
void move() {
if (keys['a']) //move left
pos.x -= vel.x;
if (keys['d']) //move right
pos.x += vel.x;
if (keys['w']) //move up
pos.y -= vel.y;
if (keys['s']) //move down
pos.y += vel.y;
}
}
You store your circles in an array. You are not comparing the circles against each other. So you have:
for (int j, i = 0; i < p.length; i++) {
p[i].display();
p[i].mouseOver();
}
You need instead
void draw() {
background(0);
if(p.length>1){ //Need to have more than 1 to check overlap
for (int i = 0; i < p.length; i++) {
for (int other = i; other < p.length; other++) {
boolean res=p[i].overlapOtherCircle(p[other]);
if(res==true){
//Overlap happened: Change the color of both the 'i' and 'other' object
}
else{
//Update the field of only i object with a non-overlapping color
}
}
}
}
for (int i = 0; i < p.length; i++) {
p[i].display();
}
}
and inside your class you need to define:
boolean overlapOtherCircle(Postac otherObj){
return dist(x,y,otherObj.x,otherObj.y) > (radius/2.0 + otherObj.radius/2.0);
}
Check this
www.jeffreythompson.org/collision-detection/index.php
https://forum.processing.org/two/discussion/24966/bouncing-balls-collision#latest
Notice there is a new forum at https://discourse.processing.org
Kf
LiquidFun can be found in the Add Library listing, it seems to be the best implementation of box2d for processing. Much higher and smoother framerates than the other two listed.
For a start I would point to the included example box2d_BrickWall and seeing if you can draw the bricks with a rect in place of the box2d rendering.
Here's my attempt. But this example doesn't move the box2d camera, the box2d_car example does and might be better, that's the part I was having problems with. Basically my scale settings are just tuned by hand to match, can't find a way to get it spot on. I've edited this to draw the bricks with rects instead of the box2d renderer
edit: I seem to have it kinda figured out enough
/**
*
* LiquidFunProcessing | Copyright 2017 Thomas Diewald - www.thomasdiewald.com
*
* https://github.com/diwi/LiquidFunProcessing.git
*
* Box2d / LiquidFun Library for Processing.
* MIT License: https://opensource.org/licenses/MIT
*
*/
import com.thomasdiewald.liquidfun.java.DwWorld;
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;
import processing.core.*;
import processing.opengl.PGraphics2D;
//
// Simple stacking demo.
//
//
// Controls:
//
// LMB ... drag bodies
// LMB + SHIFT ... shoot bullet
// MMB ... add particles
// RMB ... remove particles
// 'r' ... reset
// 't' ... update/pause physics
// 'f' ... toggle debug draw
//
int viewport_w = 1280;
int viewport_h = 720;
int viewport_x = 230;
int viewport_y = 0;
boolean UPDATE_PHYSICS = true;
boolean USE_DEBUG_DRAW = false;
DwWorld world;
ArrayList<Body> bricks = new ArrayList<Body>();
public void settings(){
size(viewport_w, viewport_h, P2D);
smooth(8);
}
public void setup(){
surface.setLocation(viewport_x, viewport_y);
reset();
world.setGravity(new Vec2(0,-32.0));
frameRate(60);
}
public void release(){
if(world != null) world.release(); world = null;
}
public void reset(){
// release old resources
release();
world = new DwWorld(this, 20);
// create scene: rigid bodies, particles, etc ...
initScene();
}
PVector pos = new PVector(0,0);
public void draw(){
pos = new PVector(22,32);
world.transform.setCamera(pos.x, pos.y/2);
if(UPDATE_PHYSICS){
world.update();
}
PGraphics2D canvas = (PGraphics2D) this.g;
canvas.background(32);
canvas.pushMatrix();
world.applyTransform(canvas);
world.drawBulletSpawnTrack(canvas);
if(USE_DEBUG_DRAW){
world.displayDebugDraw(canvas);
// DwDebugDraw.display(canvas, world);
} else {
world.bodies.display(canvas);
world.particles.display(canvas);
}
canvas.popMatrix();
pushMatrix();
scale(20,20);
//world.transform
translate(pos.x/-1.0,( pos.y/2 + -18));
for (Body b : bricks){
//Vec2 t = b.getTransform();
pushMatrix();
// Vec2 l = b.getWorldCenter();
Vec2 l = b.getWorldCenter();
translate(32+l.x,36-l.y);
rotate(-b.getAngle());
rect(-0.5, 0, 1.00,0.25);
//println( b.getContactList());
popMatrix();
}
popMatrix();
int num_bodies = world.getBodyCount();
int num_particles = world.getParticleCount();
String txt_fps = String.format(getClass().getName()+ " [bodies: %d] [particles: %d] [fps %6.2f]", num_bodies, num_particles, frameRate);
surface.setTitle(txt_fps);
}
//////////////////////////////////////////////////////////////////////////////
// User Interaction
//////////////////////////////////////////////////////////////////////////////
public void keyReleased(){
if(key == 'r') reset();
if(key == 't') UPDATE_PHYSICS = !UPDATE_PHYSICS;
if(key == 'f') USE_DEBUG_DRAW = !USE_DEBUG_DRAW;
}
//////////////////////////////////////////////////////////////////////////////
// Scene Setup
//////////////////////////////////////////////////////////////////////////////
public void initScene() {
float screen_scale = world.transform.screen_scale;
float b2d_screen_w = world.transform.box2d_dimx;
float b2d_screen_h = world.transform.box2d_dimy;
float b2d_thickness = 20 / screen_scale;
{
float radius = 25 / screen_scale;
CircleShape circle_shape = new CircleShape();
circle_shape.setRadius(radius);
FixtureDef fixture_def = new FixtureDef();
fixture_def.shape = circle_shape;
fixture_def.density = 10f;
fixture_def.friction = 0.30f;
fixture_def.restitution = 0.30f;
BodyDef body_def = new BodyDef();
body_def.type = BodyType.DYNAMIC;
body_def.angle = 0.0f;
body_def.position.x = -1/screen_scale;
body_def.position.y = b2d_screen_h - 10;
body_def.bullet = true;
Body circle_body = world.createBody(body_def);
circle_body.createFixture(fixture_def);
world.bodies.add(circle_body, true, color(64, 125, 255), true, color(0), 1f);
}
{ // Walls
BodyDef bd = new BodyDef();
bd.position.set(0, 0);
Body ground = world.createBody(bd);
PolygonShape sd = new PolygonShape();
float x, y, w, h;
// BOTTOM
x = 0;
y = 0;
w = b2d_screen_w;
h = b2d_thickness;
sd.setAsBox(w/2f, h/2f, new Vec2(x, y), 0.0f);
ground.createFixture(sd, 0f);
// TOP
x = 0;
y = b2d_screen_h;
w = b2d_screen_w;
h = b2d_thickness;
sd.setAsBox(w/2f, h/2f, new Vec2(x, y), 0.0f);
ground.createFixture(sd, 0f);
// LEFT
x = -b2d_screen_w/2;
y = +b2d_screen_h/2;
w = b2d_thickness;
h = b2d_screen_h - b2d_thickness;
sd.setAsBox(w/2f, h/2f, new Vec2(x, y), 0.0f);
ground.createFixture(sd, 0f);
// RIGHT
x = +b2d_screen_w/2;
y = +b2d_screen_h/2;
w = b2d_thickness;
h = b2d_screen_h - b2d_thickness;
sd.setAsBox(w/2f, h/2f, new Vec2(x, y), 0.0f);
ground.createFixture(sd, 0f);
world.bodies.add(ground, true, color(0), !true, color(0), 1f);
}
createWall(10, 20, 40, 20, 0, 10);
}
public void createWall(int numx, int numy, float dimx, float dimy, float tx, float ty){
float scree_scale = world.transform.screen_scale;
dimx /= scree_scale;
dimy /= scree_scale;
tx /= scree_scale;
ty /= scree_scale;
PolygonShape brick_shape = new PolygonShape();
brick_shape.setAsBox(dimx*0.5f, dimy*0.5f);
PolygonShape brick_shape2 = new PolygonShape();
brick_shape2.setAsBox(dimx*0.25f, dimy*0.5f);
FixtureDef fixture_def = new FixtureDef();
fixture_def.shape = brick_shape;
fixture_def.density = 40;
fixture_def.friction = 0.7f;
fixture_def.restitution = 0.00f;
BodyDef body_def = new BodyDef();
body_def.type = BodyType.DYNAMIC;
body_def.angle = 0.0f;
body_def.allowSleep = true;
int scol = color(0);
int fcol = color(224,128,64);
colorMode(HSB, 360,100,100);
randomSeed(1);
float ox = 0;
float oy = dimy/2;
for(int y = 0; y < numy; y++){
float off = 0.5f;
for(int x = 0; x < numx; x++){
boolean odd_row = (y & 1) == 1;
ox = -numx * dimx * 0.5f;
ox += odd_row ? dimx * off : 0;
fixture_def.shape = brick_shape;
if(!odd_row && x == 0){
fixture_def.shape = brick_shape2;
ox += dimx * 0.25;
}
else if(odd_row && x == (numx-1)){
fixture_def.shape = brick_shape2;
ox -= dimx * 0.25;
}
body_def.position.x = tx + ox + x * (dimx);
body_def.position.y = ty + oy + y * (dimy);
Body brick = world.createBody(body_def);
brick.createFixture(fixture_def);
bricks.add(brick);
float hsb_h = 20 + random(-3, 3);
float hsb_s = random(70,60);
float hsb_b = random(70,100);
fcol = color(hsb_h, hsb_s, hsb_b);
world.bodies.add(brick, true, fcol, true, scol, 0.5f);
}
}
colorMode(RGB, 255);
}
There is example for 2D collision with vectors
Please edit your post above and format your code so that people can run it and help you!
This is a collision detection question -- please see a basic introduction to collision detection:
Finally, you are talking about sphere / sphere collision detection. That is circle-circle collision detection with an added z axis.
Is the distance between x,y,z and a,b,c less than the sum of their radii? If so, they are colliding, and they should alter direction.
Notice that PVector has some built-in methods that can help -- e.g. for calculating the distance between two 3D points.
i whant to put an image in to the shape but its coming out white can anyone help
`class astroid {`
// An astroid angle, speed, size, rotation
float angle, speed, size, rotSpeed;
float position;
float rotation;
float xoff, yoff;
float x, y;
PShape s; // The PShape object - Keeps the astroid shape
float i;
int id;
// Constructor
astroid(float _angle, float _speed, float _size, float _rotSpeed, float _xoff, float _yoff, int _id) {
angle = _angle;
speed = _speed;
size = _size;
rotSpeed = _rotSpeed;
xoff = _xoff;
yoff = _yoff;
id = _id;
if (xoff<1000) {
x = 250+500*cos(angle)+xoff;
y = 250+500*sin(angle)+yoff;
} else {
x = _xoff-2000;
y = _yoff-2000;
}
rotation = 0;
// Generate the shape of the astroid - Some variations for all
s = createShape();
s.beginShape();
//s.fill(2 55, 255, 170);
//s.setTexture(
s.setTexture(ast);
s.noStroke();
for (i=0; i<TWO_PI; i=i+PI/(random(4, 11))) {
s.vertex(random(ast_size*0.8, ast_size*1.2)*cos(i), random(ast_size*0.8, ast_size*1.2)*sin(i));
}
s.endShape(CLOSE);
}
// Increases the speed. Used in the end of the game to clear screen of astroids
void incSpeed() {
speed = speed * 1.02;
}
// Update position, return true when out of screen
boolean update() {
int i;
x = x - cos(angle)*speed;
y = y - sin(angle)*speed;
rotation = rotation + rotSpeed;
// Check for astroid vs astroid collision
for (i = 0; i<astroids.size(); i++) {
astroid a = astroids.get(i);
if ((a != this) && (a.coll(x, y, ast_size*size, id))) {
if (size > 1) {
astroids.add(new astroid(angle-random(PI/5, PI/7), speed+random(0, speed/2), size/2, rotSpeed, 2000+x, 2000+y, id));
astroids.add(new astroid(angle+random(PI/5, PI/7), speed+random(0, speed/2), size/2, rotSpeed, 2000+x, 2000+y, id));
ast_id++;
}
astroids.remove(i);
}
}
pushMatrix();
// Set position as the new 0,0
translate(x, y);
// Rotate screen "angle"
rotate(rotation);
// Draw astroid
scale(size);
shape(s);
texture(ast);
// Bring back normal perspektive
popMatrix();
if (x<-300 || x>800 || y<-300 || y>800) {
return true;
} else {
return false;
}
}
//
boolean coll(float _x, float _y, float _size, int _id) {
float dist;
dist = sqrt ((x-_x)*(x-_x) + (y-_y)*(y-_y));
// Check if distance is shorter than astroid size and other objects size
if ((dist<(_size+ast_size*size)) && (id!=_id)) {
// Collision,
if (_id>0) id = _id;
if (size > 1) {
// If the astroid was "large" generate two new fragments
astroids.add(new astroid(angle-random(PI/5, PI/7), speed+random(0, speed/2), size/2, rotSpeed, 2000+x, 2000+y, id));
astroids.add(new astroid(angle+random(PI/5, PI/7), speed+random(0, speed/2), size/2, rotSpeed, 2000+x, 2000+y, id));
}
return true;
} else {
return false;
}
}
}
@Tushar - first things first: set up some way to properly measure performance. E.g. something that displays a framerate (actually even that is fairly crude) so you can make a more objective decision on whether your 'optimisation' is actually effective ;)
Then here are some things to try:
Cache calculated values where possible
As TfGuy44 said, avoid repeating calculations - store these as soon as possible:
For example anything referencing fractions of width
or height
can be calculated and stored in setup() (just make sure you use a variable that's available in draw) - e.g.
const halfWidth = width /2;
const blockHeight = height * -5/6;
It also used to be the case that you should set variables used in loops outside the loop - e.g.:
const limit = trails.length -1
for (let i = limit; i > -1; i--) {
avoid iterating over the same loop multiple times
for (let trail of trails) {
trail.move();
}
for (let block of blocks) {
block.move();
}
arrow.update();
for (let trail of trails) {
trail.show();
}
for (let block of blocks) {
block.show();
}
arrow.show();
You could combine move/update and show methods and get:
for (let trail of trails) {
trail.moveAndShow();
}
for (let block of blocks) {
block.moveAndShow();
}
arrow.updateAndShow();
Avoid expensive array operations
splice()
is a relatively slow array operation. If you splice an element from an array that you're also pushing new objects to; then you should consider fixing the size of the array to the maximum number of objects you'll require and just hide unused elements from view when they're not needed. You should definitely be able to re-cycle your trails objects and probably the blocks too...
For a technical perspective see this
BTW - I haven't run your code - so maybe this is deliberate - but your collision detection appears to only check one block (block[0]
) for a hit. If the arrow can hit any of the visible blocks then you need to do that check in a loop (which could slow things down even more)
If things start getting really laggy then you might want to use time-based animation: that allows you to essentially drop frames so the animation always runs at the same speed.
Ok, you need to take the code you provide above and merge it into a single tab, the main tab. Then, using the code you provided, review it and make sure it runs as I can still find some pieces missing. Either you reduce your code to an MCVE or you make sure the code you provide runs. Please keep in mind we do not have your images so you can provide some information about your images and reduce the number of images used to a minimum. If you can access the images via urls, please provide them.
Kf
Got it kfrajer , * UPDATED* so I simplified it a bit leaving just the essential parts to emphasize what im trying to do. Id like to detect collision between the ghost and the pillars but neglecting the transparencies that is. As the obstacles are arrays that're linked i dont know how to do this effectively
Took the code a lot further, it runs multiple pipes and the collision pgraphic is minimally sized for speed.
Excellent, Thanks Imccandles your code is exactly what i may be thinking about, However, there's only one issue, I can't use any stored images with it for whatever reason.
edit: I got it to work this time loading the PImages from the data folder in setup...doing that didn't work with the previous code...but it works now smh.
Took the code a lot further, it runs multiple pipes and the collision pgraphic is minimally sized for speed.
For me, I go from 1000fps to ~600fps when checking for collision;
FX2D runs much faster but is more limited, holds at 1000fps for me. To convert replace P2D with FX2D on line 12 and remove the P2D 3rd argument entirely on line 53.
color blue = color(0, 0, 255, 255),
transparent = color(0, 0, 0, 0);
PImage pipe = loadImage("http://" + "flappycreator.com/default/tube2.png");
PImage bird = loadImage("http://" + "flappycreator.com/default/bird_sing.png");
Sprite sbird;
ArrayList<Sprite> spipes;
float fps = 0;
void setup() {
size(800, 800, P2D);
//bird.resize((int)(bird.width*2), ((int)bird.height*2));
spipes = new ArrayList<Sprite>();
for (int i = 0; i < 6; i++) {
Sprite sPipe = new Sprite(pipe, color(255, 0, 0, 200));
sPipe.loc = new PVector(i*120+50, 500+random(250));
spipes.add(sPipe);
}
sbird = new Sprite(bird, color(0, 255, 0, 200));
frameRate(1000);
noCursor();
}
void draw() {
clear();
sbird.loc = new PVector(mouseX,mouseY);
sbird.draw();
for (Sprite s : spipes) {
s.draw();
PixelCollision check = sbird.pixelCollision(s);
if (check!=null) {
image(check.pg, check.loc.x, check.loc.y);
stroke(0,255,0,255);
noFill();
rect( check.loc.x, check.loc.y, check.pg.width, check.pg.height);
noStroke();
stroke(255);
fill(255,0,255,255);
ellipse(check.hit.x, check.hit.y, 5, 5);
}
}
fill(255);
fps = (fps*119 + frameRate)/120.0;
text((int)fps + " fps", 10, 10);
}
class PixelCollision {
PGraphics pg;
PVector loc;
PVector hit;
PixelCollision(int w, int h, PVector nloc) {
pg = createGraphics(w, h, P2D);
loc = nloc.copy();
}
}
class Sprite {
PImage img;
PVector loc = new PVector(0, 0);
color tint;
Sprite(PImage pimg, color colTint) {
img = pimg;
tint = colTint;
}
void draw() {
draw(g);
}
boolean overlap(Sprite s) {
if ((loc.x < s.loc.x+s.img.width) && (loc.x+img.width > s.loc.x) &&
(loc.y < s.loc.y+s.img.height) && (loc.y+img.height > s.loc.y)) {
return true;
}
return false;
}
void draw(PGraphics pg) {
pg.pushMatrix();
pg.translate(loc.x, loc.y);
pg.image(img, 0, 0);
//pg.rect(0, 0, bird.width, bird.height);
pg.popMatrix();
}
PixelCollision pixelCollision(Sprite s) {
PixelCollision pc = null;
if (overlap(s)) {
float x = max(loc.x, s.loc.x);
float y = max(loc.y, s.loc.y);
float w = min(loc.x+img.width, s.loc.x+s.img.width);
float h = min(loc.y+img.height, s.loc.y+s.img.height);
pc = new PixelCollision( ceil(w-x), ceil(h-y), new PVector(x, y));
PGraphics pg = pc.pg;
pg.beginDraw();
pg.clear();
pg.tint(tint);
pg.image(img, -(x-loc.x), -(y-loc.y));
pg.tint(s.tint);
pg.image(s.img, -(x-s.loc.x), -(y-s.loc.y));
pg.endDraw();
pg.loadPixels();
int i = 0;
for (; i < pg.width*pg.height-1; i++) {
color c = pg.pixels[i];
if ((red(c)>0)&&(green(c)>0)) {
//pg.pixels[i] = blue;
break;
}
}
if (i== pg.width*pg.height-1) pc.hit = null;
else pc.hit = new PVector(x+ (i%pg.width), y + floor((i-(i%pg.width))/pg.width));
/* for (; i < pg.width*pg.height; i++) { // uncomment this and above to show collisions, slows code
color c = pg.pixels[i];
if ((red(c)>0)&&(green(c)>0)) {
pg.pixels[i] = blue;
}
}
pg.updatePixels(); */
}
if ((pc != null) && (pc.hit == null)) return null;
return pc;
}
}
Here's an example of some pixel based collision. Perhaps I should point out this way of doing it on the CPU is very slow and not really good for a commercial game, needs to be done in shaders.
A solution to this might be to check for bounding box collisions, create a collision pgraphics that is only the size of the overlap (far less pixels), and draw your images there offset.
Basically, you draw your image twice. Once to the screen, once tinted and transparent to a collision pgraphics. Then we check all the pixels in the collision pgraphics for pixels that contain both the bird(tinted to be only red) and the pipe(tinted to be only green).
PGraphics pgCollision;
color blue = color(0, 0, 255, 255),
transparent = color(0,0,0,0);
PImage pipe = loadImage("http://" + "flappycreator.com/default/tube2.png");
PImage bird = loadImage("http://" + "flappycreator.com/default/bird_sing.png");
void setup() {
size(800, 800, P2D);
pgCollision = createGraphics(width, height, P2D);
}
void draw() {
clear();
// draw tinted semi-transparent images
pgCollision.beginDraw();
pgCollision.clear();
pgCollision.tint(255, 0, 0, 200); // draw bird as transparent red
drawBird(pgCollision);
pgCollision.tint(0, 255, 0, 200); // pipes as transparent green
drawPipe(pgCollision);
pgCollision.endDraw();
noTint();
// check all pixels for ones that contain both red and green
pgCollision.loadPixels();
for (int i = 0; i < width*height; i++) {
color c = pgCollision.pixels[i];
if ((red(c)>0)&&(green(c)>0))
pgCollision.pixels[i] = blue; // collision detected
else pgCollision.pixels[i] = transparent; // optional, slow
}
pgCollision.updatePixels();
drawPipe(g);
drawBird(g);
image(pgCollision, 0, 0);
}
void drawPipe(PGraphics pg) {
pg.image(pipe, 200, 600);
}
void drawBird(PGraphics pg) {
pg.image(bird, mouseX, mouseY);
}
I'm fairly new to processing but I've been progressing well with learning how to use it. I've been working on a simple flappy bird esque game and what I want to do is to have the bird and "pipes" collisions be recognized on a pixel-level, ive seen Peter Lagers code for pp_collision but i can't seem to get it to work for the obstacles. can someone tell me how to incorporate the classes into pp_collision(PImage imgA, float aix, float aiy, PImage imgB, float bix, float biy)
for souls https://i.imgur.com/PZm7ivN.png and https://i.imgur.com/wvOkeEZ.png . I would love to know how to get collisions on a pixel level for animated sprites (ie. the souls array) as well but its secondary which is why i commented its code out.
//int numFrames = 2; // The number of frames in the animation
//int currentFrame = 0;
//PImage[] souls = new PImage[numFrames];
int gameState; //0 = startscreen, 1 = in-game, 2 = game over, 3 = restart-screen
int o = 240;
Ghost ghost;
Obstacle[] obstacles = new Obstacle[2];
Score score;
// Game states
boolean gameStarted = false;
boolean gameOver = false;
boolean gameRestart = false;
void setup() {
//frameRate(30);
fullScreen(FX2D);
//size(1280, 720, FX2D);
ghost = new Ghost(width/2, height/2);
obstacles[0] = new Obstacle(width, random(100, height-100));
obstacles[1] = new Obstacle(width*1.5+25, random(100, height-100));
score = new Score();
//startTimer = new Timer (0);
//for (int k = 0; k < numFrames; k++) {
// String imageName = "Soul_" + nf(k, 2) + ".png";
// souls[k] = loadImage(imageName);
//}
}
void draw() {
background(175);
if (gameState==0) {
gameRestart = true;
drawMenuScreen();
score.highscores();
//startTimer.countUp();
//fill (255);
//text (startTimer.getTime(), 60, 60);
}
if (gameState==0 && mousePressed) {
if (gameRestart == true)
//timerReset();
score.reset();
gameState = 1;
}
if (gameState==1) {
gameStarted = true;
gameRestart = false;
ghost.draw();
for (Obstacle o : obstacles) {
o.draw();
//Souls();
}
score.draw();
detectCollision();
if (gameState==1 && mousePressed) {
//startTimer.countUp();
//fill (255);
//text (startTimer.getTime(), 60, 60);
}
if (gameState==1 && mousePressed) {
ghost.jump();
}
}
if (gameState==2) {
//startTimer.countUp();
//fill (255);
//text (startTimer.getTime(), 60, 60);
gameStarted = false;
gameRestart = false;
drawGameOver();
ghost.reset();
for (Obstacle obs : obstacles) {
obs.reset();
}
}
//if (gameState==2 && startTimer.getTime()>=3.5) {
if (gameState==2 && mousePressed) {
if (gameStarted == false && gameRestart == false);
//timerReset();
gameState=3;
}
if (gameState==3) {
gameRestart = true;
drawMenuScreen();
score.highscores();
}
if (gameState==3 && mousePressed) {
if (gameRestart == true)
score.reset();
gameState = 1;
}
}
class Score {
private int score = 0;
private int highscore;
private boolean scoreIncreased = false;
// Methods for increasing scores. If score is NOT increased
void highscores(){
if (score>highscore)
highscore=score;
else if (gameState==0 || gameState==3) {
textAlign(CENTER);
fill(255);
textSize(width/60);
text("HIGHSCORE: " + highscore, width/2, height/2 + height/8.25);
}
}
void increase() {
if (!scoreIncreased) {
score += 1;
scoreIncreased = true;
}
}
void reset() {
score = 0;
scoreIncreased = false;
}
void allowScoreIncrease() {
scoreIncreased = false;
}
void draw() {
pushStyle();
if (gameState==2) {
textAlign(CENTER);
fill(0);
textSize(width/60);
text("SCORE: " + score, width/2, height/2 + 65);
}
else if (gameState==1) {
//rectMode(CORNER);
textAlign(CENTER);
fill(255);
textSize(width/60);
text("Score: " + score, width/2, 40);
}
popStyle();
}
}
class Obstacle {
float initX;
float topX;
float topY;
float w = 120; // original was 50
PImage obstacle1, obstacle2;
Obstacle(float initialTopX, float initialTopY) {
initX = initialTopX;
topX = initialTopX;
topY = initialTopY;
obstacle1 = loadImage("https://" + "i.imgur.com/9Dnn4sI.png");
obstacle2 = loadImage("https://" + "i.imgur.com/d83OfMi.png");
}
void draw() {
pushStyle();
imageMode(CORNERS);
image(obstacle1, topX, topY, topX+w, height-1);
image(obstacle2, topX, 0, topX+w, topY - 180);
popStyle();
// Controls speed of object x movements (namely for obstacles)
// topX -= 4.25;
topX -= 9.5;
}
void reset() {
topX = initX;
topY = random(100, height-100);
}
void reposition() {
topX = width;
topY = random(100, height-100);
}
}
class Ghost {
float x;
float y;
float size = 85;
float vy = 0;
float ay = 0.63;
PImage ghost;
Ghost(float initialX, float initialY) {
x = initialX;
y = initialY;
ghost = loadImage("https://" + "i.imgur.com/GPRyMO7.png");
}
void draw() {
pushStyle();
imageMode(CENTER);
image(ghost, x, y, size, size);
popStyle();
y += vy;
vy += ay;
}
void reset() {
y = 200;
vy = 0;
}
void jump() {
vy = -9.5;
}
}
// void Souls(){
// currentFrame = (currentFrame+1) % numFrames; // Use % to cycle through frames
// image(souls[(currentFrame) % numFrames], width/2, height/2);
//}
void drawGameOver() {
pushStyle();
fill(200, 200, 200, 200);
noStroke();
rect(-20, -20, width + 40, height + 40);
score.draw ();
popStyle();
}
void drawMenuScreen() {
fill(0);
noStroke();
rect(-20, -20, width + 40, height + 40);
;
}
void detectCollision() {
// Did the ghost come out of the screen?
if (ghost.y > height || ghost.y < 0) {
gameState=2;
}
for (Obstacle obstacle : obstacles) {
if (ghost.x - ghost.size/2.0 > obstacle.topX + obstacle.w) {
score.increase();
}
if (obstacle.topX + obstacle.w < 0) {
obstacle.reposition();
score.allowScoreIncrease();
}
//if (obstacle.detectCollision(ghost)) {
//gameState=2;
//}
}
}
Can you help with incorporating the collision detection method below to the work on the ghost class and the obstacles array in my code
obstacle2 = loadImage("up2.png");
obstacle1x = (width - obstacle1.width)/2;
obstacle1y = (height/3 - obstacle1.height)/2;
// obstacle2x = (width - obstacle2.width)/4;
// obstacle2y = (height - obstacle2.height)/4;
// f2x = (width - ghost.width)/2;
// f2y = (height - ghost.height)/2;
}
void draw(){
background(0);
image(obstacle1,obstacle1x,obstacle1y);
obstacle1x = obstacle1x-2;
if (obstacle1x <= -150){
obstacle1x = 900;}
image(ghost,mouseX,mouseY);
if(pp_collision(obstacle1,obstacle1x,obstacle1y,ghost,mouseX,mouseY)){
stroke(255,64,64);
strokeWeight(1);
noFill();
rect(obstacle1x,obstacle1y,obstacle1.width,obstacle1.height);
rect(mouseX,mouseY,ghost.width,ghost.height);
}
}
final int ALPHALEVEL = 20;
boolean pp_collision(PImage imgA, float aix, float aiy, PImage imgB, float bix, float biy) {
int topA, botA, leftA, rightA;
int topB, botB, leftB, rightB;
int topO, botO, leftO, rightO;
int ax, ay;
int bx, by;
int APx, APy, ASx, ASy;
int BPx, BPy; //, BSx, BSy;
topA = (int) aiy;
botA = (int) aiy + imgA.height;
leftA = (int) aix;
rightA = (int) aix + imgA.width;
topB = (int) biy;
botB = (int) biy + imgB.height;
leftB = (int) bix;
rightB = (int) bix + imgB.width;
if (botA <= topB || botB <= topA || rightA <= leftB || rightB <= leftA)
return false;
// If we get here, we know that there is an overlap
// So we work out where the sides of the overlap are
leftO = (leftA < leftB) ? leftB : leftA;
rightO = (rightA > rightB) ? rightB : rightA;
botO = (botA > botB) ? botB : botA;
topO = (topA < topB) ? topB : topA;
// P is the top-left, S is the bottom-right of the overlap
APx = leftO-leftA;
APy = topO-topA;
ASx = rightO-leftA;
ASy = botO-topA-1;
BPx = leftO-leftB;
BPy = topO-topB;
int widthO = rightO - leftO;
boolean foundCollision = false;
// Images to test
imgA.loadPixels();
imgB.loadPixels();
// These are widths in BYTES. They are used inside the loop
// to avoid the need to do the slow multiplications
int surfaceWidthA = imgA.width;
int surfaceWidthB = imgB.width;
boolean pixelAtransparent = true;
boolean pixelBtransparent = true;
// Get start pixel positions
int pA = (APy * surfaceWidthA) + APx;
int pB = (BPy * surfaceWidthB) + BPx;
ax = APx;
ay = APy;
bx = BPx;
by = BPy;
for (ay = APy; ay < ASy; ay++) {
bx = BPx;
for (ax = APx; ax < ASx; ax++) {
pixelAtransparent = alpha(imgA.pixels[pA]) < ALPHALEVEL;
pixelBtransparent = alpha(imgB.pixels[pB]) < ALPHALEVEL;
if (!pixelAtransparent && !pixelBtransparent) {
foundCollision = true;
break;
}
pA ++;
pB ++;
bx++;
}
if (foundCollision) break;
pA = pA + surfaceWidthA - widthO;
pB = pB + surfaceWidthB - widthO;
by++;
}
return foundCollision;
}
I quickly threw together my version of a popular mobile game called "Sine Line".
Links to my code (whichever you prefer): https://pastebin.com/FfxhJs6s https://hastebin.com/jekezecawu.js
The code seems to work fine on both PC and Mobile. But, I think it slowed down considerably after I added the Collision checking (Line 59) in my draw loop, especially on mobile.
Here's a link for quick testing: http://random-codes.000webhostapp.com/sineline.html
I'd like to optimize it further as I do think there's room for it, but I can't seem to find any way. Any help would be appreciated :')
int drawShot=0;
color c;
int xShotfired = 0;
int drawAsteroid;
int asX;
int asY;
int asSpeed;
int shot1X=60;
int shot1Y=300;
int shot1SpeedX=1;
int shot1SpeedY=-1;
boolean collision = false;
void setup() {
size(600, 600);
background(0);
asX=300;
asSpeed =10;
frameRate(44);
}
void draw() {
background(0);
drawTurret(10, color(255, 0, 0), true);
drawTurret(540, color(0, 0, 255), true);
drawShot(shot1X, shot1Y, true);
drawShot(540, 300, true);
shot1X+=shot1SpeedX;
shot1Y+=shot1SpeedY;
drawAsteroid(asX, asY, asSpeed);
}
void drawTurret(int x, color cVal, boolean rightTurret) {
fill(cVal);
rect(x, 10, 50, 580);
}
void drawShot(int xShot, int yShot, boolean rightShot) {
fill(255, 0, 0);
ellipse(xShot, yShot, 20, 20);
// return drawShot = drawShot - 4;
}
void drawAsteroid(int x, int y, int speed) {
fill(255);
ellipse(x, y, 100, 100);
asY= asY + speed;
}
boolean collision(int xAsteroid, int yAsteroid,
int xBolt, int yBolt) {
return false;
}
//
I added the class pan and changed it to the revised one you gave, but it is now giving me errors that there are things that do not exist such as Pan(int), collision(Normal), variables x,y and r
I don't know what happened to the other discussion I was writing a reply to. Some of what I wrote applies here too. Here's what I had:
Well, your code has some problems.
The biggest issue I see is a lack of nice formatting. Press Ctrl + t in the editor to automagically format your code.
If you do that, then it should immediately become apparent that you are missing a stray closing brace. In fact, your Timer class is getting defined inside your Pan class! Add this closing brace in so your Pan class ends before your Timer class.
The next issue I see is that you are loading the images inside the class definitions. Don't do this. To make sure that the images are only ever loaded once, put them inside the function that only ever runs once: setup().
The display() method inside the normalEgg class has a loop in it. I have no idea why. You don't need a loop to draw the same image in the same place ten times. Just draw the image once?
Anyway, actually looking at the collision method, it appears you have a pair of stray opening and closing braces in there that you don't need. Remove those.
Looking at the collision method some more, we see that it looks fine! You are getting the distance from the center of the pan to the center of an egg. If that distance is less than some value, then there is a collision. That sounds good. There's no problem with it.
But there is a problem. Your code has a bug. A bug happens when you have assumed your code does something that it dosen't actually do.
This is a really sneaky bug too, and I suggest you take a minute here to try to find it yourself again before I clue you in to the problem.
Last chance to solve it yourself. Here's a hint: Where is your pan? No really, where is your pan?
The problem is that your code assumes your pan is at (pan.x, pan.y). But it isn't. It's drawn at (mouseX, 450), so where it appears to be has nothing to do with the x and y variables in the pan class! That is, even though the pan moves like you would like, if you use pan.x and pan.y as it's position, well, that position is always (0,0)!
The best way to fix this is to modify the Pan class:
class Pan {
float x, y, r;
Pan() {
r = 30;
x = mouseX;
y = 450;
}
void display() {
x = mouseX;
image(pan, x, y);
}
}
Now pan.x and pan.y are updated when they need to be, and the collision function should work properly. Try it! Does it?
eggs disappear midway as they are going down, please send help! idk if its the timer or array problem, but if anyone can detect why it disappears at random times, then please send the correct code
PImage pan;
PImage egg;
PImage goldegg;
PImage rottenegg;
Pan catcher;
Timer timer;
Normal[] normal;
Golden[] golden;
Rotten[] rotten;
int totalNormal = 0;
int totalGolden = 0;
int totalRotten = 0;
void setup() {
size(500, 500);
imageMode(CENTER);
catcher = new Pan(20);
normal = new Normal[10];
golden = new Golden[5];
rotten = new Rotten[5];
timer = new Timer(3000);
timer.start();
}
void draw() {
background(250, 237, 235);
catcher.setLocation(mouseX, 450);
catcher.display();
if (timer.isFinished()) {
normal[totalNormal] = new Normal();
totalNormal++ ;
golden[totalGolden] = new Golden();
totalGolden++;
rotten[totalRotten] = new Rotten();
totalRotten++;
if (totalNormal >= normal.length) {
totalNormal = 0;
}
if (totalGolden >= golden.length) {
totalGolden = 0;
}
if (totalRotten >= rotten.length) {
totalRotten = 0;
}
timer.start();
}
for (int i = 0; i < totalNormal; i++ ) {
normal[i].move();
normal[i].display();
if (catcher.collision(normal[i])) {
normal[i].caught();
}
}
for (int i = 0; i < totalGolden; i++) {
golden [i].move();
golden[i].display();
if(catcher.collision(golden[i])) {
golden[i].caught();
}
}
for (int i = 0; i <totalRotten; i++){
rotten[i].move();
rotten[i].display();
if(catcher.collision(rotten[i])) {
rotten[i].caught();
}
}
}
class Golden {
float x, y, r;
float speed;
Golden() {
r = 10;
x = random(width);
y = -20;
speed = 4;
}
void move() {
y += speed;
}
// boolean atBottom() {
// if (y > height + r) {
// return true;
// } else {
// return false;
// }
// }
void display() {
goldegg = loadImage ("GoldenEgg.png");
for (int i = 2; i < r; i++ ) {
image(goldegg, x, y);
}
}
void caught() {
speed = 0;
y = -1000;
}
}
class Normal {
float x, y, r;
float speed;
Normal() {
r = 10;
x = random(width);
y = -20;
speed = random(1, 2);
}
void move() {
y += speed;
}
//boolean atBottom() {
// if (y > height + r) {
// return true;
// } else {
// return false;
// }
//}
void display() {
egg = loadImage ("RegularEgg.png");
for (int i = 2; i < r; i++ ) {
image(egg, x, y);
}
}
void caught() {
speed = 0;
y = -1000;
}
}
float r;
float x, y;
Pan(float tempR) {
r = tempR;
x = 0;
y = 0;
}
void setLocation(float tempX, float tempY) {
x = tempX;
y = tempY;
}
void display() {
pan = loadImage ("Pan.png");
image(pan, x, y);
}
boolean collision(Normal n) {
float d = dist(x, y, n.x, n.y);
if (d < r + n.r) {
return true;
} else {
return false;
}
}
boolean collision(Golden g) {
float d = dist(x, y, g.x, g.y);
if (d < r + g.r) {
return true;
} else {
return false;
}
}
boolean collision(Rotten o) {
float d = dist(x, y, o.x, o.y);
if (d < r + o.r) {
return true;
} else {
return false;
}
}
}
class Rotten {
float x, y, r;
float speed;
Rotten() {
r = 10;
x = random(width);
y = -20;
speed = 3;
}
void move() {
y += speed;
}
//boolean atBottom() {
// if (y > height + r) {
// return true;
// } else {
// return false;
// }
//}
void display() {
rottenegg = loadImage ("RottenEgg.png");
for (int i = 2; i < r; i++ ) {
image(rottenegg, x, y);
}
}
void caught() {
speed = 0;
y = -1000;
}
}
class Timer {
int savedTime;
int totalTime;
Timer(int tempTotalTime) {
totalTime = tempTotalTime;
}
void start() {
savedTime = millis();
}
boolean isFinished() {
int passedTime = millis()- savedTime;
if (passedTime > totalTime) {
return true;
} else {
return false;
}
}
}
I have been playing with the Leap Motion for the last couple of days ever since I discovered the "Leap Motion for Processing" library.
The biggest problem that you have is that sometimes the Leap Motion library does not immediately provide data. To demonstrate this I modified example sketch "LM_1_Basics". It can take up to 99 msecs for the Leap Motion to connect, that's a really long time from the sketches point of view.
In your original code you were assuming the the right-hand's position data was available from the very first iteration of the draw(). Unfortunately, initially it isn't, I modified your code to illustrate this problem:
import de.voidplus.leapmotion.*;
import processing.sound.*;
import punktiert.math.Vec;
import punktiert.physics.*;
LeapMotion leap;
SinOsc sine;
Hand leftHand;
Hand rightHand;
float freq;
float amp;
float pos;
PVector hL;
PVector hR;
int teller = 0;
int amount = 100;
// world object
VPhysics physics;
// attractor
BAttraction attr;
void setup() {
//size(displayWidth, 700);
size(1280, 720); // HD 720P
leap = new LeapMotion(this);
sine = new SinOsc(this);
//Start the Sine Oscillator.
sine.play();
sine.amp(amp);
noStroke();
background(#57385c);
//frameRate(30);
smooth();
//set up physics
physics = new VPhysics();
physics.setfriction(0.4f);
// new AttractionForce: (Vec pos, radius, strength)
attr = new BAttraction(new Vec(width * .5f, height * .5f), 400, .01f);
physics.addBehavior(attr);
//
// val for arbitrary radius
float rad = attr.getRadius()/4;
// vector for position
Vec pos = new Vec (random(rad, width/2 - rad), random(rad, height/2 - rad));
// create particle (Vec pos, mass, radius)
VParticle particle = new VParticle(pos, 9, rad);
// add Collision Behavior
particle.addBehavior(new BCollision());
// add particle to world
physics.addParticle(particle);
for (int i = 1; i < amount; i++) {
// val for arbitrary radius
float rad2 = random(2, 20);
// vector for position
Vec pos2 = new Vec(random(rad2, width - rad2), random(rad2, height - rad2));
// create particle (Vec pos, mass, radius)
VParticle particle2 = new VParticle(pos2, 8, rad2);
// add Collision Behavior
particle2.addBehavior(new BCollision());
// add particle to world
physics.addParticle(particle2);
}
}
void draw() {
background(255);
smooth();
for (Hand hand : leap.getHands()) {
boolean handIsLeft = hand.isLeft();
boolean handIsRight = hand.isRight();
leftHand = leap.getLeftHand();
hL = leftHand.getPosition();
if (hL == null) println("No LH data!");
rightHand = leap.getRightHand();
hR = rightHand.getPosition();
if (hR == null) println("No RH data!");
//----------------------- LEFT HAND ----------------------------------
if (handIsLeft) {
text("leftHand-X=" + hL.x, 10, 15); //shows hL.x in sketch
text("leftHand-Y=" + hL.y, 10, 30); //shows hL.y in sketch
text("leftHand-Z=" + hL.z, 10, 45); //shows hL.z in sketch
text("volume(in %)= " + nf(amp*100, 1, -3), 10, 60);
leftHand.draw();
// Map leftHandY van 0.0 to 1.0 voor amplitude (volume)
amp = map(hL.y, 0, height, 1.0, 0.0);
}
sine.amp(amp);
//----------------------- RIGHT HAND ----------------------------------
if (handIsRight) {
text("rightHand-X= " + hR.x, width-160, 15); // shows hL.x in sketch
text("rightHand-Y= " + hR.y, width-160, 30); // shows hL.y in sketch
text("rightHand-Z= " + hR.z, width-160, 45); // shows hL.z in sketch
text("freq(in Hz)= " + nf(freq, 3, -3), width-160, 60);
rightHand.draw();
// Map rightHandX van 100Hz to 800Hz voor frequency
freq = map(hR.x, 0, width, 100.0, 800.0);
}
if (!handIsLeft && handIsRight) {
amp = 0;
}
sine.freq(freq);
} // end for - hand
physics.update();
noFill();
stroke(200, 0, 0);
// set pos to mousePosition
Vec mousePos;
// Deal with right-hand position not yet ready?
// Note: The Leap Motion can take a fraction of a second to start providing data and
// this code is outside the "for (Hand hand : leap.getHands())" for-loop ;-)
if (hR == null) {
println("hR is null!");
mousePos = new Vec(mouseX, mouseY); // Added by Niels
} else {
println("hand x,y = " + hR.x + "," + hR.y);
mousePos = new Vec(hR.x, hR.y); // Added by Niels
}
attr.setAttractor(mousePos);
//ellipse(attr.getAttractor().x, attr.getAttractor().y, attr.getRadius(), attr.getRadius());
noStroke();
fill(0, 125);
teller = 0;
for (VParticle p : physics.particles) {
//println("teller= " + teller);
if (teller == 0) {
p.set(mouseX, mouseY);
ellipse(p.x, p.y, p.getRadius() * 2, p.getRadius() * 2);
teller++;
}
if (teller == 1); {
ellipse(p.x, p.y, p.getRadius() * 2, p.getRadius() * 2);
}
} // end for - p
}
With no call to frameRate() specified Processing will call draw() as quickly as it can. When I run the modified sketch I see the following in the console window:
# Leap Motion Library v2.3.1.6 - Leap Motion SDK v2.3.1+31549 - https://github.com/nok/leap-motion-processing
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
hR is null!
translate(), or this particular variation of it, is not available with this renderer.
hand x,y = 647.9134,592.4121
hand x,y = 786.3234,530.3577
hand x,y = 767.5345,525.84015
hand x,y = 745.8991,519.5922
So you see you need to handle the situation where you don't immediately get data from the Leap Motion.