I have been following a 2d side scroller tutorial in java and have got the basics working, I changed the code a bit to make it so that the tiles and background are always moving, this worked as i intended. The relevant code is below:
Within the character class:
if (speedX < 0) {
centerX += speedX;
}
if (speedX == 0 || speedX < 0) {
bg1.setSpeedX(0);
bg2.setSpeedX(0);
}
if (centerX <= 350 && speedX > 0) {
centerX = centerX + speedX ;
}
if (speedX > 0 && centerX > 350) {
bg1.setSpeedX(-MOVESPEED / 4);
bg2.setSpeedX(-MOVESPEED / 4);
}
Within the tile class:
speedX = bg.getSpeedX() * 3;
tileX = tileX + speedX - 4;
I wanted a way to make it so that if the character moves left, the tiles + background move slower. I am having issues with variable scope and setters/getters. Within the main game class, I have the code:
case
KeyEvent.VK_LEFT:
character.moveLeft();
character.setMovingLeft(true);
break;
How can i include an if statement within the tile class that reads whether the character is moving left (determined from a keyPressed event in the main game class) and adjusts the speed of the tiles accordingly?
I want to write something to the effect of:
if (setMovingLeft = true){
speedX = bg.getSpeedX() * 3;
tileX = tileX + speedX - 1; << changed from - 4
Obviously this doesn't work, can anyone suggest a way to accomplish this? I can provide more information if needed.
Related
I'm having trouble with making my comparisons. The project is supposed to draw a square from user input, and then wherever the user clicks would draw a dot of varying colors there. For instance, if they click inside the square it should make a red circle, if it's on the edge of the square it makes a green circle, and if outside it makes a blue circle. At the moment my program draws red and blue circles, but no greens. In fact it draws red circles when it's above a certain point as well.
public class Square extends GraphicsProgram {
// Instance variables
private int side; // the length of a side
private int anchorX; // the X value at the upper left corner
private int anchorY; // the Y value at the upper left corner
public Square(int x, int y, int side) {
anchorX = x;
anchorY = y;
this.side = side;
}
// mouseClicked method
public void mouseClicked(MouseEvent e) {
// Find the location where the mouse was clicked
int x = e.getX();
int y = e.getY();
// boolean variables to indicate location
boolean isInside = false;
boolean isOutside = false;
boolean isOnEdge = false;
if (x > anchorX + 1 && anchorY + 1 < y && anchorY + side + 1 > y) {
isInside = true;
}
if (x > anchorX + side + 1 && anchorY + side + 1 < y && x > anchorX + side - 1 & y > anchorY + side - 1) {
isOutside = true;
}
/*** NOTE: There a hard, and an easy way to do this! ***/
if (anchorX - 1 <= x && x <= anchorX - 3 && anchorY - 1 <= y && anchorY + side - 3 >= y) {
isOnEdge = true;
}
if (isOnEdge == true) {
System.out.println("(" + x + ", " + y + ") is on the square");
GOval circle = new GOval(x - 2, y - 2, 4, 4);
circle.setFillColor(Color.GREEN);
circle.setFilled(true);
add(circle);
}
else if (isInside == true) {
System.out.println("(" + x + ", " + y + ") is inside the square");
GOval circle = new GOval(x - 2, y - 2, 4, 4);
circle.setFillColor(Color.RED);
circle.setFilled(true);
add(circle);
}
else if (isOutside == true) {
System.out.println("(" + x + ", " + y + ") is outside the square");
GOval circle = new GOval(x - 2, y - 2, 4, 4);
circle.setFillColor(Color.BLUE);
circle.setFilled(true);
add(circle);
}
}
}
We were given a hint on how to do the (x,y) locations of the square as
"For example, the left edge of the square has:
x values in the range: anchorX-1 ≤ x ≤ anchorX+1, and
y values in the range: anchorY-1 ≤ y ≤ anchorY+side+1.
Which would mean that if we had a square with anchorX 50, anchorY 100 and side 60, coordinates like (49-51, 99-161) would be considered on the edge of the left side.
I think the problem is a little confusion with the bounds that make up the square - understandable as it's difficult to visualize.
Is Inside:
if (x > anchorX+1 && anchorY+1 < y && anchorY+side+1 > y) {
isInside = true;
}
Right now this:
Makes sure it's to the right of the left side x > anchorX+1
Makes sure it's to the below the top anchorY+1 < y
Makes sure it's above the bottom anchorY+side+1 > y
The problems with that are:
anchorY+side+1 > y will include the edge - the +1 will go over
There is nothing making sure it's to the left of the right side
A working solution would be:
if (x > anchorX+1 && y > anchorY+1 && x < anchorX+side-1 && y < anchorY+side-1) {
isInside = true;
}
Is Outside:
if (x > anchorX+side+1 && anchorY+side+1 < y && x > anchorX+side-1 & y > anchorY+side-1) {
isOutside = true;
}
Right now this:
Makes sure it's to the right of the right side x > anchorX+side+1
Makes sure it's below the bottom anchorY+side+1 < y
Makes sure it's to the right of the right side x > anchorX+side-1
Makes sure it's above the bottom y > anchorY+side-1
The problems with that are:
x > anchorX+side-1 and y > anchorY+side-1 will include the edge in the area considered outside.
There is nothing making sure it's to the left of the left side or above the top side.
x > anchorX+side+1 and x > anchorX+side-1 do practically the same.
You used the & symbol I'm not sure was intentional or not. The difference is && only runs if the previous are all true, while & always runs. && is therefore faster and usually preferred.
By checking all are true, it only runs when both to the right of and below the square.
A working solution would be:
if (x < anchorX-1 || y < anchorY-1 || x > anchorX+side+1 || y > anchorY+side+1) {
isOutside = true;
}
Is On Edge:
This is the more tricky one
if (anchorX-1 <= x && x <= anchorX-3 && anchorY-1 <= y && anchorY+side-3 >= y) {
isOnEdge = true;
}
Right now this:
Makes sure it's to the right of the left part of the edge anchorX-1 <= x
Makes sure it's to the left of the a point to the left of the left edge x <= anchorX-3
Makes sure it's below the top part of the bottom anchorY-1 <= y
Makes sure it's above a point above the bottom anchorY+side-3 >= y
The problems with that are:
anchorX-1 <= x and x <= anchorX-3 are contridictary, so there is no x such that both are true, so the whole thing must be false.
You used -3 a lot, when you probably meant to use +1 to get the other side of the edge.
You only check the left and bottom edges - the other two are ignored.
As you're using && instead of || (OR), you it will only be true when the whole thing is true - it must be within both edges at the same time - meaning only the corner would be counted.
This could be fixed to create a working solution for this one, but defining all the conditions manually would take a lot of work. This is what it refers to in the easy and hard comment.
As a hint, you can use the fact you already know if it's in the square to simplify it.
I suggest thinking on it.
If you're struggling to comprehend all this, I suggest drawing it out manually and writing down all the values onto it - it's much easier than trying to do it in your head. It gets easier the more you do it.
I'm currently working on a Top-Down-Shooter and having some issues with collision.
My world is made of tiles (64x64). The tiles and the entities are rectangles. The player moves with a speed of e.g 2.74 (and not in pixels for smoother movement). But when it comes to the collision between the player (an entity) and a wall i have some issues. To check if there is a collision i take the current position of my player and his movement speed to calculate where his next position would be and if there is any collision. But i check every pixel on the way, so i cant skip an obstacle even if the movement speed is very high. Let's just say the players current position is X:200 Y:200 and he moves 2.74 Pixels a tick in the x direction. My game now checks if there is any collision at X:201 Y:200, X:202 Y:200 or X:202.74 Y:200 and if not moves the player to that position. If I now try to move the player further in the x direction and there is a wall 0.26 Pixels away the player wont move and leave a tiny gap. I tried to calculate the distance between player and wall and add this amount to the players position but for that I need to know which side of the wall the player hits. Also I want the player to be able to move up and down when the wall he hits is in front of him and the other way around.
Here is my collision method (in Java):
public static boolean collision(float ex, float ey, int width, int height) { // ex, ey would be the next position of the player
if (ex < 0 || ex + width > worldWidth || ey < 0 || ey + height > worldHeight) return true; // checks if this position is in the world
int firstTileX = (int) (ex / Tile.TILE_SIZE); // calculates tiles he could possible collide width
int firstTileY = (int) (ey / Tile.TILE_SIZE);
int lastTileX = (int) ((ex + width - 1) / Tile.TILE_SIZE);
int lastTileY = (int) ((ey + height - 1) / Tile.TILE_SIZE);
for (int y = firstTileY; y <= lastTileY; y++) {
if (y < 0) continue; // checks for out of bounds
if (y >= worldTileHeight) break;
for (int x = firstTileX; x <= lastTileX; x++) {
if (x < 0) continue;
if (x >= worldTileWidth) break;
if (tiles[y][x].solid) return true; // if the tile is solid -> collision found
}
}
return false; // no collision found
}
And my movement method:
public void move(float xa, float ya) {
float nx, ny;
while (xa != 0 || ya != 0) {
nx = x;
ny = y;
if (xa != 0) {
if (Math.abs(xa) > 1) { // if the x-speed is greater than 1
nx = x + MathUtil.abs(xa); // returns -1 for negative numbers and 1 for positiv
xa -= MathUtil.abs(xa);
} else { // less than 1
nx = x + xa;
xa = 0;
}
}
if (ya != 0) { // same here
if (Math.abs(ya) > 1) {
ny = y + MathUtil.abs(ya);
ya -= MathUtil.abs(ya);
} else {
ny = y + ya;
ya = 0;
}
}
if (!Level.collision(nx, ny, width, height)) setPosition(nx, ny); // checks if there is an collision and sets the new position if not
else if (!Level.collision(nx, y, width, height)) x = nx; // if there was a collision check if the player can walk in x direction
else if (!Level.collision(x, ny, width, height)) y = ny; // or in y direction
}
}
My problem is the pretty much the same as CoderMusgrove's problem in his post (Pixel-perfect collision and doubles):
Summary & Question
I have a problem where if the speed of an entity isgreater thanthe distance from the tile it is going into, it will leave at least a pixel in between itself and the tile, and I really don't like this. What kind of algorithm could I use that will find the tiniest difference between the entity and the tile?
If you need any additional information, I will be glad to add it.
Thanks for your help!
Easily resolvable by changing your interpretation.
You are retaining a fractional position for the purpose of fine grained speed. Ignore the fraction for the purpose of collision detection and display (if you were to do sub-pixel rendering, do the collision on the subpixel rendering accurarcy level).
int screenX = (int) Math.round(objX);
int screenY = (int) Math.round(objY);
// rendering and collision detection based on rounded position
I have been stuck on making some collision detection in my game (its kind of like Terraria) for a while but i made this code and... well, it kind of works. It works if the collision is above or on the left of the player, but if the collision is on the right, or below, instead of bouncing back, the player accelerates through the blocks until there is empty space. Here is the code that i made:
private void checkCollision() {
for(int x = (int) (xpos-1); x <= xpos+1; x++){
if(x < 0 || x > main.mw-1) continue;
for(int y = (int) (ypos-2); y <= ypos+1; y++){
if(y < 0 || y > main.mh-1) continue;
if(main.map[x][y] == null) continue;
if(!main.map[x][y].solid) continue;
if(main.map[x][y].blocktype == -1) continue;
double distance = Math.sqrt((xpos-x)*(xpos-x) + (ypos-y)*(ypos-y));
if(distance > 1.0){
continue;
}else{
double x_overlap = Math.max(0, Math.min(xpos + 16, x + 16) - Math.max(xpos, x));
double y_overlap = Math.max(0, Math.min(ypos + 32, y + 16) - Math.max(ypos, y));
double overlapArea = x_overlap * y_overlap;
if(overlapArea > 0){
if(x_overlap > y_overlap){
yblock += y_overlap/2;
}
if(x_overlap < y_overlap){
xblock += x_overlap/2;
}
//guessing i need to do something here to make player
go other way if block is on other side
}
}
}
}
}
So how would i make the player bounce back if the block that he is colliding with is on the right or below. Also is there any way i can make this smoother - right now the player be bouncing all over the place. Thanks! :)
What you want to do is keep track of the player's location, and if the location after moving is out of bounds you can reset the player's position to be right on the edge of the limit.
That's how I dealt with collision detection, I answered another question similar to this one though some folk decided to downvote the answer, go figure.
I am struggling with what must be a basic concept, but can you have a look at my issue?
I have the code where: ai moves the player bat, HEIGHT = total height of Display, and batHeight is the size of the pong paddle/bat:
public void ai(int bally, int HEIGHT, int batHeight) {
if (bally < this.y + ySize / 2) {
if (this.y <= 0) {
System.out.println("Upper Bound");
y = 0;
} else {
y -= 2;
}
}
if (bally > this.y + ySize / 2) {
if (this.y >= HEIGHT - batHeight) {
System.out.println("Lower Bounds");
y = HEIGHT - batHeight;
} else {
y += 2;
}
}
}
The above does exactly what I want it to do. Pong Bat moves up, and when it hits the top of the screen, it prints the console line, and stops the Bat. Exactly the same happens at the bottom of the screen. It prints the console, and stops the bat. It does this every time with no issues.
Now, if I modify the code slightly:
public void ai(int bally, int HEIGHT, int batHeight) {
if (bally < this.y + ySize / 2) {
if (this.y <= 0) {
System.out.println("Upper Bound");
y = 0;
} else {
if(rand.nextInt(2)+1 == 1){
y -= 2;
}else{
y -=3;
}
}
}
if (bally > this.y + ySize / 2) {
if (this.y >= HEIGHT - batHeight) {
System.out.println("Lower Bounds");
y = HEIGHT - batHeight;
} else {
y += 2;
}
}
}
It iterates once, stopping at the top bound, but then it loses itself, and forgets the bounds and the bat moves off the screen. I have Console printing the Bat y position, and it tracks with no issue, accurately displaying its y co-ord, but after the first iteration, it goes to negative y and greater that screen height.
I did have the theory that you cannot nest a IF inside an ELSE statement, so i tried moving it around so that it read:
if(this.y != 0){
if(rand.nextInt(2) + 1 == 1){
//move the paddle at speed 1
} else {
//move paddle at speed 2
}
}else{
//do not move the paddle
}
But that made no difference.
The idea behind the code was to add some chance for the AI bat. Sometimes its fast, and other times it is slower.
Thanks in advance,
Your code from far away looks like this:
for a given time:
if the ball is below the paddle {
if the paddle is below the screen, put it back
else move it down 2 or 3 units
}
if the ball is above the paddle {
if the paddle is above the screen, put it back
else move it up 2 units
}
Imagine the case where the ball is at y = 1 and the paddle is at y = 2. The first if statement will be triggered (1 < 2), the paddle is not outside (2 > 0), so it moves down 2 or 3 units. Let's say 3, for argument's sake. Now, paddle is at y = -1, the ball is still at y = 1. Now, the condition for the second big if is true! So we enter it: the paddle's not above, and we move it up two units. Now, the paddle is at y = 1...
It is clear that it should not have entered the second loop. So, stick an else in front of it, because it should only ever enter one :)
Ok, so I have a game I just started and I am kind of stuck on the smooth scrolling. I have the basic scrolling part done but my background (Grid) only moves by intervals of 50.
for (int x = (getPlayerX() / getTileSize()) - 6; x < (getPlayerX() / getTileSize()) + 9; x++)
{
for (int y = (getPlayerY() / getTileSize()) - 5; y < (getPlayerY() / getTileSize()) + 8; y++)
{
int xPos = ((x - (getPlayerX() / tileSize)) + (getScreenX() / tileSize) - 1) * tileSize;
int yPos = ((y - (getPlayerY() / tileSize)) + (getScreenY() / tileSize) - 1) * tileSize;
if (x > 0 && x < mapX && y > 0 && y < mapY)
{
if (getTiles()[x][y].tileID == 0)
{
g.drawRect(xPos, yPos, tileSize, tileSize);
}
if (getTiles()[x][y].tileID == 1)
{
g.fillRect(xPos, yPos, tileSize + 1, tileSize + 1);
}
}
}
}
Sorry about the subtraction and addition in the for loops, I have them set up so it will display from 1 to whatever instead of 0 to whatever - 1.
So basically I want to redraw the grid every pixel I move, instead of every 50. Put I dont want to iterate over every pixel on the screen
Ok, at first you are confusing with the background and the grid. A grid is a way to check collisions and a spatial partitioning algorithm that never moves. A background is an image which is drawn behind every entity in your game in every level.
What you are trying to do is make the level scroll, as per what I understand. To do so, we create a class called View also called as a Camera which draws the background and the visible entities by centering the entity which is controlled by the player.
And to center an entity and draw the map, I use these classes. Hope you understand that I wrote them in C#.
Map
MapInfo
MapLayer
MapLoader
MapManager
MapView
And here is my implementation of Grid. I have the java versions of the same classes here but I haven't implemented the Grid class in java.
You can read my tutorial Using Grids For Collisions for more info on how it works. Hope it helps.