I try to create a very simple physics engine for my study (processing used for a interactive installation).
The target is to have a ground covered with balls that you can throw around with gestures (based on Kinect information).
Therefor I need to do some basic physic simulation like bouncing and thats what I started with. So there are just balls falling down and bouncing. I simulated the air resistance with a simple 0.995f multiplication on the speed if the ball moves up. Works nice and looks realistic. The main problem is, that the balls never stay calm on the ground. Instead they start to tremble on the ground. That means there is a movement of 1 or 2 pixels up and down.
How can I prevent that without implementing some "borders" on which I set the position directly to the bottom and the speed to zero?
My applet:
public class BubblePhysicApplet extends PApplet {
public static int width = 640;
public static int height = 480;
long lastTime = -1;
Bubble[] mBubbles = new Bubble[10];
Random mRandom = new Random();
public void setup() {
// size(width, height, OPENGL);
size(width, height, P2D);
for (int i = 0; i < mBubbles.length; i++) {
mBubbles[i] = new Bubble(mRandom.nextInt(width), mRandom.nextInt(height), 50);
}
lastTime = System.currentTimeMillis();
}
public void draw() {
background(0);
long tmp = System.currentTimeMillis();
long elapsed = tmp - lastTime;
for (Bubble bubble : mBubbles) {
bubble.animate(elapsed);
bubble.draw(this);
}
lastTime = System.currentTimeMillis();
}
}
The ball/bubble:
public class Bubble {
float mX;
float mY;
float mSize;
float mSpeedX = 0;
float mSpeedY = 0;
public Bubble(int x, int y, int size) {
mX = x;
mY = y;
mSize = size;
}
public void draw(PApplet applet) {
applet.stroke(255);
applet.noFill();
applet.ellipseMode(PApplet.CENTER);
applet.ellipse(mX, mY, mSize, mSize);
}
public void animate(long elapsed) {
updateSpeedY(elapsed);
if (mSpeedX != 0 || mSpeedY != 0) {
checkBorders();
}
}
private void checkBorders() {
if (mY > BubblePhysicApplet.height - mSize / 2) {
mY = 2 * BubblePhysicApplet.height - (mY + mSize);
mSpeedY = -mSpeedY;
}
if (mX > BubblePhysicApplet.width) {
mX = BubblePhysicApplet.width - (mX - BubblePhysicApplet.width);
mSpeedX = -mSpeedX;
}
}
private void updateSpeedX() {
}
private void updateSpeedY(long elapsed) {
mSpeedY += (elapsed / 1000f) * 9.81f;
if (mSpeedY < 0) {
mSpeedY *= 0.95f;
}
mY += mSpeedY;
}
}
It's not only air resistance that slows the ball down, but the fact that it's not perfectly elastic as this line suggests: mSpeedY = -mSpeedY;
The ball absorbs energy when it squishes against the floor before it bounces back, so it doesn't bounce as high. Try a real super ball. I seem to remember it only bounces 80% as high or so. You might try:
mSpeedY = - (0.8 * mSpeedY);
you have to fix your check borders method, read this answer I just gave a complete formulas needed for realistic physical simulation. and it's also more realistic if you move objects using hist method (p = v*dt + 1/2*adtdt)
The problem is that in updateSpeedY we have mSpeedY += (elapsed / 1000f) * 9.81f; even when there is a collision. That said collision is detected later in checkBorders where the speed is flipped mSpeedY = -mSpeedY;. The problem is that if the ball is hitting the floor with a speed near 0, it bounces with a speed of 0 + (elapsed / 1000f) * 9.81f;!!
You have to rethink your code.
in the same fashion you used a friction factor for the air, you can also include a friction factor for the contact with the ground, and which even higher values, so at each contact, it starts to lose eneger rapidly and finally stops
Related
It's basically a simple game, in that, when the mouse pointer is within the circle, it adds one to the score. I'm new to processing and tried to create this simple game.
Here's the code:
float dist;
float score;
float x;
float y;
float ran;
float a;
float b;
void setup(){
size(800,600);
background(0);
score = 0;
}
void draw(){
background(0);
text("score: "+score,600,20);
x = random(800);
y = random(600);
circle_(x,y);
if ( (abs(mouseX - x) <= 200) && (abs(mouseY - y) <= 200 )) { // algorithm for checking whether mouse inside the circle or not
score = score + 1;
}
}
void circle_(float x,float y){
delay(1000);
circle(x,y,50);
}
There are 2 problems here: first, you're checking 200 pixels where it should be 25 (as in 25 being half the diameter of the circle). But this is the easy one. The real issue is with the delay(1000); line.
That's the real pain.
It means that your program "sleeps" for about 1000/1001 seconds. While the mouse can go around the screen, this one just isn't listening. It's waiting.
You can track time in Processing with the millis() method. It gives you how many milliseconds have passed since you started running the sketch. I ninja coded you a couple lines to keep track of time and teleport the circle every 1 second. Here's the code:
float score;
float x;
float y;
int respawnCircle;
void setup() {
size(800, 600);
background(0);
score = 0;
}
void draw() {
background(0);
text("score: "+score, 600, 20);
if (millis() > respawnCircle) {
changeCircleCoordinates();
}
circle_(x, y);
if ((abs(mouseX - x) <= 25) && (abs(mouseY - y) <= 25 )) { // using 25 as it's half the circle's diameter
score = score + 1;
// if you want the circle to change place right when you get one point uncomment the next line
// changeCircleCoordinates();
}
}
void changeCircleCoordinates() {
respawnCircle = millis() + 1000;
x = random(800);
y = random(600);
}
void circle_(float x, float y) {
//delay(1000); // this is why your collision detection wasn't working: the program is sleeping for about 1000/1001 milliseconds... you have to be very lucky to be on target at just the right time
circle(x, y, 50);
}
Hope it helps. Have fun!
I am currently working on a 3 cushion billiards game project. I have added two balls on the table so far. I am trying to move one of the balls but I am having a hard time doing that. Should I use a timer? If so then could you tell me an effective way to use the timer on my code so I can move my balls?
Your help would be much appreciated.
Thanks in advance.
Farhan Hasan
I have tried to create a move function for the class balls. But I am not sure what I should put inside the function, I have added the xSpeed and ySpeed. The xLocation and the yLocation changes depending on the xSpeed and ySpeed.
public class Balls
{
private Color ballFillColor;
private Color ballBorderColor;
private int ballX = 0;
private int ballY = 0;
private int xSpeed = 5;
private int ySpeed = 0;
private int ballWidth = 0;
private int ballHeight = 0;
Timer t;
public boolean fillBall = false;
private static Balls ballArray[]; //Required for drawMultipleBalls
Balls(){ //Constructor
ballBorderColor = Color.black;
}
Balls(int ballX, int ballY, int ballWidth, int ballHeight, Color ballBorderColor, JFrame window){ //Constructor
// X , Y , Width, Height, Border Colour, container
this.setBallBorderColor(ballBorderColor);
this.setBallWidth(ballWidth);
this.setBallHeight(ballHeight);
this.setBallX(ballX);
this.setBallY(ballY);
this.drawBall(window);
}
//Here is the move function. I am not really sure what to do here.
public void move()
{
if(this.ballX < 1000 - this.ballWidth)
{
this.ballX += this.xSpeed;
}
try
{
Thread.sleep(1);
}
catch(Exception e)
{
}
}
//GET AND SET FUNCTIONS HERE
//HERE ARE THE FUNCTIONS WHICH ARE RESPONSIBLE FOR DRAWING MY BALLS IN JFRAME
public void drawBall(JFrame frame)
{
frame.getContentPane().add(new MyComponent());
}
public void drawMultipleBalls(JFrame frame, Balls[] balls)
{
ballArray = balls;
frame.getContentPane().add(new MyComponent2());
}
private class MyComponent extends JComponent{
public void paintComponent(Graphics g){
if (fillBall) //Fill first, and then draw outline.
{
g.setColor(ballFillColor);
g.fillOval(getBallX(),getBallY(), getBallHeight(),getBallWidth());
}
g.setColor(getBallBorderColor());
g.drawOval(getBallX(),getBallY(), getBallHeight(),getBallWidth());
}
}
private class MyComponent2 extends JComponent{
public void paintComponent(Graphics g){
for (int i = 0; i < ballArray.length; i++)
{
if (ballArray[i].fillBall) //Fill first, and then draw outline.
{
g.setColor(ballArray[i].ballFillColor);
g.fillOval(ballArray[i].getBallX(),ballArray[i].getBallY(), ballArray[i].getBallHeight(),ballArray[i].getBallWidth());
}
g.setColor(ballArray[i].getBallBorderColor());
g.drawOval(ballArray[i].getBallX(),ballArray[i].getBallY(), ballArray[i].getBallHeight(),ballArray[i].getBallWidth());
}
}
}
Hopefully, I can have two movable balls for the game, the should bounce back as the hit the edge of the screen and they should be able to slow down over time. For that, I am thinking to use a damper (I will multiply the xSpeed and ySpeed with a number less than 1, eventually it will slow down the ball)
Here is a simple example I came up with to show a ball moving and bouncing off the edges.
The direction changes based on the boundary. Left and top edges just check for 0. Bottom and right edges need to include the diameter of the ball.
The x and y increments are independent. And these amounts in conjunction with the timer can change the movement. Notice however, that to have objects bounce off of each other (as in a pool game) is more complicated due to angle of trajectories, etc. And the distances bounced will vary and slow with time based on frictional values. Everything else is documented in the Java API.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MovementDemo extends JPanel implements ActionListener {
JFrame frame = new JFrame("Movement Demo");
int size = 500;
int x = 50;
int y = 200;
int diameter = 50;
int yinc = 2;
int xinc = 2;
int xdirection = 1;
int ydirection = 1;
public MovementDemo() {
setPreferredSize(new Dimension(size, size));
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new MovementDemo().start());
}
public void start() {
Timer timer = new Timer(100, this);
timer.setDelay(5);
timer.start();
}
public void actionPerformed(ActionEvent ae) {
if (x < 0) {
xdirection = 1;
}
else if (x > size - diameter) {
xdirection = -1;
}
if (y < 0) {
ydirection = 1;
}
else if (y > size - diameter) {
ydirection = -1;
}
x = x + xdirection * xinc;
y = y + ydirection * yinc;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLUE);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, diameter, diameter);
}
}
It seems in general there are a few things you need to figure out:
has the ball collided with another ball
has the ball collided with a wall
otherwise just figure out what is the ball's new position based on its velocity
Below is some sample code that stubs some of this out. You can first compare the current ball's position to all others (not including the current ball of course). If there are any equal positions, process a collision with a ball. If the ball is at the window border i.e it hit a wall, process a collision with a wall. Otherwise just calculate its new position based on its current velocity.
The process collision part is just to apply physics mechanics to whatever degree of complexity you require. One general suggested change would be to update the velocity of the balls then apply it to the position after. The specific calculations for velocity changes you could apply as needed and as you can imagine it can get pretty involved which is why I suggest using a separate method and possibly a sub class for velocity instead of managing each part of the velocity vector in the ball itself. I used the wall as an object because of this. The composition, weights, velocities etc of the object's colliding can affect the resulting collision, but how complex you want that processing to be is up to you.
Sorry I'm no physics expert but I hope this sends you in the right direction in terms of code! Also this might help with the specific calculations you might want to use:
https://www.khanacademy.org/science/physics/one-dimensional-motion/displacement-velocity-time/v/calculating-average-velocity-or-speed
public void move()
{
// check if balls are on same position not including this ball
for(Ball b: ballArray){
if (this.position == b.position && this != b){
processCollision(this, b, null);
} else{
// if the ball hasn't collided with anything process its movement based on speed
// this assumes a 1000 x 1000 window for keeping objects inside it
if(this.ballX < 1000 - this.ballWidth && this.ballY < 1000 - this.ballHeight){
this.ballX += this.xSpeed;
this.ballY += this.ySpeed;
}else {
processCollision(this, null, new Wall());
}
}
}
try
{
Thread.sleep(1);
}
catch(Exception e)
{
}
}
public void processCollision(Ball b1, Ball b2, Wall w){
// if ball hasn't collided with a wall, process a ball - ball collision
if(w == null){
// apply physics mechanics according the complexity desired for ball collisions
b1.xSpeed -= b2.xSpeed;
b1.ySpeed -= b2.ySpeed;
// ball 2 would end up slowing down
b2.xSpeed -= b1.xSpeed;
b2.ySpeed -= b1.ySpeed;
}
// if ball hasn't collided with a ball, process a ball - wall collision
if(b2 == null){
// apply physics mechanics for hitting a wall
// e.g as below: just send ball in opposite direction
b1.xSpeed = b1.xSpeed * -1;
b1.ySpeed = b1.ySpeed * -1;
}
// either way, process ball's new position based on its new speed
b1.ballX += b1.xSpeed;
b1.ballY += b1.ySpeed;
b2.ballX += b2.xSpeed;
b2.ballY += b2.ySpeed;
}
I am working on a 2D platformer game for my, last, HS year project.
The game is basically about a player walking back & forward, collecting points and reaching goals... The player can shoot bullets and when bullets hit a block, it is destroyed. Now, I wanted to add an explosion effect using so called "particle" objects. I have written the manager class for it and it seemed to have worked the first time but after shooting a few times, i noticed that the particles stopped getting deleted, they just continue and travel out of screen. The life-time limit is 500ns.
I have also noticed that if i shoot bullets as soon as the game starts, the effect finishes as it is supposed to. but after waiting for a few more seconds and then shooting bullets, the effect particles do not behave as they should.
Here is what it looks like when i shoot bullets as soon as i start the game (What it's supposed to look like):
and here is what it looks like, after waiting a few seconds before shooting the bullets.
ParticleManager.java
public class ParticleManager {
private ArrayList<Particle> particles;
private ArrayList<Particle> removeParticles;
public ParticleManager() {
particles = new ArrayList<Particle>();
removeParticles = new ArrayList<Particle>();
}
public int getListSize() {
return particles.size();
}
/*
Generate particles
*/
public void genParticle(int x, int y, int amount) {
for(int i = 0; i < amount; i++) {
particles.add(new Particle("explosion" , x,y, i));
}
}
public void update() {
// Iterate trough particle objects
// update them & check for lifeTime
for(Particle p: particles) {
// Updating particle object before
// checking for time lapse
p.update();
// Append outdated particles to removeParticles
// if time limit has passed
if(System.nanoTime() - p.timePassed >= Config.particleLife) {
removeParticles.add(p);
}
}
// finally, delete all "remove-marked" objects
particles.removeAll(removeParticles);
}
public void render(Graphics2D g) {
for(Particle p: particles) {
p.render(g);
}
}
}
Particle.java
class Particle {
private double px, py, x, y;
private int radius, angle;
public long timePassed;
String type;
public Particle(String type, double x, double y, int angle) {
this.x = x;
this.y = y;
this.radius = 0;
this.angle = angle;
this.timePassed = 0;
this.type = type; // explosion, tail
}
public void update() {
px = x + radius * Math.cos(angle);
py = y + radius * Math.sin(angle);
radius += 2;
this.timePassed = System.nanoTime();
}
public void render(Graphics2D g) {
g.setColor(Color.WHITE);
g.fillOval((int)px, (int)py, 5, 5);
}
}
I haven't figured out what I am doing wrong here, I've googled about some stuff and at one point i came across an answer mentioning that some references don't get deleted directly for some reason...
and my question is "How can I make these particles vanish after a certain amount of time has passed? - as shown in the first GIF"
I think the problem is that you are constantly overwriting timePassed.
// Updating particle object before
// checking for time lapse
p.update();
// Append outdated particles to removeParticles
// if time limit has passed
if(System.nanoTime() - p.timePassed >= Config.particleLife) {
removeParticles.add(p);
}
p.update() sets timePassed to now and then the if check checks if time passed is far from now (it will never be since it was just set).
I think you do want to set timePassed in the constructor (maybe it would be better named timeCreated).
Additionally, just a heads up, you never clear removeParticles so that list is going to grow forever until it causes the process to run out of memory.
I have created a simple rendition of the classic Pong game on Android Studio for a college course. At this point, almost everything is ready to go, except for the fact that I created an unbeatable AI for the enemy paddle. I created the paddles and the ball with the default RectF class and change my AI paddle's position based on the ball's current position (I subtract/add by 65 because my paddles' lengths are 130 pixels and it centers the paddle compared to the ball). This essentially allows the enemy paddle to move at an infinite speed because it is matching the ball's speed/position (the ball speed increases with each new level). Here is that method:
public void AI(Paddle paddle) {
RectF paddleRect = paddle.getRect();
RectF ballRect = ball.getRect();
if (ballRect.left >= 65 && ballRect.right <= screenX - 65) {
paddleRect.left = (ballRect.left - 65);
paddleRect.right = (ballRect.right + 65);
}
if (ballRect.left < 65) {
paddleRect.left = 0;
paddleRect.right = 130;
}
if (ballRect.right > screenX - 65) {
paddleRect.left = screenX - 130;
paddleRect.right = screenX;
}
}
For reference, here are the relevant parts of my Paddle class:
public Paddle(float screenX, float screenY, float xPos, float yPos, int defaultSpeed){
length = 130;
height = 30;
paddleSpeed = defaultSpeed;
// Start paddle in the center of the screen
x = (screenX / 2) - 65;
xBound = screenX;
// Create the rectangle
rect = new RectF(x, yPos, x + length, yPos + height);
}
// Set the movement of the paddle if it is going left, right or nowhere
public void setMovementState(int state) {
paddleMoving = state;
}
// Updates paddles' position
public void update(long fps){
if(x > 0 && paddleMoving == LEFT){
x = x - (paddleSpeed / fps);
}
if(x < (xBound - 130) && paddleMoving == RIGHT){
x = x + (paddleSpeed / fps);
}
rect.left = x;
rect.right = x + length;
}
The fps in the update(long fps) method above is passed through from the run() method in my View class:
public void run() {
while (playing) {
// Capture the current time in milliseconds
startTime = System.currentTimeMillis();
// Update & draw the frame
if (!paused) {
onUpdate();
}
draw();
// Calculate the fps this frame
thisTime = System.currentTimeMillis() - startTime;
if (thisTime >= 1) {
fps = 1000 / thisTime;
}
}
}
My paddles and ball constantly update in my onUpdate() method in the View class.
public void onUpdate() {
// Update objects' positions
paddle1.update(fps);
ball.update(fps);
AI(paddle2);
}
How can I attach a speed limit to my AI paddle using the paddle speed I already define for each new paddle? I've already tried modifying the AI(Paddle paddle) method to incorporate +/- (paddleSpeed / fps) and it didn't affect the paddle seemingly at all. Maybe I just implemented it wrong, but any help would be fantastic!
To make the AI move the paddle at a steady rate rather than jumping to the correct spot, just try to make the middle of the paddle line up with the middle of the ball:
public void AI(Paddle paddle) {
RectF paddleRect = paddle.getRect();
RectF ballRect = ball.getRect();
float ballCenter = (ballRect.left + ballRect.right) / 2;
float paddleCenter = (paddleRect.left + paddleRect.right) / 2;
if (ballCenter < paddleCenter) {
setMovementState(LEFT);
}
else {
setMovementState(RIGHT);
}
}
and then after you call AI(paddle2) inside of onUpdate, call paddle2.update(fps). This way you aren't repeating yourself with the drawing code. You will notice that the AI paddle may not do perfectly if the ball is much faster than the paddle. In this case you can use math to anticipate where the ball will end up and work on getting there.
So, I'm trying to make a game in LWJGL and it seems to work fine for me. Although, I ran into some issues in moving my entities around on the screen. I want to make it go from one point to another, at the same speed. Also, I'm animating my sprite according to the direction the entity is moving.
But! I have some issues:
1# It flickers because the movement is defined a modifier: delta (to make smooth movement defined by the FPS). Actually, it never really reaches it's point (because it recalculates and never hits the position). How can I solve this?
2# When 2 players join the same server, my character on the fastest computer runs faster. I think it's because of the FPS, how can that be solved?
private String name;
private float positionx,positiony; // Current
private int targetx,targety; // Target
private int dx, dy; // Direction
private int pointx, pointy; // Direction
private float speed;
private Sprite sprite;
public Entity(String name, int positionx, int positiony, Sprite sprite){
this.name = name;
this.speed = 0.1f;
this.positionx = 720;
this.positiony = 450;
this.targetx = 1000; // fix this
this.targety = 10; // this for testing.
this.sprite = sprite;
this.dx = 0;
this.dy = 0;
}
//double distance = Math.sqrt((vx * vx) + (vy * vy));
public void move(long delta){
if(positionx < targetx){
dx = 1;
pointx = 1;
}else if(positionx > targetx){
dx = -1;
pointx = -1;
}else{
dx = 0;
}
if(positiony < targety){
dy = 1;
pointy = 1;
}else if(positiony > targety){
dy = -1;
pointy = -1;
}else{
dy = 0;
}
//Set animations:
if(positionx==targetx && positiony==targety){
if(pointx<0){
sprite.setAnimation(5, 2, 100); // Standing left
}else if(pointx>0){
sprite.setAnimation(6, 2, 100); // Standing right
}else if(pointy<0){
sprite.setAnimation(7, 2, 100); // Standing up
}else if(pointy>0){
sprite.setAnimation(4, 2, 100); // Standing down
}
}else{
if(pointx<0){
sprite.setAnimation(1, 2, 100); // Walking left
}else if(pointx>0){
sprite.setAnimation(2, 2, 100); // Walking right
}else if(pointy<0){
sprite.setAnimation(3, 2, 100); // Walking up
}else if(pointy>0){
sprite.setAnimation(0, 2, 100); // Walking down
}
}
//movement here.
positionx += dx*delta*speed;
positiony += dy*delta*speed;
System.out.println(dx*delta*speed);
sprite.setPosition((int)positionx, (int)positiony);
}
1# It flickers because the movement is defined a modifier: delta (to make smooth movement defined by the FPS). Actually, it never really reaches it's point (because it recalculates and never hits the position). How can I solve this?
If you store point A and point B between which it moves, you can set a time interval. Each time interval a set distance will be travelled and if at one iteration the object goes too far you can set its coordinates for point B. This can be easily done with a Timer. That way, after a certain amount of time, it will be on your specified position.
2# When 2 players join the same server, my character on the fastest computer runs faster. I think it's because of the FPS, how can that be solved?
Same answer as question #1, if you use a Timer. Each player will move at the same speed (because the elapsed time is the same for each gamer).
Bottom line:
fps is variable, while elapsed time is the same for everyone.