In CS class we made a simple game using a program called greenfoot. This game was much like the game "Frogger" if you are familiar. I am now practicing on my own, and want to make a game similar. My new game is going to be somewhat close to PacMan. The game I made before I control a rocket ship that needs to reach the top of the screen. Meanwhile, I have made randomly selected sizes and speeds for rectangles bouncing of the walls. But, I want to make it more interesting for my new game. I want a loop for these objects that create a random direction when it is first complies, and bounce of the walls and continue on in that direction, much like that famous screen saver that bounces around. Here is my code for the first game, is it anything like this? So ultimately my question is, how do I write a loop for a random direction.
public boolean canMoveRight()
{
if ( getX() + 1 < getWorld().getWidth() )
return true;
else
return false;
}
public boolean canMoveLeft()
{
if ( getX() - 1 > 0 )
return true;
else
return false;
}
public void moveRight()
{
setLocation( getX() + speed, getY() );
}
public void moveLeft()
{
setLocation ( getX() - speed, getY() );
}
public void act()
{
if (right==true)
{
if (canMoveRight() )
{
moveRight();
}
else
{
right = false;
}
}
else
{
if( canMoveLeft() )
moveLeft();
else
right = true;
}
}
Define a Direction enum
e.g.
Up, RightUp,Right... LeftUp.
Use random to pick one.
Direction translates to a change in position of dX,dX, so with a movement step of say 1 pixel UpLeft is -1,-1 (origin top left !)
then in your loop simply add dx to X and dy to Y.
Something along these lines, I guess, would work:
Random random = new Random();
int direction = random.nextInt(1); // gives 0 or 1 randomly
if (direction == 0) {
// move left
} else {
// move right
}
Are you looking for something likes this?
int horz = ((Math.random() * 10) % 10) + 1; //I just choose 10 at random
int vert = ((Math.random() *10) % 10) + 1;
//You can use another random number to choose to negate either horz or vert if you want
//You can also use random numbers to define the start location.
public boolean canMoveHorz()
{
if ( (getX() + horz < getWorld().getWidth() && horz > 0) || (getX() + horz > 0 && horz < 0))
return true;
else
return false;
}
public boolean canMoveVert()
{
if ( (getY() + vert > 0 && vert < 0) || (getY() + vert < getWorld().getHeight() && vert > 0))
return true;
else
return false;
}
public void act() {
if(!canMoveHorz()) {
horz *= -1;
}
if(!canMoveVert()) {
vert *= -1;
}
setLocation(getX() + horz, getY() + vert);
}
This will require some tweaking but what it does is choose 2 random numbers that dictate the speed (vertically and horizontally) for the object. Then it moves the object in those directions until it reaches the edge of the World at which point it negates the speed so the object will move the opposite direction. This is not the same as a true bounce off the walls because I don't do anything with the angle of the hit to determine the angle of the bounce but this should be able to get you started. If you want a more realistic bounce you'll have to do some geometric calculations.
Related
I need to change Ball Direction after collision with another ball or with a edge of the window.
I managed to do something like that:
y += yMove;
x += xMove;
//if the ball moves to the right edge of the window, turn around.
if(x > width - size)
{
x = width - size;
xMove *= -1;
if (xMove > 0) {
xSpeed = xMove + (Math.random() * (1));
}
if (xMove <= 0) {
xSpeed = xMove - (Math.random() * (1));
}
if (yMove > 0) {
ySpeed = yMove + (Math.random() * (1));
}
if (yMove <= 0) {
ySpeed = yMove - (Math.random() * (1));
}
}
And same for another edges.
I'm trying to use same method for changing direction of balls after they collide with each other, but it's just not working / it's weird. Can anyone help me?
When balls collide, make vector connecting ball centers (N) and normalize it (uN)
Components of velocities parallel to N (normal) are exchanged (due to impulse law)
Components of velocities perpendicular to N (tangential) remain the same
To get components in given local system, use scalar and cross product:
V1t = dot(V1, uN)
V2t = dot(V2, uN)
V1n = cross(V1, uN)
V2n = cross(V2, uN)
after collision
V1t' = V2t
V2t' = V1t
V1n' = V1n
V2n' = V2n
To return into global system (I did not checked signs thoroughly):
V1x = V1t` * uN.X + V2n` * uN.Y
V1y = -V1t` * uN.Y + V2n` * uN.X
(This is essentially dot and cross products again, but I expanded expressions to show different bases)
Note that this approach is like to ball-edge collision, when N is normal to the border and you reverse only one component of velocity vector.
For your BouncingBall class, you can have a method like flipDirection(), but you can have a finer directional control by splitting it into 2 methods which filps the direction of the ball vertically and horizontally.
class BouncingBall{
public void horizontalFlip(){
moveX *= -1;
}
public void verticalFlip(){
moveY *= -1;
}
//To have move control over each direction, you can have a method for each direction.
public void moveNorth(){
moveY = Math.abs(moveY) * -1;
}
public void moveSouth(){
moveY = Math.abs(moveY);
}
public void moveWest(){
moveX = Math.abs(moveX) * -1;
}
public void mpveEast(){
moveX = Math.abs(moveX);
}
}
Depending on how you want the ball to bounce off. In a simple bounce off, the balls can bounce towards 4 possible directions:
North West
North East
South West
South East
The direction of the ball to bounce off will be relative to the position of the ball it is colliding with and you do not want 2 collided balls which move in the same direction to switch direction just because they collided. Hence you need to check the positions of the 2 balls, and flipDirection() becomes insufficinet to achieve that.
if(b1.intersects(b2)){
if(b1.getX() < b2.getX()){ // b1 above b2
b1.moveNorth();
b2.moveSouth();
}
else{
b1.moveSouth();
b2.moveNorth();
}
if(b1.getY() < b2.getY()){ // b1 at left side of b2
b1.moveWest();
b2.moveEast();
}
else{
b1.moveEast();
b2.moveWest();
}
}
For example, to change direction when hitting the walls on the left and right:
if(ball.getPosX() <= 0 || ball.getPosX() >= PNL_WIDTH-Ball.SIZE)
ball.horizontalReverse();
Same logic for verticalReverse.
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 am simply trying to make a generic way to check for collision between rectangles. If you hit the top of a rectangle stop moving. However my rectangles seem to stop regardless of the x coordinate. I have three rectangles falling and one static rectangle that doesn't move, they are supposed to all fall on top of this static rectangle however when I run the code this happens.
Here is the collision handler code
float distanceY, furthestLeft;
public void update() {
for (int i = 0; i < stageObjects.size(); i++) {
iPos = stageObjects.get(i).getPosition();
iDim = stageObjects.get(i).getDimensions();
for(int k = 0; k < stageObjects.size(); k++){
kPos = stageObjects.get(k).getPosition();
kDim = stageObjects.get(k).getDimensions();
if(k == i){
continue;
}
distanceY = assignDy();
furthestLeft = assignDx();
//DistanceY is the subtraction of one objects y coordinate and
// if it equals 0 then they are colliding and the furthest left
// is the bottom right x coord of the furthest left objects x
//coord so it should check if this x is contained within an
// objects left x coord to right x coord
if(distanceY <= 1 && distanceY >= 0 && furthestLeft >= iPos.x && furthestLeft <= iPos.x + iDim.x){
stageObjects.get(i).react(Tuples.HIT_BOTTOM);
stageObjects.get(k).react(Tuples.HIT_FROM_TOP);
System.out.println("Collision: " + stageObjects.get(i).toString() + " with " +
stageObjects.get(k).toString());
}
}
}
}
}
public float assignDy(){
if(kPos.y > iPos.y){
return Math.abs(kPos.y - (iPos.y + iDim.y));
}else
return Math.abs(iPos.y - (kPos.y + kDim.y));
}
public float assignDx(){
if(kPos.x > iPos.x){
return kPos.x + kDim.x;
}else
return iPos.x + iDim.x;
}
The error lies here and here is the react method
public void react(int occurence){
if(occurence == Tuples.HIT_BOTTOM){
velocity.y = 0;
}
}
However, if they are further apart the code works perfectly look.
I have also noticed that the rectangle can fall through other rectangles if it is to the left of another rectangle, but if it further to the right at all it will get hung as if it landed on the rectangle. The only reason the above image worked is because the furthest right fell first, anything to the left to another rectangle will get hung as well if it falls after the rectangle to the left
I just don't see what exactly I am doing wrong any help is greatly appreciated!
Change iPos in the condition to something more generic, assign a variable like assignDx and dy to ccheck if Ipos or kPos is what you need to check for like so
public void assignOx(Vector2 ox){
if(kPos.x > iPos.x){
ox.x = iPos.x;
ox.y = iPos.x + iDim.x;
}else{
ox.x = kPos.x;
ox.y = kPos.x + kDim.x;
}
}
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 :)
I'm making a android game for a school project. I'm familiar with java, but not experienced with making games. In my game a ball is controlled by the player. This ball needs to bounce of of walls.
I've tried this in two ways, but both unsuccessful. First try: I'm able to detect overlap, but not able to detect the side the ball hits.
c = the ball, r = the wall
float closestX = c.center.x;
float closestY = c.center.y;
if(c.center.x < r.topLeft.x) {
closestX = r.topLeft.x;
}
else if(c.center.x > r.topLeft.x + r.width) {
closestX = r.topLeft.x + r.width;
}
if(c.center.y < r.topLeft.y) {
closestY = r.topLeft.y;
}
else if(c.center.y > r.topLeft.y + r.height) {
closestY = r.topLeft.y + r.height;
}
return c.center.distSquared(closestX, closestY) < c.radius * c.radius;
So I tried a new approach. But this approach is unstable and treats the ball like a square.
cNew = the ball with the next position, cOld = the ball with the current position, r = wall
if (cNew.center.x + cNew.radius >= r.topLeft.x && cNew.center.x - cNew.radius <= r.topLeft.x + r.width)
{
if (cOld.center.y + cOld.radius < r.topLeft.y && cNew.center.y + cNew.radius >= r.topLeft.y)
{
return Side.TOP;
}
else if (cOld.center.y - cOld.radius > r.topLeft.y + r.height && cNew.center.y - cNew.radius <= r.topLeft.y + r.height)
{
return Side.BOTTOM;
}
}
if (cNew.center.y + cNew.radius >= r.topLeft.y && cNew.center.y - cNew.radius <= r.topLeft.y + r.height)
{
if (cOld.center.x + cOld.radius < r.topLeft.x && cNew.center.x + cNew.radius >= r.topLeft.x)
{
return Side.LEFT;
}
else if (cOld.center.x - cOld.radius > r.topLeft.x + r.width && cNew.center.x - cNew.radius <= r.topLeft.x + r.width)
{
return Side.RIGHT;
}
}
return null;
I need to combine these two is some way, but I haven't been able to find out how.
Help is much appreciated.
Didn't go very carefully with the code (and considering it is your school project, probably I shouldn't be doing your homework), but I believe treating the ball as a square would not have any negative effects if it is just going to bounce off walls. Is there something else you want to do with it?
Your first code is missing out on the fact that the surface of the ball will collide with the wall before its center. You might want to take that into account. And in what sense is your second code unstable?
Some more details would be useful here.
I am going to tell you here how I did :
for the player(and every enemy as well) you need :
x
y
w
h
and :
x velocity
y velocity
and the following point array(lists) :
outline :
upper side
lower side
left side
right side
all together
-all points that are in your ball, every pixel that hasnt alpha=0, for checking collision with walls
Walls :
walls are given as point array(list). For example, analyze the level image, every black pixel is added
Now, do the following :
in your class, have a method for moving
there you need the following logic :
int miny=Integer.MAX_VALUE;
for (Point p:walls) { //For every point in the walls
if (p.x >= (int)x && p.x <= (int)x+w && (int)p.x-(int)x < lower_side.length) {
try {
Point p2=lower_side[(int)p.x-(int)x]; //Get the point that is on the same height as the walls point
if (p.y >= (int)(y+p2.y) && (int)(y+p2.y+yvel) >= p.y && p.y-p2.y-1 < miny) { //Check if you are going to hit the wall, and if it is earlier as the earliest point determined.
miny=p.y-p2.y-1d; //Where is the earliest point where this can happen
}
} catch (Exception bug) {
System.out.println(bug);
}
}
}
apply this to all directions and dimensions.
if (miny != Integer.MAX_VALUE) {
y=miny; //Set position over the wall
yvel=-(yvel*0.75); //Bounce off
}
If you have any questions, feel free to comment.