I am unable to create several instances of the waveClock object even though I have put it in an array and marked the centre positions for each object. I would like to create 4 objects in one window, all responding to different sound frequencies/beat onsets etc
Could someone shed some light on how to go about this? I believe it may be an issue with the centerX and centerY variables in the waveClock class
ArrayList<waveClock> waveClocks = new ArrayList<waveClock>();
//global variables
float angnoise, radiusnoise;
float xnoise, ynoise;
float angle = -PI/6;
float radius;
float strokeCol = 254;
int strokeChange = -1;
int speed; //changes speed of visualisation once beat is detected?
void setup()
//for every waveClock we need 180 pixels width, then add 20 pixels for first gap
size(740, 650);
background(255);
//code is called
waveClocks.add(new waveClock(100, height/2, minRadius, bassColour, lowBassBand, highBassBand, numberOfLowOnsetsThreshold));
waveClocks.add(new waveClock(280, height/2, minRadius, midColour, lowMidBand, highMidBand, numberOfMidOnsetsThreshold));
waveClocks.add(new waveClock(460, height/2, minRadius, highColour, lowHighBand, highHighBand, numberOfHighOnsetsThreshold));
waveClocks.add(new waveClock(640, height/2, minRadius, veryHighColour, lowVeryHighBand, highVeryHighBand, numberOfVeryHighOnsetsThreshold));
//set the min and max radius of each of the viz circles
/* for (int i = 0; i < waveClocks.size(); i++) {
//go through the arraylist of waveClocks and set the min and max radius of each circle
waveClocks.get(i).setMinMaxRadius(minRadius, maxRadius);
}*/
song.play();
beat = new BeatDetect(song.bufferSize(), song.sampleRate());
bl = new BeatListener(beat, song);
}
void draw() {
//clear the screen by painting it black
//background(0);
for (int i = 0; i < waveClocks.size(); i++) {
//has there been a beat in the range? get(circle ID).low band, high band etc.
if (beat.isRange(waveClocks.get(i).getLowBand(), waveClocks.get(i).getHighBand(), waveClocks.get(i).getOnsetThreshold())) {
waveClocks.get(i).setMaxRadius();
}
//waveClocks.get(i).drawCircle();
waveClocks.get(i).drawWaveClock();
}
}
waveClock class in a separate tab
//class is an architecture blueprint
//objects are the actual buildings built from the methods (can make as many as you like)
//constructor is the builder/constructor literally
class waveClock {
float centerX; //co-ordinates of circle's position
float centerY; //co-ordinates of circle's position
float radius; //avg radius
// float minRadius; //smallest size it can be
// float maxRadius; //biggest size it can be
color col; //colour
int onsetThreshold; //
int lowBand; //looks at lowest band of frequency and makes circle sensitive to it
int highBand; //looks at highest band of frequency and makes circle sensitive to it
boolean onset; //has there been an onset (beat has occurred or not?)
//the constructor
waveClock(float x, float y, float r, color c, int lb, int hb, int t) {
centerX = x;
centerY = y;
radius = r;
col = c;
lowBand = lb;
highBand = hb;
onsetThreshold = t;
}
void drawWaveClock() {
radiusnoise += 0.005;
radius = (noise(radiusnoise)*350) + 1;
angnoise += 0.005;
angle += (noise(angnoise)*6) - 3;
if (angle > 360) {
angle -= 360;
} else if (angle < 0) {
angle += 360;
}
xnoise += 0.01;
ynoise =+ 0.01;
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
float rad = radians(angle);
float x1 = centerX + (radius*cos(rad));
float y1 = centerY + (radius*sin(rad));
float opprad = rad + PI;
float x2 = centerX + (radius*cos(opprad));
float y2 = centerY + (radius*sin(opprad));
strokeCol += strokeChange;
if (strokeCol > 354) {
strokeChange = -1;
} else if (strokeCol < 0) {
strokeChange = 1;
}
stroke(strokeCol, 60);
strokeWeight(1);
line(x1, y1, x2, y2);
}
}
You aren't ever using the class-level centerX and centerY variables. Instead, you're recalculating a new centerX and centerY in the drawWaveClock() function.
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
These are all drawn from the center of the screen, so the waves will end up in the same position.
In the future, please try to narrow your problem down to a MCVE that demonstrates the problem. Also please use proper naming conventions- classes start with an upper-case letter, for example. Good luck.
I just started learning game programming through the libgdx framework and I am at the collision detection stage of development. I made a pretty simple game that has some basic bounding-box collision detection system. However, I want to implement pixel-perfect collision for accuracy.
I will be showing snippets of code that I think are important to help you understand what is going on.
A two-dimensional array is created to define the position of the tiles on the screen:
int[][] map = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,1,1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,1,1,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
};
This create() method from my main game class adds a player and three entities to an ArrayList of type Entity.
#Override
public void create () {
batch = new SpriteBatch();
tileTexture = new Texture("block.png");
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
// add some entities including a player
entities.add(new Player(this, 100, 150, 20, 20, 120.0f, new Texture("player.png")));
entities.add(new Entity(this, 50, 150, 20, 20, 120.0f, new Texture("enemy.png")));
entities.add(new Entity(this, 200, 200, 20, 20, 120.0f, new Texture("enemy.png")));
entities.add(new Entity(this, 180, 50, 20, 20, 120.0f, new Texture("enemy.png")));
}
The render() method draws the tile map and the entities when the game is run. Another class named Entity holds the data of a particular entity (can be a block/player). The data can be the x and y position of that entity.
// draw tile map
// go over each row bottom to top
for(int y = 0; y < mapHeight; y++) {
// go over each column left to right
for(int x = 0; x < mapWidth; x++) {
// tile
if(map[x][y] == 1) {
batch.draw(tileTexture, x * tileSize, y * tileSize);
}
}
}
// draw all entities
for(int i = entities.size() - 1; i >= 0; i--) {
Entity e = entities.get(i);
batch.draw(e.texture, e.x, e.y);
}
This produces:
To check for collision when the player (green block) moves, I have two methods that check if the player is colliding with an entity or a tile.
The tileCollision() method:
public boolean tileCollision(Entity e, Direction direction, float newX, float newY) {
boolean collision = false;
// determine affected tiles
int x1 = (int) Math.floor(Math.min(e.x, newX) / tileSize);
int y1 = (int) Math.floor(Math.min(e.y, newY) / tileSize);
int x2 = (int) Math.floor((Math.max(e.x, newX) + e.width - 0.1f) / tileSize);
int y2 = (int) Math.floor((Math.max(e.y, newY) + e.height - 0.1f) / tileSize);
// tile checks
for(int x = x1; x <= x2; x++) {
for(int y = y1; y <= y2; y++) {
if(map[x][y] == 1) {
collision = true;
e.tileCollision(map[x][y], x, y, newX, newY, direction);
}
}
}
return collision;
}
The line of code e.tileCollision(map[x][y], x, y, newX, newY, direction); in this method calls the tileCollision() method in the Entity class that prints the position of where the block collides with a tile.
To check collisions between entities, we have this method:
public boolean entityCollision(Entity e1, Direction direction, float newX, float newY) {
boolean collision = false;
for(int i = 0; i < entities.size(); i++) {
Entity e2 = entities.get(i);
// we don't want to check for collisions between the same entity
if(e1 != e2) {
// axis aligned rectangle rectangle collision detection
if(newX < e2.x + e2.width && e2.x < newX + e1.width &&
newY < e2.y + e2.height && e2.y < newY + e1.height) {
collision = true;
e1.entityCollision(e2, newX, newY, direction);
}
}
}
return collision;
}
NOTE: The green block can move across an entity but cannot go through tiles. This is because the line e1.entityCollision(e2, newX, newY, direction); calls the entityCollision() method in the class Entity that lets the green block move.
This type of collision detection seems basic and inefficient (time complexity of O(n^2)).
How do I implement pixel-perfect collision in this context?
Additional question: If I want to improve the efficiency, what collision detection system can I use to eliminate unnecessary checks?
So I am working on a blackjack game, I have wrote a render process which will render a card going out of the cards stack and sliding to the place where it shows all dealer's cards.
My method works fine, except one problem which I will elaborate:
Whenever Y coordinate reaches the target Y coordinate first, the sprite will only move on X-asis because it cant move Y anymore, instead of making a straight angle to the point.
So what it will do is move up diagonally and then instantly go to the right (in my case)
GIF:
(source: gyazo.com)
MP4 (choose mp4 in the (..) menu http://gyazo.com/bec6daadcb46bedc4777a3e4c5ff8c77)
As you can see, it does what I just said.
What did I do wrong? how can I make it motion in a straight angle to the target without going diagonal up and than turn right away?
My process code:
// If the target is on the right side of the start point
if (startPoint.getX() < endPoint.getX()) {
if (current.getX() < endPoint.getX()) {
current.x += moveSpeed;
if (current.getX() > endPoint.getX()) {
current.x = (int) endPoint.getX();
}
}
else {
xDone = true;
}
}
else {
if (current.getX() > endPoint.getX()) {
current.x -= moveSpeed;
if (current.getX() < endPoint.getX()) {
current.x = (int) endPoint.getX();
}
}
else {
xDone = true;
}
}
// Vise-versa
if (startPoint.getY() < endPoint.getY()) {
if (current.getY() < endPoint.getY()) {
current.y += moveSpeed;
if (current.getY() > endPoint.getY()) {
current.y = (int) endPoint.getY();
}
}
else {
yDone = true;
}
}
else {
if (current.getY() > endPoint.getY()) {
current.y -= moveSpeed;
if (current.getY() < endPoint.getY()) {
current.y = (int) endPoint.getY();
}
}
else {
yDone = true;
}
}
// Callback, dw about it
CardContainer.getCardSprite(CardContainer.SPECIAL, 0).drawSprite((int) current.getX(), (int) current.getY());
// Alert finished, in poisiuton
if (xDone && yDone) {
ch.submitCard(card);
}
current = current position
startPoint = the start point
endPoint = the end point
Thanks!
EDited code:
private void applyMovement(double alpha) {
double dx = endPoint.getX() - startPoint.getX();
double dy = endPoint.getY() - startPoint.getY();
this.current.setLocation(startPoint.getX() + alpha * dx, startPoint.getY() + alpha * dy);
}
public void process() {
double alpha = (double) stepsDone / distance;
applyMovement(alpha);
stepsDone++;
// Callback, dw about it
CardContainer.getCardSprite(CardContainer.SPECIAL, 0).drawSprite((int) current.getX(), (int) current.getY());
// Alert finished, in poisiuton
if (stepsDone >= distance) {
ch.submitCard(card);
}
}
Distance calculation:
this.distance = (int) start.distance(end);
Used Point2D distance method:
public double distance(Point2D pt) {
double px = pt.getX() - this.getX();
double py = pt.getY() - this.getY();
return Math.sqrt(px * px + py * py);
}
I would recommend to not use any form of "slope" in such a computation. You will run into problems when the difference in x-direction approaches zero, because then the slope will tend towards infinity.
Assuming that your points are Point2D.Double (or something similar - you should include this kind of information in your questions!), you can compute the movement as follows:
private Point2D.Double initial = ... // The initial position
private Point2D.Double current = ... // The current position
private Point2D.Double target = ... // The target position
void applyMovment(double alpha) {
double dx = target.getX() - initial.getX();
double dy = target.getY() - initial.getY();
current.x = initial.getX() + alpha * dx;
current.y = initial.getY() + alpha * dy;
}
The applyMovment method sketched here can be called with a double value between 0.0 and 1.0, where 0.0 corresponds to the initial position and 1.0 corresponds to the target position. This is just a Linear Interpolation.
So for example, when you have some sort of loop for the animation, you can use the method as follows:
int numberOfSteps = 10;
for (int i=0; i<=numberOfSteps; i++)
{
double alpha = (double)i / numberOfSteps;
applyMovement(alpha);
repaint();
}
This works for any arrangement of the start- and end points, without any sign- or direction issues. It just interpolates between the two positions.
Your calculation needs to be based upon moving the currentY and currentX along a specific line, not a specific set of intervals (moveSpeed). The formula for graphing points on a line is:
y = mx + b
Where x and y are the varying points, m is equal to the slope of the line, and b is what's called the y-intercept.
Your slope is calculated by the formula:
double slope = ((double) endPoint.getY() - startPoint.getY()) / ((double) endPoint.getX() - startPoint.getX());
And the Y intercept can be calculated by just plugging in a bunch of known values once you have them:
double yIntercept = (double) endPoint.getY() - (slope * endPoint.getX())
Then, just loop through the count of the difference in X:
for (int xVal = startPoint.getX(); xVal < endPoint.getX(); xVal++){
currentX = xVal;
currentY = (slope * xVal) + yIntercept;
}
And you should be good.
Warning: this is all off of the top of my head, I don't know if it'll compile.
I am writing a isometric tile based game where the characters can walk freely amongst the tiles, but not be able to cross over to certain tiles that have a collides flag. Sounds easy enough, just check ahead of where the player is going to move using a Screen Coordinates to Tile method and check the tiles array using our returned xy indexes to see if its collidable or not. if its not, then don't move the character. The problem I'm having is my Screen to Tile method isn't spitting out the proper X,Y tile indexes. This method works flawlessly for selecting tiles with the mouse. NOTE: My X tiles go from left to right, and my Y tiles go from up to down. Reversed from some examples on the net. Here's the relevant code:
public Vector2 ScreentoTile(Vector2 screenPoint) {
//Vector2 is just a object with x and y float properties
//camOffsetX,Y are my camera values that I use to shift everything but the
//current camera target when the target moves
//tilescale = 128, screenheight = 480, the -46 offset is to center
// vertically + 16 px for some extra gfx in my tile png
Vector2 tileIndex = new Vector2(-1,-1);
screenPoint.x -= camOffsetX;
screenPoint.y = screenHeight - screenPoint.y - camOffsetY - 46;
tileIndex.x = (screenPoint.x / tileScale) + (screenPoint.y / (tileScale / 2));
tileIndex.y = (screenPoint.x / tileScale) - (screenPoint.y / (tileScale / 2));
return tileIndex;
}
The method that calls this code is:
private void checkTileTouched () {
if (Gdx.input.justTouched()) {
if (last.x >= 0 && last.x < levelWidth && last.y >= 0 && last.y < levelHeight) {
if (lastSelectedTile != null) lastSelectedTile.setColor(1, 1, 1, 1);
Sprite sprite = levelTiles[(int) last.x][(int) last.y].sprite;
sprite.setColor(0, 0.3f, 0, 1);
lastSelectedTile = sprite;
}
}
if (touchDown) {
float moveX=0,moveY=0;
Vector2 pos = new Vector2();
if (player.direction == direction_left) {
moveX = -(player.moveSpeed);
moveY = -(player.moveSpeed / 2);
Gdx.app.log("Movement", String.valueOf("left"));
} else if (player.direction == direction_upleft) {
moveX = -(player.moveSpeed);
moveY = 0;
Gdx.app.log("Movement", String.valueOf("upleft"));
} else if (player.direction == direction_up) {
moveX = -(player.moveSpeed);
moveY = player.moveSpeed / 2;
Gdx.app.log("Movement", String.valueOf("up"));
} else if (player.direction == direction_upright) {
moveX = 0;
moveY = player.moveSpeed;
Gdx.app.log("Movement", String.valueOf("upright"));
} else if (player.direction == direction_right) {
moveX = player.moveSpeed;
moveY = player.moveSpeed / 2;
Gdx.app.log("Movement", String.valueOf("right"));
} else if (player.direction == direction_downright) {
moveX = player.moveSpeed;
moveY = 0;
Gdx.app.log("Movement", String.valueOf("downright"));
} else if (player.direction == direction_down) {
moveX = player.moveSpeed;
moveY = -(player.moveSpeed / 2);
Gdx.app.log("Movement", String.valueOf("down"));
} else if (player.direction == direction_downleft) {
moveX = 0;
moveY = -(player.moveSpeed);
Gdx.app.log("Movement", String.valueOf("downleft"));
}
//Player.moveSpeed is 1
//tileObjects.x is drawn in the center of the screen (400px,240px)
// the sprite width is 64, height is 128
testX = moveX * 10;
testY = moveY * 10;
testX += tileObjects.get(player.zIndex).x + tileObjects.get(player.zIndex).sprite.getWidth() / 2;
testY += tileObjects.get(player.zIndex).y + tileObjects.get(player.zIndex).sprite.getHeight() / 2;
moveX += tileObjects.get(player.zIndex).x + tileObjects.get(player.zIndex).sprite.getWidth() / 2;
moveY += tileObjects.get(player.zIndex).y + tileObjects.get(player.zIndex).sprite.getHeight() / 2;
pos = ScreentoTile(new Vector2(moveX,moveY));
Vector2 pos2 = ScreentoTile(new Vector2(testX,testY));
if (!levelTiles[(int) pos2.x][(int) pos2.y].collides) {
Vector2 newPlayerPos = ScreentoTile(new Vector2(moveX,moveY));
CenterOnCoord(moveX,moveY);
player.tileX = (int)newPlayerPos.x;
player.tileY = (int)newPlayerPos.y;
}
}
}
When the player is moving to the left (downleft-ish from the viewers point of view),
my Pos2 X values decrease as expected but pos2 isnt checking ahead on the x tiles, it is checking
ahead on the Y tiles(as if we were moving DOWN, not left), and vice versa, if the player moves down, it will check ahead on the X values (as if we are moving LEFT, instead of DOWN).
instead of the Y values.