Snake game, increasing length in processing - java

I am trying to recreate the snake game, right now i am stuck on adding a new section to the snake everything it collides with an apple
I tried to tell the program to draw a new rectangle but with the x axis slightly shifted and this "shifting" would slowly increase every time my snake eats an apple. My snake starts off with 2 sections, and when i move the snake towards the green apple, it only moves the second section instead of drawing a new one, I know i didn't tell my draw method to draw a new rectangle every time my snake eats an apple since i have no clue on how to do that
public void draw(PApplet p) {
// clear area
p.fill(255, 0, 0);
// draw snake head
p.rect(x, y, length, width);
// draw snake body ?
if (upIsDown == true ) {
p.rect(x, y - section, length, width);
} else if(downIsDown == true) {
p.rect(x, y + section, length, width);
} else if(RightIsDown == true) {
p.rect(x - section, y, length, width);
} else if(LeftIsDown == true) {
RightIsDown = false;
p.rect(x + section, y, length, width);
}
}
the section variable increases by 10 in my checkCollision method
The snake gets longer, but my program only draws the head and the tail of the snake

I added comments to your code.
You code in draw clears the whole game area, then draws 2 rectangles. If you want to see 3 rectanges, you will need to call p.rect() 3 times in that method. If you want to see 10 rectanges, you will need to call it 10 times (so maybe a loop would be good). Else reconsider the call to p.fill() in the beginning.
For a loop, you would need to store the coordinates for each body segment in a structure like a LinkedList, with the coordinates for each segment, and in the draw method draw all segments.

Related

libGDX - Strange Collision Behaviour

I'm having some difficulty implementing very basic collision within libGDX. The update code for the "player" is as so:
private void updatePosition(float _dt)
{
Vector2 _oldPos = _pos;
_pos.add(_mov.scl(_dt*50));
_bounds.setPosition(_pos.x-8, _pos.y-12);
if(_game.getMap().checkCollision(_bounds))
{
System.out.println("Collision Detected");
_pos = _oldPos;
_bounds.setPosition(_pos.x-8, _pos.y-12);
}
}
So, initially _oldPos is stored as the values of _pos position vector before applying any movement.
Movement is then performed by adding the movement vector _mov (multiplied by the delta-time * 50) to the position vector, the player's bounding rectange _bounds is then updated to this new position.
After this, the player's new bounding Rectangle is checked for intersections against every tile in the game's "map", if an intersection is detected, the player cannot move in that direction, so their position is set to the previous position _oldPos and the bounding rectangle's position is also set to the previous position.
Unfortunately, this doesn't work, the player is able to travel straight through tiles, as seen in this image:
So what is happening here? Am I correct in thinking this code should resolve the detected collision?
What is strange, is that replacing
_pos = _oldPos;
with (making the same move just made in reverse)
_pos.sub(_mov.scl(_dt*50));
Yields very different results, where the player still can travel through solid blocks, but encounters resistance.
This is very confusing, as the following statement should be true:
_oldPos == _pos.sub(_mov.scl(_dt*50));
A better solution for collision detection would be to have a Vector2 velocity, and every frame add velocity to position. You can have a method that tests if Up arrow key is pressed, add 1 (or whatever speed you would like) to velocity. And if down is pressed, subtract 1 (or whatever speed). Then you can have 4 collision rectangles on player, 1 on top of player, bottom, left, and right. You can say
if(top collides with bounds){
if(velocity.y > 0){
set velocity.y = 0.
}
}
And do the same for down, left and right (eg... for bottom, make sure to test if(velocity.y < 0) instead of if(velocity.y > 0).
EDIT: You code is not working because you set oldPos = pos without instantiating a new Vector2. Which means when you add onto pos, it also changes oldPos. So say oldPos = new Vector2(pos);
try to test future position before move. If collision, don't move.

Collisions in breakout game

So I'm creating a breakout game and everything's going well, except certain collisions with bricks. I don't know how to go about detecting if the ball hits the brick from the left or the right. I'm trying to create an if statement that reads "if the ball hits the brick from the left or the right, xSpeed is multiplied by -1, else if the ball hits the brick from the top or bottom, y is multiplied by -1." This is easy to do, but detecting where the brick is hit has me stumped. I'm using javafx. I'm sure it's easy, I'd just like to figure out how I should start.
Make a collision box around the brick and the ball and compare the position values, something like this:
Rectangle brickCollision = new Rectangle(x, y, w, h);
Rectangle playerCollision = new Rectangle(x, y, w, h);
//example (collision for one side)
if(playerCollision .x + playerCollision.w > brickCollision.x && playerCollision.x < brickCollision.x + brickCollision.w){
System.out.println("Collision");
}
This is not java fx specific:
You have probably a setup for the grid with grid_x and grid_y coordinates to indicated a brick or empty spot.
When collision occurs, you know the grid position of the ball Bl_xy (which has to be an empty spot) and the grid position of the brick Br_xy which was hit.
Now, if the empty spot Bl_xy is above or below of the brick Br_xy, you need to change the vertical speed component for the ball.
If the empty spot Bl_xy is left or right from Br_xy, change the horizontal speed.
I hope this helps on your super secret school project.

recursive levels and loop counting

I have a homework assignment that I am ready to turn in, in the assignment I had to use recursion to draw nested circles 10 levels deep, after banging my head against this for a few hours I finally completed it. My only question is, is the image I am drawing 10 levels deep or actually 11?
This question comes from the fact that I have specifically state the recursion to end when it has gone through 10 levels, but I do tell the method to draw the original circles then it calls itself. this is making me think that it draws the first level then goes down 10 to make a total of 11 levels. the Image it creates goes down so far that I can not count the circles :/
any clarification would be appreciated, thanks!
// import statements
import java.awt.*;
import javax.swing.*;
public class RecursiveCircles
{
public static void main(String[] args)
{
// create a new canvas
RCanvas myCanvas = new RCanvas();
// create JFrame
JFrame myJframe = new JFrame();
myJframe.setTitle("Recursive Circles");
// set JFrame size, location and close operation
myJframe.setSize(1500, 500);
myJframe.setLocation(100, 100);
myJframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// and canvas to JFrame and make it visble
myJframe.getContentPane().add(myCanvas);
myJframe.setVisible(true);
} // end main
} // end class RecursiveCircles
/*
* this class will draw the main circle of the image and will have the recursive
* method that draws the two outer circles down 10 levels
*/
class RCanvas extends Canvas
{
// defualt constructor
public RCanvas ()
{}
public void paint (Graphics graphics)
{
// declare variables
String title = "Recursive Circles";
int n = 300; // diamerter of the circle
int xOrigin = 600; // x location of start of circle (makes circle around the origin I wanted
int yOrigin = 100; // y location of start of circle (makes circle around the origin i wanted
int radius = n/2; // radius of circle (half the diamerter
int level = 10;
// make canvas background color black
graphics.setColor(Color.black); // make the background color black
graphics.fillRect(0, 0, 1500, 500); // rectangle that fills the JFrame
// put title on canvas
graphics.setColor(Color.BLUE);
graphics.drawString(title, 725, 50);
// draw main circle
graphics.setColor(Color.WHITE);
graphics.drawOval(xOrigin, yOrigin, n, n);
drawRCircles(graphics,xOrigin,yOrigin,radius,level); // call recrusrive method
System.out.println(level);
} // end paint
/*
* This is the recursive method that will draw the two circles on the outer sides of the
* main circle. it will then call itself and repate the process till it is 10 levels deep
*/
public void drawRCircles(Graphics graphics,int xOrigin,int yOrigin, int radius, int level)
{
int newRadius = (radius/2); // radius of smaller circle
int newXOrigin = xOrigin - (newRadius); // xOrigin of circle on left of the main circle
int newYOrigin = yOrigin + (newRadius); // yOrigin of circle on the right of the main circle
int newXOrigin2 = xOrigin + (newRadius*3); // xOrigin of circle on the right of the main circle
int newYOrigin2 = yOrigin + (newRadius); // yOrigin of circle on the right of the main circle
if (level > 0) // counts down from 10 to make the recursive image 10 levels deep
{
graphics.drawOval(newXOrigin, newYOrigin, newRadius*2, newRadius*2); // draw recursive circle on the left of main circle
graphics.drawOval(newXOrigin2, newYOrigin2, newRadius*2, newRadius*2); // draw recursive circle on the right of main circle
drawRCircles(graphics, newXOrigin, newYOrigin , newRadius, (level-1)); // make recursion of left circle
drawRCircles(graphics, newXOrigin2, newYOrigin2,newRadius,(level-1)); // make recursion of right circle
}// end if
} // end drawRCircles
}// end class
Your code is drawing 11 circles but your call(s) to the drawRCircles itself is responsible for only 10 of them.
More specifically, these lines are drawing 1 circle.
// draw main circle
graphics.setColor(Color.WHITE);
graphics.drawOval(xOrigin, yOrigin, n, n);
This circle gets drawn regardless of whether or not you even have a drawRCircles function. (Try removing it and running your code to see what happens.)
Then, your code calls the drawRCircles function 11 times, but only draws 10 circles since the last call to it, with level = 0 fails the test if(level > 0).
the Image it creates goes down so far that I can not count the circles :/
A quick tip: since you want to know if, given max level of N, will it draw N or N+1 levels of circles, you could also just try changing your level variable to something more manageable (like 2) and checking it visually.
Going back to your code above, and ignoring the draw main circle portion (since it's independent of your recursive circle drawing) you have
drawRCircles(graphics,xOrigin,yOrigin,radius,level); // call recursive method
System.out.println(level);
and within your public void drawRCircles(…) function,
drawRCircles(…,level-1);
Let's check it with level = 2 instead of 10:
drawRCircles(…, 2)
--> Check if 1 > 0.
--> Yes, 1 > 0 so drawRCircles(…, 1)
--> Check if 0 > 0.
--> No, 0 = 0, so stop.
Number of levels = 2 = number of recursive circles drawn.

Tile collision with sliding along walls

I've got a ball that I can move around on a map consisting of equally sized tiles. The player should not be able to walk over the tiles that are darker and have a black border. I've got a multidimensional array of the tiles that I use to check which tiles are solid.
I would like the player to slide against the wall if he is moving both horizontally and vertically into it. The problem is that if he does that he sticks to the wall. I managed to get it working perfectly on each axis, but separately. Here is my code for the horizontal collision checking:
if (vx < 0) {
// checks for solid tiles left of the player
if (level.isBlocked(i, j) || level.isBlocked(i, jj)) {
x = side * (i + 1); // moves player to left side of tile
vx = 0;
}
} else if (vx > 0) {
// checks for solid tiles right of the player
if (level.isBlocked(ii, j) || level.isBlocked(ii, jj)) {
x = (ii * side) - getWidth(); // moves player to right side of tile
vx = 0;
}
}
The level.isBlocked() method checks if that index of the array is occupied by a solid tile. The i and j variables is which index in the array the player's top right corner is located on. The ii and jj variables is which index in the array the player's bottom right corner is located on.
This works fine, but then if I add the same chunk of code beneath but replacing x with y, vx with vy and so on the problem occurs. So I can add either the horizontal or vertical collision handling and it works, but not at the same time. I've seen a few articles explaining I have to separate them or something, but I didn't understand much of them. How can I check collision on both axes and keep the sliding effect?
I finally got it to work. Angelatlarge's answer was helpful in understanding the problem, but I decided to start from scratch. I ended up first calculating the new x and y position and storing them in separate variables. Then I checked the tile under the middle left of the player and the same with the middle right. I then set a boolean to true if the player was standing on a tile because of his horizontal speed. If there was no collision I set the real x variable to the new one I calculated earlier. I then repeated the same thing for the vertical collision.
This is for the horizontal checking:
float newX = x + vx * delta;
boolean xCollision = false;
if (vx < 0) {
int i = level.toIndex(x);
int j = level.toIndex(y + getHeight() / 2);
xCollision = level.isBlocked(i, j);
} else if (vx > 0) {
int i = level.toIndex(x + getWidth());
int j = level.toIndex(y + getHeight() / 2);
xCollision = level.isBlocked(i, j);
}
if (!xCollision) x = newX;
The problem is that with the setup you have, given a block and the player position, and also given the fact that they overlap, you don't know whether the player collided with a vertical or a horizontal wall of the block. So see this more clearly consider the following block and two collision paths
The top path will collide with the left wall, and requires a vx=0; (cessation of horizontal movement), while the bottom path collides with the bottom wall and will require vy=0;, or stopping of the vertical movement.
I think in order to do the kind of collision detection you want, you will want to compute intersections of the player path and the walls of the blocks, not just checking whether the player overlaps a block. You could hack the desired behavior by computing the overlapping rectange of the player rectangle and the block rectangle. Consider the following situation:
where the red seqare represents your player. The fact that the overlap rectangle (the small rectangle occupied where the player is on top of the block) is more wide than it is tall suggests that it was the vertical collision that happened, not a horizontal. This is not foolproof, however. And it still requires you to be able to access the shape of the block, rather than just stesting if a part of the player rectangle overlaps a block.

StackOverflowError with a specific algorithm to color a closed shape

My assignment is to implement an algorithm to color a closed shape starting from a given (x,y) coordinate and "spread" via recursive calls untill it reaches the borders of the shape. So far this is what I've come up with:
private void color(int x, int y) {
g2d.draw(new Line2D.Double(x, y, x, y));
if (!robot.getPixelColor(x - 1, y).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x - 1, y);
} else if (!robot.getPixelColor(x + 1, y).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x + 1, y);
} else if (!robot.getPixelColor(x, y - 1).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x, y - 1);
} else if (!robot.getPixelColor(x, y + 1).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x, y + 1);
}
}
The Robot class' getPixelColor is the only way I found to get the color of a given pixel (as far as I know another would be getRGB, but that only works on Image objects). To my understanding this should work, as the outer lines of the shape are definitely black, and the initial x and y values come from a MouseListener, so they are inside the shape, however I get the following error:
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at sun.java2d.pipe.BufferedContext.validateContext(BufferedContext.java:110)
at sun.java2d.d3d.D3DRenderer.validateContextAA(D3DRenderer.java:42)
at sun.java2d.pipe.BufferedRenderPipe$AAParallelogramPipe.fillParallelogram(BufferedRenderPipe.java:445)
at sun.java2d.pipe.PixelToParallelogramConverter.drawGeneralLine(PixelToParallelogramConverter.java:264)
at sun.java2d.pipe.PixelToParallelogramConverter.draw(PixelToParallelogramConverter.java:121)
at sun.java2d.SunGraphics2D.draw(SunGraphics2D.java:2336)
at dline.DrawingSpace.color(DrawingSpace.java:87)
at dline.DrawingSpace.color(DrawingSpace.java:93)
at dline.DrawingSpace.color(DrawingSpace.java:90)
at dline.DrawingSpace.color(DrawingSpace.java:93)
at dline.DrawingSpace.color(DrawingSpace.java:90)
(drawingSpace is a sub-class of JPanel)
The teacher did tell us that this is memory consuming, however it's supposed to be a working algorithm, so I'm doing something wrong, obviously. Any help would be much appriciated, thank you.
You can try to increase the Stack size: How to increase the Java stack size?
Probably you have a bug in your algorithm, or the shape is too big. What helps if you 'draw' your algorithm on a piece of graph paper. That way you can check your algorithm.
I'm guessing that you're backtracking onto previously visited pixels. The pixel you just drew probably won't be visible to robot until after you return from color, so it will not appear red from the previous painting.
Do you have a reference to the java.awt.Shape? A much simpler way than using the robot would be to use Shape.contains(Point) to see whether it's in the shape you're supposed to draw.
The basic algorithm either way is depth-first traveral. To do a DFS when there are possible cycles, you can record the pixels you've already drawn.
//java.awt.Point
Set<Point> paintedPixels = new HashSet<Point>();
private void color(int x, int y) {
if ( paintedPixels.contains(new Point(x, y)) ) {
//already painted
return;
}
paintedPixels.add(new Point(x, y));
//...
}
Now, this could still result in a very deep search. You might consider instead using a non-recursive breadth-first traveral. See the Wikipedia article on Flood Fill.
The problem with implementing this as a recursive algorithm is that it has (for bigger images) a very high recursion depth.
In Java (and most other imperative programming languages, too) the maximal recursion depth is limited by the amount of stack space for each thread, since it must keep a stack frame for each method invocation there.
You may try smaller images first, and try to increase the stack size with the -xss parameter.
Edit: As pointed out by Mark, the Robot will not get any pixels until your drawing is complete, since often your drawing is double-buffered (i.e. the Swing engine lets you paint first on an image, and draws then the complete image to the screen).
Also, you are not converting between device (screen) and user (component) coordinates for the lookup.
You wrote:
The Robot class' getPixelColor is the only way I found to get the color of a given pixel (as far as I know another would be getRGB, but that only works on Image objects).
So, why don't you use an Image object? Fill your shape while drawing on the Image, and then draw the whole image at once to the screen.
And your method can be made much more readable if you transfer the "is already painted" test inside the recursive call:
private void color(int x, int y) {
// getPixel invokes something in the image - or replace it here.
Color org = getPixel(x,y);
if (org.equals(Color.BLACK)) {
// reached the border
return;
}
if (org.equals(Color.RED)) {
// already painted before
return;
}
g2d.draw(new Line2D.Double(x, y, x, y));
color(x-1, y);
color(x+1, y);
color(x, y-1);
color(x, y-1);
}

Categories

Resources