I'm really new to Java and am working on a class project - I need to draw some pixels in a panel. I was given the jar code for the panel, and now I need to make different trails - specifically, I need to create a trail of pixels that will go around the perimeter of the panel, and I need to create some circles.
Regarding the boxes - I've gotten part of it to work. My pixels starts in the upper left corner and run to the upper right corner, go down the right side of the panel, and then it goes a little crazy - I'm not sure if it stops at the bottom right corner or goes below the bounds of the panel itself, but it doesn't complete its trip around the perimeter. My code is:
import cs251.lab1.Display;
public class Visualizer {
private static final int PIXEL_SIZE = 50;
public static void main(String[] args) {
Display panel = new Display(10, PIXEL_SIZE);
drawWrappingDots(panel);}
public static void drawWrappingDots(Display panel) {
int x = 1;
int y = 1;
while (x > 0 && y > 0){
if (x < panel.getWidth()){
panel.drawNextPixel(x, y);
x++;
}
if (x == panel.getWidth()){
panel.drawNextPixel(x, y);
y++;
}
if (x > 0 && y == panel.getHeight()){
panel.drawNextPixel(x, y);
x--;
}
if (x == 0 && y == panel.getHeight()){
panel.drawNextPixel(x, y);
y--;
}
What am I doing wrong?
Second, how do I draw a circle? I know it needs to use the math library, but I'm not sure how to go about this. Any help on this is much appreciated. Thank you.
As for the first question, you could use multiple if-statements:
int x = 1; //x starts a little to the right of 0
int y = 0; //y starts at 0
while (x > 0 && y > 0){
if (x < panel.getWidth() && y == 0){
panel.drawNextPixel(x, y);
x++;
}
else if (x == panel.getWidth() && y != panel.getHeight()){
panel.drawNextPixel(x, y);
y++;
}
else if (x > 0 && y == panel.getHeight()){
panel.drawNextPixel(x, y);
x--;
}
else {
panel.drawNextPixel(x, y);
y--;
}
}
This way, you check both the x and y coordinates when deciding which way you want to draw the pixels. It starts with x=1 and y=0, then moves to the right until x hits the border, then moves downward until y hits the border, then moves left until x hits 0, and finally moves upwards until y hits 0 and the while condition becomes false.
As for the circle, you need to use trigonometry. Designate a point in the middle of the panel to draw the circle. Then designate a radius you want for the circle.
int middle = 50;
int radius = 20;
Then, you use trigonometry:
int deg = 0;
while ( deg <= 360 ) {
x = middle + (int)(Math.cos(deg)*radius);
y = middle + (int)(Math.sin(deg)*radius);
panel.drawNextPixel(x, y);
deg++;
}
That should do it.
Change while cycle to:
while (x > 0 && y > 0){
if (x < panel.getWidth()){
panel.drawNextPixel(x, y);
x++;
}
if (x == panel.getWidth() && y != panel.getHeight()){
panel.drawNextPixel(x, y);
y++;
}
if (x > 1 && y == panel.getHeight()){
panel.drawNextPixel(x, y);
x--;
}
if (x == 1 && y > 0){
panel.drawNextPixel(x, y);
y--;
}
Maybe, this is not perfect solution.
Related
I was working on an animation on processing.
But, I have a question about the code below:
So, you can see on the output, the ball is going everywhere on the window. I want to make a barrier for the ball. The ball can pass from the middle but if it hit the line it goes somewhere with the speed of (int)random(1, 3).
How to make that?
Here is a picture of what I would like to achieve:
One way to do this is to check for collision when the ball passes through the middle, specifically when the ball's velocity would make y pass from < height/2 to > height/2.
Something like this:
if (((y < height/2 && y+dirY > height/2) || (y > height/2 && y+dirY < height/2)) && (x < width/2-middle || x > width/2+middle)){
dirY = (int) random (1,3);
dirX = (int) random (1,3);
}
(A more appropriate solution would be to create the collision when the edge of the ball passes the barrier, but I'll leave that up to you)
I'm not going to write code, but I'll tell you how to calculate it, it's not that hard.
Taken a circle, we know the center and the radius.
Taken a line we know the startpoint and endpoint.
The line intersects the circle if the distance from them center to startpoint or endpoint is smaller than radius (e.g. point is inside circle)
A line intersects circle if startpoint X is on the left of center (sX < cX), endpoint X on the right (eX > cX), and the distance between their Y and the center Y is less than radius (cY - sY < r)
Note that this really applies only in your simple case with a horizontal line. Normally is better to really work with vectors calculations to determine distance from center to line for example. That would allow you to work with diagonal lines etc.
For your toy model, the easiest way to handle collisions is considering a collision zone. So,
Establish the collision zone limits x1, x2, y1, y2. When the center of the ball enters this zone, collision rules apply.
Consider elastic collisions: your ball only collides with an horizontal line, so only the vertical component of the velocity can be affected, and it never looses speed.
Consider to test your toy model with a good bunch of initial conditions, so you can discover any artifacts due to the smallness of your model, the values you are using, and so on. (I have modified the initial position of the ball for a random initial position, run the model several times to see how it behaves under different initial conditions).
int dirX = (int)random(1, 3);
int dirY = (int)random(1, 3);
//int x = 20, y = 20;
int middle = 20;
int x = (int)random(20, 180);
int y = (int)random(20, 80);
int x1, x2, y1, y2;
void setup() {
size(200,200);
// collision zone limits
x1 = (width/2 - middle) + 20/2 - 1; // 89
x2 = (width/2 + middle) - 20/2 + 1; // 111
y1 = height/2 - 20/2 + 1; // 91
y2 = height/2 + 20/2 - 1; // 109
}
void draw() {
background(255);
ellipse(x, y, 20, 20);
line(0, height/ 2, width/2 - middle, height/2); // (0, 100, 80, 100)
line(width/2 + middle, height/2, width, height/2); // (120, 100, 200, 100)
x += dirX;
y += dirY;
if (x > width || x < 0)
dirX *= -1;
if (y > height || y < 0)
dirY *= -1;
if ((x < x1 && y > y1 && y < height/2 && dirY > 0) || // upper left and going down
(x < x1 && y > height/2 && y < y2 && dirY < 0) || // lower left and going up
(x > x2 && y > y1 && y < height/2 && dirY > 0) || // upper right and going down
(x > x2 && y > height/2 && y < y2 && dirY < 0)) // lower right and going up
dirY *= -1;
}
For a more complex model, you could consider more sophisticated situations as, for example, the backwards collision due to the ends of the lines, the collision of the contour of the ball with the lines, etc.
Most learned friends
I have a sprite that moves around on screen but at the moment it just moves diagonally from left to right and goes off screen and then comes back on the other side.
What I would like it to do is bounce off the edges of the screen in a random fashion but, not being all that clued up on maths, I'm struggling to figure out the coordinates to do this.
Below is what I have so far: (this is an updated code for the Sprite class:
public class Sprite {
//x,y position of sprite - initial position (0,50)
// int [] DIRECTION_TO_ANIMATION_MAP = {3, 1, 0, 2};
private static final int BMP_ROWS = 3;
private static final int BMP_COLUMNS = 4;
private int x = 0;
private int y = 0;
private int xSpeed = 5;//Horizontal increment of position (speed)
private int ySpeed;// Vertical increment of position (speed)
private int currentFrame = 0;
private GameView gameView;
private Bitmap spritebmp;
//Width and Height of the Sprite image
private int bmp_width;
private int bmp_height;
// Needed for new random coordinates.
//private Random random = new Random();
public Sprite(GameView gameView) {
this.gameView = gameView;
spritebmp = BitmapFactory.decodeResource(gameView.getResources(),
R.drawable.running_ninja_sprite);
this.bmp_width = spritebmp.getWidth() / BMP_COLUMNS;
this.bmp_height = spritebmp.getHeight() / BMP_ROWS;
/*Random rnd = new Random(System.currentTimeMillis());
xSpeed = rnd.nextInt(45)-5;
ySpeed = rnd.nextInt(25)-5;*/
}
//update the position of the sprite
public void update() {
//if (x < 0 || x > gameView.getWidth() ){ xSpeed = xSpeed * -1;}
//if (y < 0 || y > gameView.getHeight() ){ ySpeed = ySpeed * -1;}
if (x > gameView.getWidth() - bmp_width - xSpeed || x + xSpeed < 0) {
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y > gameView.getHeight() - bmp_height - ySpeed || y + ySpeed < 0) {
ySpeed = -ySpeed;
}
y = y + xSpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
//y = random.nextInt(gameView.getWidth());
//wrapAround(); //Adjust motion of sprite.
}
public void draw(Canvas canvas) {
update();
int srcX = currentFrame * bmp_width;
int srcY = 1 * bmp_height; //getAnimationRow()
Rect src = new Rect(srcX, srcY, srcX + bmp_width, srcY + bmp_height);
Rect dst = new Rect(x, y, x + bmp_width, y + bmp_height);
//Draw sprite image
canvas.drawBitmap(spritebmp, x, y, null);
}
/*private int getAnimationRow() {
double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int direction = (int) Math.round(dirDouble) % BMP_ROWS;
return DIRECTION_TO_ANIMATION_MAP[direction];
}*/
public void wrapAround() {
//Code to wrap around
if (x < 0) x = x + gameView.getWidth(); //increment x whilst not off screen
if (x >= gameView.getWidth()) { //if gone of the right sides of screen
x = x - gameView.getWidth(); //Reset x
}
if (y < 0) y = y + gameView.getHeight();//increment y whilst not off screen
if (y >= gameView.getHeight()) {//if gone of the bottom of screen
y -= gameView.getHeight();//Reset y
}
}
// Checks if the sprite was touched
public boolean wasItTouched(float ex, float ey) {
boolean touched = false;
if ((x <= ex) && (ex < x + bmp_width) &&
(y <= ey) && (ey < y + bmp_height)) {
touched = true;
}
return touched;
}
}
It now does bounce off the edge but from top left, diagonally to the right and back up in the same direction and continues to do this back and forth. I'd like it to be random in its direction after hitting the edge. Any suggestions? As you can see from the code I have tried a lot of things but the sprite just keeps on doing this continuous back and forth diagonal motion and I'm at a loss as to what I can do.
Thanks
Just negate your speed every time you hit a wall
if (x < 0 || x > gameView.getWidth() ){ xSpeed = xSpeed * -1;}
if (y < 0 || y > gameView.getHeight() ){ ySpeed = ySpeed * -1;}
/////////////////////////////// Edit
It will fit something like this. You can also remove your wrap function as it is no longer applicable
//update the position of the sprite
public void update() {
x = x + xSpeed;
y = y + xSpeed;
bounce();
}
private void bounce(){
if (x <= 0 || x >= gameView.getWidth() ){ xSpeed = xSpeed * -1;}
if (y <= 0 || y >= gameView.getHeight() ){ ySpeed = ySpeed * -1;}
}
I am having trouble getting if-else statement to draw correct colors for my program. I'm under the impression that the if-statements are not organized correctly with the else statement and the "setColor," I am stumped on how to make the black render as yellow. The best way to describe it is to show it.
I'd appreciate any help!
My output (wrong):
Goal output (right):
My code:
import java.awt.*;
public class IfGridEx3 {
public static void main(String[] args) {
DrawingPanel panel = new DrawingPanel(400, 400);
panel.setBackground(Color.blue);
Graphics g = panel.getGraphics();
int sizeX = 40;
int sizeY = 40;
for (int x = 0; x < 10; x++) {
for (int y = 0; y < 10; y++) {
int cornerX = x*sizeX;
int cornerY = y*sizeY;
if (x > 1)
if (x < 8)
if (y > 1)
if (y < 8)
g.setColor(Color.green);
else
g.setColor(Color.yellow);
g.fillRect(cornerX+1, cornerY+1, sizeX-2, sizeY-2);
g.setColor(Color.black);
g.drawString("x="+x, cornerX+10, cornerY+15); // text is positioned at its baseline
g.drawString("y="+y, cornerX+10, cornerY+33); // offsets from the corner do centering
}
}
}
}
Your else is based only on result of last if, so g.setColor(Color.yellow); will be invoked only if all conditions
if (x > 1)
if (x < 8)
if (y > 1)
will be true (otherwise condition in last if will not even be tested),
and result evaluation of condition from last if
if (y < 8)
will be false. It means, that else will not be invoked if previous 3 conditions are false, which is why you are seeing some areas unset.
To solve this problem you can create single condition for center area
if (x > 1 && x < 8 && y > 1 && y < 8){
g.setColor(Color.green);
} else {
g.setColor(Color.yellow);
}
Try this :
if((x>=2 && x<=7) && (y>=2 &&y<=7))
//fill color green
else
//fill yello color
I am making a tank game like the Atari tank game and I ran into some troubles. I'm trying to make the enemy's tank move towards the player's tank but it can't move diagonally since the player isn't allowed to do that also. However, the way I implemented it, it goes diagonally when the distance from the x and y axis are equal to each other. Is there a way I can make it so that it would be forced go in one direction for a while after changing direction? The way do it is that it will compare its x and y values with the player's tank ( the tank that is being passed in ) and the four cases are for if the x-component is bigger than y and is it on theright or left, and if the y-component is bigger than xand is it above or below the player's tank. Thank you for the help!
public void enemyMove(Tank t) {
if ( Math.abs(getX() - t.getX()) >= Math.abs(getY() - t.getY()) && getX() > t.getX() )
goLeft();
else if ( Math.abs(getX() - t.getX()) > Math.abs(getY() - t.getY()) && getX() < t.getX() )
goRight();
else if ( Math.abs(getX() - t.getX()) <= Math.abs(getY() - t.getY()) && getY() > t.getY() )
goUp();
else if ( Math.abs(getX() - t.getX()) < Math.abs(getY() - t.getY()) && getY() < t.getY() )
goDown();
setX(getX() + dx);
setY(getY() + dy);
}
public void goUp() {
dx = 0;
dy = -1;
}
public void goDown() {
dx = 0;
dy = 1;
}
public void goLeft() {
dx = -1;
dy = 0;
}
public void goRight() {
dx = 1;
dy = 0;
}
You can use the Manhattan distance and find the median then move the tank in both directions.
The code below is a little gross, but should do what you want. In your current code the enemy is moving one pixel in the X direction in the first frame, then one pixel in the Y direction in the next frame, which makes the movement look diagonal. The code below sets a short-term target point for the enemy tank to head towards in either the X or Y direction, at some distance away defined by MOVE_BLOCK. The enemy will move until it passes that target point, then recalculate which direction it should be moving. Note that enemyMove will be called every time a new frame is created, so probably 60 times a second.
// The tank will move this distance in x or y before changing directions
private final int MOVE_BLOCK = 120;
// The short-term target of the enemy tank
Point target = null;
public void enemyMove(Tank t) {
/* true if enemy is moving left and enemy is already left of target point,
* or moving right and right of target... */
boolean passedTarget = target == null ||
(dx < 0 && getX() < target.getX()) ||
(dx > 0 && getX() > target.getX()) ||
(dy < 0 && getY() < target.getY()) ||
(dy > 0 && getY() > target.getY());
// Calculate a new target point if the old target was passed
if(passedTarget) {
int xDist = Math.abs(getX() - t.getX());
int yDist = Math.abs(getY() - t.getY());
if ( xDist > yDist ) {
// Cover the remaining distance when close to the target
int moveLength = xDist < MOVE_BLOCK ? xDist : MOVE_BLOCK;
if( getX() >= t.getX() )
goLeft();
target = new Point(getX() - moveLength, getY());
else
goRight();
target = new Point(getX() + moveLength, getY());
} else {
int moveLength = yDist < MOVE_BLOCK ? yDist : MOVE_BLOCK;
if ( getY() >= t.getY() ) {
goUp();
target = new Point(getX(), getY() - moveLength);
} else {
goDown();
target = new Point(getX(), getY() + moveLength);
}
}
}
setX(getX() + dx);
setY(getY() + dy);
}
I need to make the game impossible to win, so I used this code to move AI paddle.
My code may be slightly unreadable at first, so here's the theory behind it: the paddle always hits the ball with the middle point, unless the ball is closer to the edge than half of the paddle length, then the paddle stops to move with one of its ends touching top or bottom window frame.
if (ball.getY() < getHeight() - HEIGHT / 2
&& ball.getY() > HEIGHT / 2) {
paddleRight.setLocation(getWidth() - 3 * WIDTH, ball.getY()
- HEIGHT / 2);
image2.setLocation(getWidth() - 3 * WIDTH, ball.getY() - HEIGHT
/ 2);
image2.sendToFront();
} else if (ball.getY() < HEIGHT / 2) {
paddleRight.setLocation(getWidth() - 3 * WIDTH, 0);
image2.setLocation(getWidth() - 3 * WIDTH, 0);
image2.sendToFront();
} else {
paddleRight.setLocation(getWidth() - 3 * WIDTH, getHeight()
- HEIGHT);
image2.setLocation(getWidth() - 3 * WIDTH, getHeight() - HEIGHT);
image2.sendToFront();
}
My ball also speeds up randomly during the game:
boolean bool = rand.nextBoolean();
if (bool)
if (dx > 0)
dx += 1;
else
dx -= 1;
else if (dy > 0)
dy += 0.5;
else
dy -= 0.5;
ball movement consist of X and Y axis movement
And at some specific speed, if the paddle gets to one of the corners it starts to blink back and forth between top and bottom corner. I can't find the reason for that in my code.
Full code here
Your if statement does not correctly handle conditions where the ball is exactly at boundaries between conditions. You have:
if (ball.getY() < getHeight()-HEIGHT/2 && ball.getY() > HEIGHT/2) {
...
} else if (ball.getY() < HEIGHT/2) {
...
} else {
...
}
But what happens when ball.getY() == HEIGHT/2? In this case, it will fall through to the third block, but this is not the desired behavior - it will briefly jump to the third condition when ball.getY() == HEIGHT/2, hence flicker when the ball's Y position is at that edge. Instead, make a simple change to your second condition:
if (ball.getY() < getHeight()-HEIGHT/2 && ball.getY() > HEIGHT/2) {
...
} else if (ball.getY() <= HEIGHT/2) { // note <= instead of <
...
} else { // ball.getY() >= getHeight()-HEIGHT/2
...
}
This should take care of the transition cases.
By the way, unrelated, you should use curly braces in nested if statements like the one you have, e.g.:
if (bool) {
if (dx > 0)
dx += 1;
else
dx -= 1;
} else {
if (dy > 0)
dy += 0.5;
else
dy -= 0.5;
}
While your original logic happens to have the same effect in this case, your original code, despite its slightly misleading indentation, actually had this structure:
if (bool)
...
else if (dy > 0)
...
else // !bool && dy <= 0
...
That probably doesn't reflect the actual intent of that if and, even though it happens to work here, adding the curly braces is a good habit to get into because it can prevent potential subtle logic errors in more complex code.