I am making a pong type game in java and I am trying to make the ball bounce off of the walls but whenever the ball hits the ball it just stops, it does not reflect off of the wall and I can't seem to figure out why.
Ball class which handles the ball movement
public class Ball {
private double x;
private double y;
private double time;
private double xreflection=1.0;
private double yreflection=1.0;
private BallTrajectory traj=new BallTrajectory(20, 20);
public Ball(double x, double y) {
this.x=x;
this.y=y;
}
public void tick() {
time+=1.0/60.0;
if(x==0)
xreflection=1.0;
else if(x==Game.Width-15)
xreflection=-1.0;
if(y==0)
yreflection=1.0;
else if(y==Game.Height-15)
yreflection=-1.0;
x+=traj.xvel()*xreflection;
y-=traj.yvel(time)*yreflection;
}
public void render(Graphics g) {
g.setColor(Color.pink);
g.fillOval((int)x, (int)y, 15,15);
}
}
This class handles the trajectory of the ball as it moves in projectile type motion
public class BallTrajectory {
private double initvel;
private double theta;
public BallTrajectory(double initvel, double theta) {
this.initvel=initvel;
this.theta=theta;
}
public double xvel() {
double xvelo=initvel*Math.cos(Math.toRadians(theta));
return xvelo;
}
public double yvel(double time) {
double yvelo=initvel*Math.sin(Math.toRadians(theta))-(9.8*time);
return yvelo;
}
public double xpos(double time) {
double xpos=initvel*Math.cos(Math.toRadians(theta))*time;
return xpos;
}
public double ypos(double time) {
double ypos=initvel*Math.sin(Math.toRadians(theta))*time-.5*9.8*Math.pow(time, 2);
return ypos;
}
Without going through a whole bunch of testing, I would suggest that it is very unlikely that x will ever be exactly equal to Game.Width or 0. Instead, you should be testing that the value is "within bounds" instead, maybe something like...
public void tick() {
time += 1.0 / 60.0;
if (x <= 0) {
xreflection = 1.0;
} else if (x >= Game.Width - 15) {
xreflection = -1.0;
}
if (y <= 0) {
yreflection = 1.0;
} else if (y >= Game.Height - 15) {
yreflection = -1.0;
}
x += traj.xvel() * xreflection;
y -= traj.yvel(time) * yreflection;
}
You should also start taking the time to learn how to debug your code, it is something you will need to do a lot, from desk-checking your logic to using print statements and the debugger
I have an arraylist of popcorn made by the following:
public class Popcorn
{
int posX;
int posY;
int speed;
int taps;
public Popcorn(int x, int y)
{
posX = x;
posY = y;
speed = PowerConstants.popcorn_speed;
taps = 0;
}
public void tick()
{
posY += speed;
}
public int getX()
{
return posX;
}
public int getY()
{
return posY;
}
public void addTap()
{
taps++;
}
public int getTaps()
{
return taps;
}
}
I have different powerups I want to use on these popcorn, one of which involves making the popcorn fall faster down the screen (dealing therefore with the speed) for a certain amount of time. The powerup works (and so does the timing system); however, it only affects newly created popcorn, not the popcorn that are already on the screen. Here is the relevant code:
ArrayList <Popcorn> popcorns;
Image happyPopcorn;
popcorns = new ArrayList<Popcorn>();
happyPopcorn = Assets.happyPopcorn;
//This section is in the updateRunning() section of my code
if ((PowersScreen3.getDecodedChoice() == Assets.powerup_speedup && System.currentTimeMillis() - power_start_3 <= 10000) ||
(PowersScreen2.getDecodedChoice() == Assets.powerup_speedup && System.currentTimeMillis() - power_start_2 <= 10000) ||
(PowersScreen.getDecodedChoice() == Assets.powerup_speedup && System.currentTimeMillis() - power_start <= 10000)) {
//The above if-state is just checking the timing system and deciding which powerup was chosen
PowerConstants.popcorn_speed = 4;
Log.d("Powerups", "all popcorn speed up");
}
It makes sense that by changing the speed constant, the speed of the newly formed popcorn would change. However, I also want the current popcorn in the arraylist to change their speed as well. How can I do this?
Currently I'm working on a simple 2d platformer, and I decided to work on physics before working on the general concept of the game. I actually haven't learned physics in school or anything, so I'm just using google/youtube tutorials as my main resources. I've currently gotten jumping working pretty nicely, but moving side to side isn't what I would like it to be. I want it to use acceleration/deceleration vs. just incrementing/decrementing the x position by a constant speed. Now I've tried using this website for x motion but that seems to be what I'm using for jumping. Here is my current player class:
import game.Game;
import game.input.PlayerController;
public class Player {
private float dt = 0.18F, gravity = 9.81F;
public float x, y, dx, dy;
private PlayerController controller;
private boolean jumping, onGround;
public float speed = 7.5F;
public float jh = 60F;
public float vy = 120F;
public Player() {
controller = new PlayerController();
}
public void update() {
controller.update(this);
dy += gravity * dt * (jumping ? -1F : 1F);
if(!jumping && !onGround && dy > vy) dy = vy;
y += dy * dt + 0.5F * gravity * dt * dt;
x += dx;
if (y > Game.height - 32) {
dy = 0;
y = Game.height - 32;
onGround = true;
} else
onGround = false;
if(dy < jh) { jumping = false;}
dx = 0;
}
public void render(Graphics g) {
g.setColor(Color.red);
g.fillRect(x, y, 32, 32);
}
public void moveLeft() {
dx -= speed;
}
public void moveRight() {
dx += speed;
}
public void jump() {
if (onGround) {
jumping = true;
dy -=jh;
}
}
}
In the PlayerController class I'm just calling player.moveLeft() and player.moveRight() when the left and right keys are pressed.
If anybody has a good idea on how to make smoother movement, that would be very helpful. Thanks!
Question: So I have created a program with a Window class that creates a JFrame and adds a JPanel from my DrawStuff class onto it. The DrawStuff class creates a ball that (is supposed to) bounce around the screen and when it hits the JFrame boundaries, change direction. The ball moves but for some reason the checkbounds part of my move method does not work. Any help would be greatly appreciated. My goal is to keep the ball in bounds.
Code from DrawStuff class:
public class Drawstuff extends JPanel {
private int x = 0;
private int y = 0;
private int dx, dy=0;
public Drawstuff(){
x = 300;
y = 250;
dx = 0;
dy = 0;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
this.setBackground(Color.BLACK);
g2d.setColor(Color.RED);
g2d.fillOval(x,y,50,50);
}
public void move(){
if (x < 600){
dx = 1;
}
if (y < 500){
dy = 1;
}
if (x > 600){
dx = -1;
}
if (y >500){
dy = -1;
}
x += dx;
y += dy;
}
}
Simple "GameLoop" from Window Class (if needed)
while (true){
stuff.repaint();
stuff.move();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Your move is wrong. The logic of it is false. You want the ball to bounce so make its movement reverse when it hits a wall. What you've done is : if it is outside get it inside and when inside try to get it outside! Change to:
public void move(){
if (x < 0) { // left bound
dx = 1; // now move right
}
if (y < 0){ // upper bound
dy = 1; // now move down
}
if (x > 600){// right bound
dx = -1; // now move left
}
if (y >500){ // lower bound
dy = -1; // now move up
}
x += dx;
y += dy;
}
For future use, I can suggest you to do it the following way :
public void move(){
if (x < 0) { // left bound
dx = -dx; // now move right, same speed
x=-x; // bounce inside
}
if (y < 0){ // upper bound
dy = -dy; // now move down, same speed
y=-y; // bounce inside
}
if (x > 600){ // right bound
dx = -dy; // now move left, same speed
x=600-(x-600); // bounce inside
}
if (y >500){ // lower bound
dy = -dy; // now move up, same speed
y=500-(y-500); // bounce inside
}
x += dx;
y += dy;
}
So you can now use any vector speed you want (at least reasonable ones). Vector coordinates are reversed accordingly to the hit, and the ball is relocated inside the bounds.
I am making a 2d rpg game in java and I have run into a problem. I can make the player move around the stage and I have rocks, trees, walls, etc. on the stage as well. I don't know how to detect the collision and make it to where the player can't move through the object. The code that reads map file and draws image on the canvas is as follows:
public void loadLevel(BufferedImage levelImage){
tiles = new int[levelImage.getWidth()][levelImage.getHeight()];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Color c = new Color(levelImage.getRGB(x, y));
String h = String.format("%02x%02x%02x", c.getRed(),c.getGreen(),c.getBlue());
switch(h){
case "00ff00"://GRASS Tile - 1
tiles[x][y] = 1;
break;
case "808080"://Stone -2
tiles[x][y] = 2;
break;
case "894627"://Dirt -3
tiles[x][y] = 3;
break;
case "404040"://Rock on Grass -4
tiles[x][y] = 4;
break;
case "00b700"://Tree -5
tiles[x][y] = 5;
break;
case"000000"://Wall -6
tiles[x][y] = 6;
break;
case "cccccc"://Rock on stone -7
tiles[x][y] = 7;
break;
default:
tiles[x][y] = 1;
System.out.println(h);
break;
}
}
}
}
And the player class is as follows:
public class Player {
private int x,y;
public int locx,locy;
private Rectangle playerR;
private ImageManager im;
public boolean up =false,dn = false,lt=false,rt=false,moving = false,canMove = true;
private final int SPEED =2;
public Player(int x, int y, ImageManager im){
this.x = x;
this.y = y;
this.im = im;
locx = x;
locy = y;
playerR = new Rectangle(x,y,16,16);
}
public void tick(){
if (up) {
if(canMove){
y -= SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
moving = true;
}
else{
y += 1;
canMove=true;
}
}
if (dn) {
y +=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if (lt) {
x -= SPEED;
locx = x;
locy = y;
moving = true;
}
if (rt) {
x+=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if(moving){
System.out.println("PLAYER\tX:"+locx+" Y:"+locy);
moving = false;
}
}
public void render(Graphics g){
g.drawImage(im.player, x, y, Game.TILESIZE*Game.SCALE, Game.TILESIZE*Game.SCALE, null);
}
}
I don't really know how to do collision, but i googled it and people said to make a rectangle for the player and all the objects that the player should collide with, and every time the player moves, move the player's rectangle. Is this the right way to do this?
EDIT EDIT EDIT EDIT
code for when collision is true:
if (rt) {
x+=SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
for(int i = 0;i<Level.collisions.size();i++){
if(intersects(playerR,Level.collisions.get(i))==true){
x-=SPEED;
locx = x;
playerR.setLocation(locx, locy);
}
}
moving = true;
}
And the intersects method is as follows:
private boolean intersects(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}
I'm going to focus on your tick method since that is where most of this logic is going. There are a couple changes here. Most notably, we only move the rectangle before checking for collisions. Then loop through all the collideable objects in your level. Once one is found, we reset our x and y and break out of the loop (no sense in looking at any of the other objects since we already found the one we collided with). Then we update our player position. By doing it this way, I centralized the code so it is not being repeated. If you ever see yourself repeating code, there is a pretty good chance that it can be pulled out to a common place, or to a method.
public void tick() {
if (up) {
y -= SPEED;
} else if (dn) {
y += SPEED;
} else if (lt) {
x -= SPEED;
} else if (rt) {
x += SPEED;
}
playerR.setLocation(x, y);
for (Rectangle collideable : Level.collisions) {
if (intersects(playerR, collideable)) {
x = locx;
y = locy;
playerR.setLocation(x, y);
break;
}
}
locx = x;
locy = y;
}
There are different ways to do that. As you talk about a "rpg" i think your view is Isometric (45° top down).
I would do the collision detection in pure 90° top down, as it is easier and, imho, more realistic.
We have 2 possibilities:
Move your Player to the next position. If there is a collision, reset his position.
Calculate the next position, if there would be a collision don't move.
If you want to have a "gliding" collision response, you have to check in which axis the collision will happen, and stop / reset movement for this axis only.
To have a more efficient collision detection only check near objects, which will possibly collide.
Do this by comparing a squared "dangerRadius" with the squared distance between your player and the object:
if ((player.x - object.x)² + (player.y - object.y)² <= dangerRadius²)
// Check for intersection
This will sort out most of the objects by using a simple calculation of:
2 subtractions
1 addition
3 multiplications (the ²)
1 compare (<=)
In your game you should sepparate the logic and the view. So basicly you don't detect, if the two images overlapp, but you check, if the objects in your logic overlap. Then you draw the images on the right position.
Hope this helps.
EDIT: Important: If you update your character, depending on the time between the last and this frame (1/FPS) you have to limit the max timestep. Why? Because if for some reason (maybe slow device?) the FPS are really low, it is possible, that the character moves verry far between 2 frames and for that he could go through an object in 1 frame.
Also if you simply reset the movement on collision or just don't move the distance between you and the object could be big for low FPS. For normal FPS and not to high movementspeed this won't happen/ be noticeable.
I personally am fairly new to Java, though I have worked with C# in the past. I am making a similar game, and for collision detection I just check the locations of the player and objects:
if (z.gettileX() == p.gettileX()){
if (z.gettileY() == p.gettileY()){
System.out.println("Collision!");
}
}
If the player (p) has equal X coordinates and Y coordinates to z(the bad guy), it will send this message and confirm that the two have, in fact, collided. If you can make it inherent in the actual class behind z to check if the coordinates a equal, you can create an unlimited number of in-game objects that detect collision and react in the same way, i.e. walls.
This is probably what your looking for. I've made this class spicificly for collision of multiple objects and for individual side collisions.
abstract class Entity {
private Line2D topLine;
private Line2D bottomLine;
private Line2D leftLine;
private Line2D rightLine;
private Rectangle rectangle;
private Entity entity;
protected boolean top;
protected boolean bottom;
protected boolean left;
protected boolean right;
protected int x;
protected int y;
protected int width;
protected int height;
public Entity(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
updateLinesAndRects();
}
public void updateLinesAndRects() {
topLine = new Line(x + 1, y, width - 2, 0);
bottomLine = new Line(x + 1, y + height, width - 2, height);
leftLine = new Line(x, y + 1, 0, height - 2);
rightLine = new Line(x + width, y + 1, 0, height - 2);
rectangle = new Rectangle(x, y, width, height)
}
public void setCollision(Entity entity) {
this.entity = entity;
top = isColliding(new Line2D[]{topLine, bottomLine, leftLine, rightLine});
bottom = isColliding(new Line2D[]{bottomLine, topLine, leftLine, rightLine});
left = isColliding(new Line2D[]{leftLine, topLine, bottomLine, rightLine});
right = isColliding(new Line2D[]{rightLine, topLine, bottomLine, leftLine});
}
public void updateBounds() {
if(top) y = entity.y + entity.height;
if(bottom) y = entity.y - height;
if(left) x = entity.x + entity.width;
if(right) x = entity.x - width;
}
public boolean isColliding() {
return rectangle.intersects(entity.rect);
}
private boolean isLinesColliding(Line2D[] lines) {
Rectangle rect = entity.getRectangle();
return lines[0].intersects(rect) && !lines[1].intersects(rect) && !lines[2].intersects(rect) && !lines[3].intersects(rect);
}
private Line2D line(float x, float y, float width, float height) {
return new Line2D(new Point2D.Float(x, y), new Point2D.Float(x + width, x + height));
}
public Rectangle getRectangle() {
return rectangle;
}
}
Example:
class Player extends Entity{
Entity[] entities;
public Player(int x, int y, int width, int height) {
super(x, y, width, height);
}
public void update() {
updateLinesAndRects();
for(Entity entity : entities) {
setCollision(entity);
if(top) system.out.println("player is colliding from the top!");
if(isColliding()) system.out.println("player is colliding!");
updateBounds(); // updates the collision bounds for the player from the entities when colliding.
}
}
public void setEntities(Entity[] entities) {
this.entities = entities;
}
}