-
GAME DEVELOPMENT TUTORIAL: DAY 3-5: COLLISION DETECTION II
Continuing with the series, we have Day 5 of Unit 3. This is part 2 of a 3 part series on Collision Detection.
I apologize in advance if there are errors in this lesson. I use an online editor and my internet connection was going on and off, so I had to rewrite some of the sections. I may have forgotten to include some details, although I double-checked. If you experience any issues, please let me know!
jamescho7@kilobolt.com
In the last lesson, we handled the vertical collisions of the robot with the orange and yellow rectangles below:
I apologize in advance if there are errors in this lesson. I use an online editor and my internet connection was going on and off, so I had to rewrite some of the sections. I may have forgotten to include some details, although I double-checked. If you experience any issues, please let me know!
jamescho7@kilobolt.com
In the last lesson, we handled the vertical collisions of the robot with the orange and yellow rectangles below:
Today, we will be checking for collision in the hands, and handling (correcting) both types of collisions.
Before we implement the collision detection, let us first discuss how we will correct a collision.
For our purposes, we will be checking two different things. The first test will determine whether the character is on the ground or in the air. The second will check which rectangle has hit something.
If we are falling, we do not want our character to grab the platform with his hands. Therefore we will be pretending that the arms do not exist while the character is in the air (it will seem slightly more realistic because the arms will be lifted up). This, however, may cause problems for us if the arms collide after the character hits the ground, so we will have to deal with that appropriately.
If we are on the ground (not ducking), we want to check the arms first and then the legs to determine which part of the body is colliding. That way, depending on the height of the platforms, our collisions will adjust accordingly.
If we are on the ground and we are ducking, then we want to check just the orange rectangle for collisions.
Now that we have planned our approach, let's begin.
Keep these things in mind as you write code! Everything will make sense when you understand the strategy.
Before we implement the collision detection, let us first discuss how we will correct a collision.
For our purposes, we will be checking two different things. The first test will determine whether the character is on the ground or in the air. The second will check which rectangle has hit something.
If we are falling, we do not want our character to grab the platform with his hands. Therefore we will be pretending that the arms do not exist while the character is in the air (it will seem slightly more realistic because the arms will be lifted up). This, however, may cause problems for us if the arms collide after the character hits the ground, so we will have to deal with that appropriately.
If we are on the ground (not ducking), we want to check the arms first and then the legs to determine which part of the body is colliding. That way, depending on the height of the platforms, our collisions will adjust accordingly.
If we are on the ground and we are ducking, then we want to check just the orange rectangle for collisions.
Now that we have planned our approach, let's begin.
Keep these things in mind as you write code! Everything will make sense when you understand the strategy.
Side Collision Detection
1. Creating the Rectangles
Much like we did with vertical collision, we will be using intersecting rectangles for side collision.
We begin in the Robot class.
1. Create the two rectangles below (in bold):
public static Rectangle rect = new Rectangle(0, 0, 0, 0);
public static Rectangle rect2 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect3 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect4 = new Rectangle(0, 0, 0, 0);
We will use rect3 to refer to the left hand, and rect4 to refer to the right hand.
2. Giving them these following values in the update method (in bold) will place them in the desired location.
Recall that the setRect method takes in parameters: (x, y, width, height).
rect.setRect(centerX - 34, centerY - 63, 68, 63);
rect2.setRect(rect.getX(), rect.getY() + 63, 68, 63);
rect3.setRect(rect.getX() - 26, rect.getY()+32, 26, 20);
rect4.setRect(rect.getX() + 68, rect.getY()+32, 26, 20);
Doing this will properly update the two rectangles to represent their respective hands.
3. If you choose, you can paint these rectangles in the paint method of the StartingClass; however, you would do this for debugging purposes, and since I have already tested the code that follows, you do not need to paint them.
We begin in the Robot class.
1. Create the two rectangles below (in bold):
public static Rectangle rect = new Rectangle(0, 0, 0, 0);
public static Rectangle rect2 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect3 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect4 = new Rectangle(0, 0, 0, 0);
We will use rect3 to refer to the left hand, and rect4 to refer to the right hand.
2. Giving them these following values in the update method (in bold) will place them in the desired location.
Recall that the setRect method takes in parameters: (x, y, width, height).
rect.setRect(centerX - 34, centerY - 63, 68, 63);
rect2.setRect(rect.getX(), rect.getY() + 63, 68, 63);
rect3.setRect(rect.getX() - 26, rect.getY()+32, 26, 20);
rect4.setRect(rect.getX() + 68, rect.getY()+32, 26, 20);
Doing this will properly update the two rectangles to represent their respective hands.
3. If you choose, you can paint these rectangles in the paint method of the StartingClass; however, you would do this for debugging purposes, and since I have already tested the code that follows, you do not need to paint them.
When to Check Collisions
You may have noticed from Day 4's lesson that I included a strange statement in the Robot class's update method:
"if (true)..."
This always defaults to true.
The reason I included this statement was because I wanted to come back to it and make some changes to it
We only want to check collision for the tiles in the immediate vicinity to the robot. Therefore, we will limit calling the collision checking methods to these 25 tiles (checkerboard):
"if (true)..."
This always defaults to true.
The reason I included this statement was because I wanted to come back to it and make some changes to it
We only want to check collision for the tiles in the immediate vicinity to the robot. Therefore, we will limit calling the collision checking methods to these 25 tiles (checkerboard):
Now all that we have to do is replace if (true) with an if statement that will be true for only these 25 squares.
Here's how I would approach writing this statement.
Notice that the tileX values for the 25 tiles described here will fall in the red region below.
Here's how I would approach writing this statement.
Notice that the tileX values for the 25 tiles described here will fall in the red region below.
Identically, the tileY values for the 25 tiles fall in the yellow region.
Therefore, we can create a rectangle that comprises this red width and yellow height and check if a given tile intersects this rectangle. If it does, than the tile is one of the 25 in the checkerboard region, and we will have to check it for collision.
Creating the Yellow-Red Rectangle
We will now create this rectangle. Despite its name, we will not be coloring it.
1. Create the yellowRed rectangle within the variable declarations section (make changes in bold):
public static Rectangle rect = new Rectangle(0, 0, 0, 0);
public static Rectangle rect2 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect3 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect4 = new Rectangle(0, 0, 0, 0);
public static Rectangle yellowRed = new Rectangle(0, 0, 0, 0);
2. Update it in the update() method with the following statement in bold::
rect2.setRect(rect.getX(), rect.getY() + 63, 68, 63);
rect3.setRect(rect.getX() - 26, rect.getY()+32, 26, 20);
rect4.setRect(rect.getX() + 68, rect.getY()+32, 26, 20);
yellowRed.setRect(centerX - 110, centerY - 110, 180, 180);
This will place the yellowRed rectangle at the appropriate location.
1. Create the yellowRed rectangle within the variable declarations section (make changes in bold):
public static Rectangle rect = new Rectangle(0, 0, 0, 0);
public static Rectangle rect2 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect3 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect4 = new Rectangle(0, 0, 0, 0);
public static Rectangle yellowRed = new Rectangle(0, 0, 0, 0);
2. Update it in the update() method with the following statement in bold::
rect2.setRect(rect.getX(), rect.getY() + 63, 68, 63);
rect3.setRect(rect.getX() - 26, rect.getY()+32, 26, 20);
rect4.setRect(rect.getX() + 68, rect.getY()+32, 26, 20);
yellowRed.setRect(centerX - 110, centerY - 110, 180, 180);
This will place the yellowRed rectangle at the appropriate location.
Checking for Collisions
Open up your Tile class.
Now that we have created the yellowRed rectangle, we can create an appropriate if statement for checking collisions.
1. Let's begin with the constructor Change the following in bold:
public Tile(int x, int y, int typeInt) {
tileX = x * 40;
tileY = y * 40;
type = typeInt;
r = new Rectangle();
if (type == 5) {
tileImage = StartingClass.tiledirt;
} else if (type == 8) {
tileImage = StartingClass.tilegrassTop;
} else if (type == 4) {
tileImage = StartingClass.tilegrassLeft;
} else if (type == 6) {
tileImage = StartingClass.tilegrassRight;
} else if (type == 2) {
tileImage = StartingClass.tilegrassBot;
} else {
type = 0;
}
}
This ensures that all the "empty" tiles, which are simply tiles without images, will have type 0.
2. Next we go down to the update() method. Make the following changes to the if statement:
You will get errors. Please ignore them for now, as we will address them directly after.
public void update() {
speedX = bg.getSpeedX() * 5;
tileX += speedX;
r.setBounds(tileX, tileY, 40, 40);
if (r.intersects(Robot.yellowRed) && type != 0) {
checkVerticalCollision(Robot.rect, Robot.rect2);
checkSideCollision(Robot.rect3, Robot.rect4, Robot.footleft, Robot.footright);
}
}
Recall that the rectangle yellowRed is the "region of 25" tiles that will be checked for collision.
Now that we have created the yellowRed rectangle, we can create an appropriate if statement for checking collisions.
1. Let's begin with the constructor Change the following in bold:
public Tile(int x, int y, int typeInt) {
tileX = x * 40;
tileY = y * 40;
type = typeInt;
r = new Rectangle();
if (type == 5) {
tileImage = StartingClass.tiledirt;
} else if (type == 8) {
tileImage = StartingClass.tilegrassTop;
} else if (type == 4) {
tileImage = StartingClass.tilegrassLeft;
} else if (type == 6) {
tileImage = StartingClass.tilegrassRight;
} else if (type == 2) {
tileImage = StartingClass.tilegrassBot;
} else {
type = 0;
}
}
This ensures that all the "empty" tiles, which are simply tiles without images, will have type 0.
2. Next we go down to the update() method. Make the following changes to the if statement:
You will get errors. Please ignore them for now, as we will address them directly after.
public void update() {
speedX = bg.getSpeedX() * 5;
tileX += speedX;
r.setBounds(tileX, tileY, 40, 40);
if (r.intersects(Robot.yellowRed) && type != 0) {
checkVerticalCollision(Robot.rect, Robot.rect2);
checkSideCollision(Robot.rect3, Robot.rect4, Robot.footleft, Robot.footright);
}
}
Recall that the rectangle yellowRed is the "region of 25" tiles that will be checked for collision.
Correcting the Errors
The last changes probably introduced several errors to your code. We will be correcting those right now.
Let's begin with the footleft, footright errors.
1. Open up your Robot class and add the following statements to the variable declarations:
public static Rectangle footleft = new Rectangle(0,0,0,0);
public static Rectangle footright = new Rectangle(0,0,0,0);
2. Then add the following statements to the update() method.
footleft.setRect(centerX - 50, centerY + 20, 50, 15);
footright.setRect(centerX, centerY + 20, 50, 15);
You can safely place them below all the other rectangles (if you need a reference, just scroll down to peek at the finished Robot class).
These two rectangles are used for checking side collision when the tile is shorter than the arm height. They are simply small rectangles that stick out a bit farther than the foot.
Now moving on to the two methods.
Add/Change the two methods in your Tile class to be as follows:
Let's begin with the footleft, footright errors.
1. Open up your Robot class and add the following statements to the variable declarations:
public static Rectangle footleft = new Rectangle(0,0,0,0);
public static Rectangle footright = new Rectangle(0,0,0,0);
2. Then add the following statements to the update() method.
footleft.setRect(centerX - 50, centerY + 20, 50, 15);
footright.setRect(centerX, centerY + 20, 50, 15);
You can safely place them below all the other rectangles (if you need a reference, just scroll down to peek at the finished Robot class).
These two rectangles are used for checking side collision when the tile is shorter than the arm height. They are simply small rectangles that stick out a bit farther than the foot.
Now moving on to the two methods.
Add/Change the two methods in your Tile class to be as follows:
public void checkVerticalCollision(Rectangle rtop, Rectangle rbot) {
if (rtop.intersects(r)) {
}
if (rbot.intersects(r) && type == 8) {
robot.setJumped(false);
robot.setSpeedY(0);
robot.setCenterY(tileY - 63);
}
}
public void checkSideCollision(Rectangle rleft, Rectangle rright, Rectangle leftfoot, Rectangle rightfoot) {
if (type != 5 && type != 2 && type != 0){
if (rleft.intersects(r)) {
robot.setCenterX(tileX + 102);
robot.setSpeedX(0);
}else if (leftfoot.intersects(r)) {
robot.setCenterX(tileX + 85);
robot.setSpeedX(0);
}
if (rright.intersects(r)) {
robot.setCenterX(tileX - 62);
robot.setSpeedX(0);
}
else if (rightfoot.intersects(r)) {
robot.setCenterX(tileX - 45);
robot.setSpeedX(0);
}
}
}
if (rtop.intersects(r)) {
}
if (rbot.intersects(r) && type == 8) {
robot.setJumped(false);
robot.setSpeedY(0);
robot.setCenterY(tileY - 63);
}
}
public void checkSideCollision(Rectangle rleft, Rectangle rright, Rectangle leftfoot, Rectangle rightfoot) {
if (type != 5 && type != 2 && type != 0){
if (rleft.intersects(r)) {
robot.setCenterX(tileX + 102);
robot.setSpeedX(0);
}else if (leftfoot.intersects(r)) {
robot.setCenterX(tileX + 85);
robot.setSpeedX(0);
}
if (rright.intersects(r)) {
robot.setCenterX(tileX - 62);
robot.setSpeedX(0);
}
else if (rightfoot.intersects(r)) {
robot.setCenterX(tileX - 45);
robot.setSpeedX(0);
}
}
}
You will notice that these completed methods have various checks/tests. You should take the time to go through each of them to make sense of each if statement.
Final Touches
Now that we have completed the collision detection checking code, we must make a few changes.
In the robot class:
1. Locate the //Handles Jumping section of the update method.
Make the following changes.
// Handles Jumping
speedY += 1;
if (speedY > 3){
jumped = true;
}
As we handle falling elsewhere, we can remove the first if statement.
The if statement that I have created prevents small fluctuations in speedY from registering as jumps.
2. You can now safely remove all the statements that paint our helper rectangles to the screen.
The completed Robot, Tile, and StartingClass code is below:
In the robot class:
1. Locate the //Handles Jumping section of the update method.
Make the following changes.
// Handles Jumping
speedY += 1;
if (speedY > 3){
jumped = true;
}
As we handle falling elsewhere, we can remove the first if statement.
The if statement that I have created prevents small fluctuations in speedY from registering as jumps.
2. You can now safely remove all the statements that paint our helper rectangles to the screen.
The completed Robot, Tile, and StartingClass code is below:
The Completed Robot Class
package kiloboltgame;
import java.awt.Rectangle;
import java.util.ArrayList;
public class Robot {
// Constants are Here
final int JUMPSPEED = -15;
final int MOVESPEED = 5;
private int centerX = 100;
private int centerY = 377;
private boolean jumped = false;
private boolean movingLeft = false;
private boolean movingRight = false;
private boolean ducked = false;
private boolean readyToFire = true;
private int speedX = 0;
private int speedY = 0;
public static Rectangle rect = new Rectangle(0, 0, 0, 0);
public static Rectangle rect2 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect3 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect4 = new Rectangle(0, 0, 0, 0);
public static Rectangle yellowRed = new Rectangle(0, 0, 0, 0);
public static Rectangle footleft = new Rectangle(0,0,0,0);
public static Rectangle footright = new Rectangle(0,0,0,0);
private Background bg1 = StartingClass.getBg1();
private Background bg2 = StartingClass.getBg2();
private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
public void update() {
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX;
}
if (speedX == 0 || speedX < 0) {
bg1.setSpeedX(0);
bg2.setSpeedX(0);
}
if (centerX <= 200 && speedX > 0) {
centerX += speedX;
}
if (speedX > 0 && centerX > 200) {
bg1.setSpeedX(-MOVESPEED / 5);
bg2.setSpeedX(-MOVESPEED / 5);
}
// Updates Y Position
centerY += speedY;
// Handles Jumping
speedY += 1;
if (speedY > 3){
jumped = true;
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= 60) {
centerX = 61;
}
rect.setRect(centerX - 34, centerY - 63, 68, 63);
rect2.setRect(rect.getX(), rect.getY() + 63, 68, 63);
rect3.setRect(rect.getX() - 26, rect.getY()+32, 26, 20);
rect4.setRect(rect.getX() + 68, rect.getY()+32, 26, 20);
yellowRed.setRect(centerX - 110, centerY - 110, 180, 180);
footleft.setRect(centerX - 50, centerY + 20, 50, 15);
footright.setRect(centerX, centerY + 20, 50, 15);
}
public void moveRight() {
if (ducked == false) {
speedX = MOVESPEED;
}
}
public void moveLeft() {
if (ducked == false) {
speedX = -MOVESPEED;
}
}
public void stopRight() {
setMovingRight(false);
stop();
}
public void stopLeft() {
setMovingLeft(false);
stop();
}
private void stop() {
if (isMovingRight() == false && isMovingLeft() == false) {
speedX = 0;
}
if (isMovingRight() == false && isMovingLeft() == true) {
moveLeft();
}
if (isMovingRight() == true && isMovingLeft() == false) {
moveRight();
}
}
public void jump() {
if (jumped == false) {
speedY = JUMPSPEED;
jumped = true;
}
}
public void shoot() {
if (readyToFire) {
Projectile p = new Projectile(centerX + 50, centerY - 25);
projectiles.add(p);
}
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public boolean isJumped() {
return jumped;
}
public int getSpeedX() {
return speedX;
}
public int getSpeedY() {
return speedY;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setJumped(boolean jumped) {
this.jumped = jumped;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setSpeedY(int speedY) {
this.speedY = speedY;
}
public boolean isDucked() {
return ducked;
}
public void setDucked(boolean ducked) {
this.ducked = ducked;
}
public boolean isMovingRight() {
return movingRight;
}
public void setMovingRight(boolean movingRight) {
this.movingRight = movingRight;
}
public boolean isMovingLeft() {
return movingLeft;
}
public void setMovingLeft(boolean movingLeft) {
this.movingLeft = movingLeft;
}
public ArrayList getProjectiles() {
return projectiles;
}
public boolean isReadyToFire() {
return readyToFire;
}
public void setReadyToFire(boolean readyToFire) {
this.readyToFire = readyToFire;
}
}
import java.awt.Rectangle;
import java.util.ArrayList;
public class Robot {
// Constants are Here
final int JUMPSPEED = -15;
final int MOVESPEED = 5;
private int centerX = 100;
private int centerY = 377;
private boolean jumped = false;
private boolean movingLeft = false;
private boolean movingRight = false;
private boolean ducked = false;
private boolean readyToFire = true;
private int speedX = 0;
private int speedY = 0;
public static Rectangle rect = new Rectangle(0, 0, 0, 0);
public static Rectangle rect2 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect3 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect4 = new Rectangle(0, 0, 0, 0);
public static Rectangle yellowRed = new Rectangle(0, 0, 0, 0);
public static Rectangle footleft = new Rectangle(0,0,0,0);
public static Rectangle footright = new Rectangle(0,0,0,0);
private Background bg1 = StartingClass.getBg1();
private Background bg2 = StartingClass.getBg2();
private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
public void update() {
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX;
}
if (speedX == 0 || speedX < 0) {
bg1.setSpeedX(0);
bg2.setSpeedX(0);
}
if (centerX <= 200 && speedX > 0) {
centerX += speedX;
}
if (speedX > 0 && centerX > 200) {
bg1.setSpeedX(-MOVESPEED / 5);
bg2.setSpeedX(-MOVESPEED / 5);
}
// Updates Y Position
centerY += speedY;
// Handles Jumping
speedY += 1;
if (speedY > 3){
jumped = true;
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= 60) {
centerX = 61;
}
rect.setRect(centerX - 34, centerY - 63, 68, 63);
rect2.setRect(rect.getX(), rect.getY() + 63, 68, 63);
rect3.setRect(rect.getX() - 26, rect.getY()+32, 26, 20);
rect4.setRect(rect.getX() + 68, rect.getY()+32, 26, 20);
yellowRed.setRect(centerX - 110, centerY - 110, 180, 180);
footleft.setRect(centerX - 50, centerY + 20, 50, 15);
footright.setRect(centerX, centerY + 20, 50, 15);
}
public void moveRight() {
if (ducked == false) {
speedX = MOVESPEED;
}
}
public void moveLeft() {
if (ducked == false) {
speedX = -MOVESPEED;
}
}
public void stopRight() {
setMovingRight(false);
stop();
}
public void stopLeft() {
setMovingLeft(false);
stop();
}
private void stop() {
if (isMovingRight() == false && isMovingLeft() == false) {
speedX = 0;
}
if (isMovingRight() == false && isMovingLeft() == true) {
moveLeft();
}
if (isMovingRight() == true && isMovingLeft() == false) {
moveRight();
}
}
public void jump() {
if (jumped == false) {
speedY = JUMPSPEED;
jumped = true;
}
}
public void shoot() {
if (readyToFire) {
Projectile p = new Projectile(centerX + 50, centerY - 25);
projectiles.add(p);
}
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public boolean isJumped() {
return jumped;
}
public int getSpeedX() {
return speedX;
}
public int getSpeedY() {
return speedY;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setJumped(boolean jumped) {
this.jumped = jumped;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setSpeedY(int speedY) {
this.speedY = speedY;
}
public boolean isDucked() {
return ducked;
}
public void setDucked(boolean ducked) {
this.ducked = ducked;
}
public boolean isMovingRight() {
return movingRight;
}
public void setMovingRight(boolean movingRight) {
this.movingRight = movingRight;
}
public boolean isMovingLeft() {
return movingLeft;
}
public void setMovingLeft(boolean movingLeft) {
this.movingLeft = movingLeft;
}
public ArrayList getProjectiles() {
return projectiles;
}
public boolean isReadyToFire() {
return readyToFire;
}
public void setReadyToFire(boolean readyToFire) {
this.readyToFire = readyToFire;
}
}
The Completed Tile Class
package kiloboltgame;
import java.awt.Image;
import java.awt.Rectangle;
public class Tile {
private int tileX, tileY, speedX, type;
public Image tileImage;
private Robot robot = StartingClass.getRobot();
private Background bg = StartingClass.getBg1();
private Rectangle r;
public Tile(int x, int y, int typeInt) {
tileX = x * 40;
tileY = y * 40;
type = typeInt;
r = new Rectangle();
if (type == 5) {
tileImage = StartingClass.tiledirt;
} else if (type == 8) {
tileImage = StartingClass.tilegrassTop;
} else if (type == 4) {
tileImage = StartingClass.tilegrassLeft;
} else if (type == 6) {
tileImage = StartingClass.tilegrassRight;
} else if (type == 2) {
tileImage = StartingClass.tilegrassBot;
} else {
type = 0;
}
}
public void update() {
speedX = bg.getSpeedX() * 5;
tileX += speedX;
r.setBounds(tileX, tileY, 40, 40);
if (r.intersects(Robot.yellowRed) && type != 0) {
checkVerticalCollision(Robot.rect, Robot.rect2);
checkSideCollision(Robot.rect3, Robot.rect4, Robot.footleft, Robot.footright);
}
}
public int getTileX() {
return tileX;
}
public void setTileX(int tileX) {
this.tileX = tileX;
}
public int getTileY() {
return tileY;
}
public void setTileY(int tileY) {
this.tileY = tileY;
}
public Image getTileImage() {
return tileImage;
}
public void setTileImage(Image tileImage) {
this.tileImage = tileImage;
}
public void checkVerticalCollision(Rectangle rtop, Rectangle rbot) {
if (rtop.intersects(r)) {
}
if (rbot.intersects(r) && type == 8) {
robot.setJumped(false);
robot.setSpeedY(0);
robot.setCenterY(tileY - 63);
}
}
public void checkSideCollision(Rectangle rleft, Rectangle rright, Rectangle leftfoot, Rectangle rightfoot) {
if (type != 5 && type != 2 && type != 0){
if (rleft.intersects(r)) {
robot.setCenterX(tileX + 102);
robot.setSpeedX(0);
}else if (leftfoot.intersects(r)) {
robot.setCenterX(tileX + 85);
robot.setSpeedX(0);
}
if (rright.intersects(r)) {
robot.setCenterX(tileX - 62);
robot.setSpeedX(0);
}
else if (rightfoot.intersects(r)) {
robot.setCenterX(tileX - 45);
robot.setSpeedX(0);
}
}
}
}
import java.awt.Image;
import java.awt.Rectangle;
public class Tile {
private int tileX, tileY, speedX, type;
public Image tileImage;
private Robot robot = StartingClass.getRobot();
private Background bg = StartingClass.getBg1();
private Rectangle r;
public Tile(int x, int y, int typeInt) {
tileX = x * 40;
tileY = y * 40;
type = typeInt;
r = new Rectangle();
if (type == 5) {
tileImage = StartingClass.tiledirt;
} else if (type == 8) {
tileImage = StartingClass.tilegrassTop;
} else if (type == 4) {
tileImage = StartingClass.tilegrassLeft;
} else if (type == 6) {
tileImage = StartingClass.tilegrassRight;
} else if (type == 2) {
tileImage = StartingClass.tilegrassBot;
} else {
type = 0;
}
}
public void update() {
speedX = bg.getSpeedX() * 5;
tileX += speedX;
r.setBounds(tileX, tileY, 40, 40);
if (r.intersects(Robot.yellowRed) && type != 0) {
checkVerticalCollision(Robot.rect, Robot.rect2);
checkSideCollision(Robot.rect3, Robot.rect4, Robot.footleft, Robot.footright);
}
}
public int getTileX() {
return tileX;
}
public void setTileX(int tileX) {
this.tileX = tileX;
}
public int getTileY() {
return tileY;
}
public void setTileY(int tileY) {
this.tileY = tileY;
}
public Image getTileImage() {
return tileImage;
}
public void setTileImage(Image tileImage) {
this.tileImage = tileImage;
}
public void checkVerticalCollision(Rectangle rtop, Rectangle rbot) {
if (rtop.intersects(r)) {
}
if (rbot.intersects(r) && type == 8) {
robot.setJumped(false);
robot.setSpeedY(0);
robot.setCenterY(tileY - 63);
}
}
public void checkSideCollision(Rectangle rleft, Rectangle rright, Rectangle leftfoot, Rectangle rightfoot) {
if (type != 5 && type != 2 && type != 0){
if (rleft.intersects(r)) {
robot.setCenterX(tileX + 102);
robot.setSpeedX(0);
}else if (leftfoot.intersects(r)) {
robot.setCenterX(tileX + 85);
robot.setSpeedX(0);
}
if (rright.intersects(r)) {
robot.setCenterX(tileX - 62);
robot.setSpeedX(0);
}
else if (rightfoot.intersects(r)) {
robot.setCenterX(tileX - 45);
robot.setSpeedX(0);
}
}
}
}
The StartingClass
package kiloboltgame;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import kiloboltgame.framework.Animation;
public class StartingClass extends Applet implements Runnable, KeyListener {
private static Robot robot;
private Heliboy hb, hb2;
private Image image, currentSprite, character, character2, character3,
characterDown, characterJumped, background, heliboy, heliboy2,
heliboy3, heliboy4, heliboy5;
public static Image tilegrassTop, tilegrassBot, tilegrassLeft,
tilegrassRight, tiledirt;
private Graphics second;
private URL base;
private static Background bg1, bg2;
private Animation anim, hanim;
private ArrayList<Tile> tilearray = new ArrayList<Tile>();
@Override
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Q-Bot Alpha");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}
// Image Setups
character = getImage(base, "data/character.png");
character2 = getImage(base, "data/character2.png");
character3 = getImage(base, "data/character3.png");
characterDown = getImage(base, "data/down.png");
characterJumped = getImage(base, "data/jumped.png");
heliboy = getImage(base, "data/heliboy.png");
heliboy2 = getImage(base, "data/heliboy2.png");
heliboy3 = getImage(base, "data/heliboy3.png");
heliboy4 = getImage(base, "data/heliboy4.png");
heliboy5 = getImage(base, "data/heliboy5.png");
background = getImage(base, "data/background.png");
tiledirt = getImage(base, "data/tiledirt.png");
tilegrassTop = getImage(base, "data/tilegrasstop.png");
tilegrassBot = getImage(base, "data/tilegrassbot.png");
tilegrassLeft = getImage(base, "data/tilegrassleft.png");
tilegrassRight = getImage(base, "data/tilegrassright.png");
anim = new Animation();
anim.addFrame(character, 1250);
anim.addFrame(character2, 50);
anim.addFrame(character3, 50);
anim.addFrame(character2, 50);
hanim = new Animation();
hanim.addFrame(heliboy, 100);
hanim.addFrame(heliboy2, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy5, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy2, 100);
currentSprite = anim.getImage();
}
@Override
public void start() {
bg1 = new Background(0, 0);
bg2 = new Background(2160, 0);
robot = new Robot();
// Initialize Tiles
try {
loadMap("data/map1.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
hb = new Heliboy(340, 360);
hb2 = new Heliboy(700, 360);
Thread thread = new Thread(this);
thread.start();
}
private void loadMap(String filename) throws IOException {
ArrayList lines = new ArrayList();
int width = 0;
int height = 0;
BufferedReader reader = new BufferedReader(new FileReader(filename));
while (true) {
String line = reader.readLine();
// no more lines to read
if (line == null) {
reader.close();
break;
}
if (!line.startsWith("!")) {
lines.add(line);
width = Math.max(width, line.length());
}
}
height = lines.size();
for (int j = 0; j < 12; j++) {
String line = (String) lines.get(j);
for (int i = 0; i < width; i++) {
if (i < line.length()) {
char ch = line.charAt(i);
Tile t = new Tile(i, j, Character.getNumericValue(ch));
tilearray.add(t);
}
}
}
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void run() {
while (true) {
robot.update();
if (robot.isJumped()) {
currentSprite = characterJumped;
} else if (robot.isJumped() == false && robot.isDucked() == false) {
currentSprite = anim.getImage();
}
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
if (p.isVisible() == true) {
p.update();
} else {
projectiles.remove(i);
}
}
updateTiles();
hb.update();
hb2.update();
bg1.update();
bg2.update();
animate();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void animate() {
anim.update(10);
hanim.update(50);
}
@Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
@Override
public void paint(Graphics g) {
g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
g.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);
paintTiles(g);
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.YELLOW);
g.fillRect(p.getX(), p.getY(), 10, 5);
}
g.drawImage(currentSprite, robot.getCenterX() - 61,
robot.getCenterY() - 63, this);
g.drawImage(hanim.getImage(), hb.getCenterX() - 48,
hb.getCenterY() - 48, this);
g.drawImage(hanim.getImage(), hb2.getCenterX() - 48,
hb2.getCenterY() - 48, this);
}
private void updateTiles() {
for (int i = 0; i < tilearray.size(); i++) {
Tile t = (Tile) tilearray.get(i);
t.update();
}
}
private void paintTiles(Graphics g) {
for (int i = 0; i < tilearray.size(); i++) {
Tile t = (Tile) tilearray.get(i);
g.drawImage(t.getTileImage(), t.getTileX(), t.getTileY(), this);
}
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Move up");
break;
case KeyEvent.VK_DOWN:
currentSprite = characterDown;
if (robot.isJumped() == false) {
robot.setDucked(true);
robot.setSpeedX(0);
}
break;
case KeyEvent.VK_LEFT:
robot.moveLeft();
robot.setMovingLeft(true);
break;
case KeyEvent.VK_RIGHT:
robot.moveRight();
robot.setMovingRight(true);
break;
case KeyEvent.VK_SPACE:
robot.jump();
break;
case KeyEvent.VK_CONTROL:
if (robot.isDucked() == false && robot.isJumped() == false
&& robot.isReadyToFire()) {
robot.shoot();
robot.setReadyToFire(false);
}
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Stop moving up");
break;
case KeyEvent.VK_DOWN:
currentSprite = anim.getImage();
robot.setDucked(false);
break;
case KeyEvent.VK_LEFT:
robot.stopLeft();
break;
case KeyEvent.VK_RIGHT:
robot.stopRight();
break;
case KeyEvent.VK_SPACE:
break;
case KeyEvent.VK_CONTROL:
robot.setReadyToFire(true);
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public static Background getBg1() {
return bg1;
}
public static Background getBg2() {
return bg2;
}
public static Robot getRobot() {
return robot;
}
}
import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import kiloboltgame.framework.Animation;
public class StartingClass extends Applet implements Runnable, KeyListener {
private static Robot robot;
private Heliboy hb, hb2;
private Image image, currentSprite, character, character2, character3,
characterDown, characterJumped, background, heliboy, heliboy2,
heliboy3, heliboy4, heliboy5;
public static Image tilegrassTop, tilegrassBot, tilegrassLeft,
tilegrassRight, tiledirt;
private Graphics second;
private URL base;
private static Background bg1, bg2;
private Animation anim, hanim;
private ArrayList<Tile> tilearray = new ArrayList<Tile>();
@Override
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Q-Bot Alpha");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}
// Image Setups
character = getImage(base, "data/character.png");
character2 = getImage(base, "data/character2.png");
character3 = getImage(base, "data/character3.png");
characterDown = getImage(base, "data/down.png");
characterJumped = getImage(base, "data/jumped.png");
heliboy = getImage(base, "data/heliboy.png");
heliboy2 = getImage(base, "data/heliboy2.png");
heliboy3 = getImage(base, "data/heliboy3.png");
heliboy4 = getImage(base, "data/heliboy4.png");
heliboy5 = getImage(base, "data/heliboy5.png");
background = getImage(base, "data/background.png");
tiledirt = getImage(base, "data/tiledirt.png");
tilegrassTop = getImage(base, "data/tilegrasstop.png");
tilegrassBot = getImage(base, "data/tilegrassbot.png");
tilegrassLeft = getImage(base, "data/tilegrassleft.png");
tilegrassRight = getImage(base, "data/tilegrassright.png");
anim = new Animation();
anim.addFrame(character, 1250);
anim.addFrame(character2, 50);
anim.addFrame(character3, 50);
anim.addFrame(character2, 50);
hanim = new Animation();
hanim.addFrame(heliboy, 100);
hanim.addFrame(heliboy2, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy5, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy2, 100);
currentSprite = anim.getImage();
}
@Override
public void start() {
bg1 = new Background(0, 0);
bg2 = new Background(2160, 0);
robot = new Robot();
// Initialize Tiles
try {
loadMap("data/map1.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
hb = new Heliboy(340, 360);
hb2 = new Heliboy(700, 360);
Thread thread = new Thread(this);
thread.start();
}
private void loadMap(String filename) throws IOException {
ArrayList lines = new ArrayList();
int width = 0;
int height = 0;
BufferedReader reader = new BufferedReader(new FileReader(filename));
while (true) {
String line = reader.readLine();
// no more lines to read
if (line == null) {
reader.close();
break;
}
if (!line.startsWith("!")) {
lines.add(line);
width = Math.max(width, line.length());
}
}
height = lines.size();
for (int j = 0; j < 12; j++) {
String line = (String) lines.get(j);
for (int i = 0; i < width; i++) {
if (i < line.length()) {
char ch = line.charAt(i);
Tile t = new Tile(i, j, Character.getNumericValue(ch));
tilearray.add(t);
}
}
}
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void run() {
while (true) {
robot.update();
if (robot.isJumped()) {
currentSprite = characterJumped;
} else if (robot.isJumped() == false && robot.isDucked() == false) {
currentSprite = anim.getImage();
}
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
if (p.isVisible() == true) {
p.update();
} else {
projectiles.remove(i);
}
}
updateTiles();
hb.update();
hb2.update();
bg1.update();
bg2.update();
animate();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void animate() {
anim.update(10);
hanim.update(50);
}
@Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
@Override
public void paint(Graphics g) {
g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
g.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);
paintTiles(g);
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.YELLOW);
g.fillRect(p.getX(), p.getY(), 10, 5);
}
g.drawImage(currentSprite, robot.getCenterX() - 61,
robot.getCenterY() - 63, this);
g.drawImage(hanim.getImage(), hb.getCenterX() - 48,
hb.getCenterY() - 48, this);
g.drawImage(hanim.getImage(), hb2.getCenterX() - 48,
hb2.getCenterY() - 48, this);
}
private void updateTiles() {
for (int i = 0; i < tilearray.size(); i++) {
Tile t = (Tile) tilearray.get(i);
t.update();
}
}
private void paintTiles(Graphics g) {
for (int i = 0; i < tilearray.size(); i++) {
Tile t = (Tile) tilearray.get(i);
g.drawImage(t.getTileImage(), t.getTileX(), t.getTileY(), this);
}
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Move up");
break;
case KeyEvent.VK_DOWN:
currentSprite = characterDown;
if (robot.isJumped() == false) {
robot.setDucked(true);
robot.setSpeedX(0);
}
break;
case KeyEvent.VK_LEFT:
robot.moveLeft();
robot.setMovingLeft(true);
break;
case KeyEvent.VK_RIGHT:
robot.moveRight();
robot.setMovingRight(true);
break;
case KeyEvent.VK_SPACE:
robot.jump();
break;
case KeyEvent.VK_CONTROL:
if (robot.isDucked() == false && robot.isJumped() == false
&& robot.isReadyToFire()) {
robot.shoot();
robot.setReadyToFire(false);
}
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Stop moving up");
break;
case KeyEvent.VK_DOWN:
currentSprite = anim.getImage();
robot.setDucked(false);
break;
case KeyEvent.VK_LEFT:
robot.stopLeft();
break;
case KeyEvent.VK_RIGHT:
robot.stopRight();
break;
case KeyEvent.VK_SPACE:
break;
case KeyEvent.VK_CONTROL:
robot.setReadyToFire(true);
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public static Background getBg1() {
return bg1;
}
public static Background getBg2() {
return bg2;
}
public static Robot getRobot() {
return robot;
}
}
|
|

unit3day5.zip | |
File Size: | 397 kb |
File Type: | zip |