I am new learner of public sources of stanford cs106a.
I got stucked when I read handout BouncingBall,here below are the complete codes
I got from cs106a handout.
The question is, for checkForCollision method code that is bottom of this page,
why should the ball do the code ball.move(0, -2 * diff), especially
execute the -2 * diff, I cannot understand this math code. Is it Ok for
ball do the code ball.move(0, -diff)? what is the difference?
what is the bounce logic? anyone here could help me to understand this
code, I am not good at math. Thank you so much
/*
* File: BouncingBall.java
*--------------------------
* This program graphically simulates a bouncing ball
*/
import acm.program.*;
import acm.graphics.*;
public class BouncingBall extends GraphicsProgram {
/** Size (diameter) of the ball */
private static final int DIAM_BALL = 30;
/** Amount Y velocity is increased each cycle
* as result of gravity
*/
private static final double GRAVITY = 3;
/** Animation delay or pause time between call moves */
private static final int DELAY = 50;
/** Initial X and Y location of ball */
private static final double X_START = DIAM_BALL;
private static final double Y_START = 100;
/** X Velocity */
private static final double X_VEL = 5;
/** Amount Y Velocity is reduced when it bounces */
private static final double BOUNCE_REDUCE = 0.9;
/** Starting X and Y Velocities */
private doublexVel = X_VEL;
private doubleyVel = 0.0;
/* private instance variable */
private GOval ball;
public void run() {
setup();
// Simulation ends when ball goes off right hand
// end of screen
while (ball.getX() < getWidth()) {
moveBall();
checkForCollision();
pause(DELAY);
}
}
/** Create and place a ball */
private void setup() {
ball = new GOval (X_START, Y_START, DIAM_BALL, DIAM_BALL);
ball.setFilled(true);
add(ball);
}
/** Update and move ball */
private void moveBall() {
// increase yVelocity due to gravity
yVel += GRAVITY;
ball.move(xVel, yVel);
}
/** Determine if collision with floor, update velocities
* and location as appropriate
*/
private void checkForCollision() {
if (ball.getY() > getHeight() - DIAM_BALL) {
// change ball's Y velocity to now bounce upwards.
yVel = -yVel * BOUNCE_REDUCE;
// Assume bounce will move ball an amount above
// the floor equal to the amount it would have dropped
// below the floor
double diff = ball.getY() - (getHeight() - DIAM_BALL);
ball.move(0, -2 * diff);
}
}
}
When the ball.move is called, the ball has moved beyond the surface it's bouncing against. So -diff would move it back to the surface, -2 * diff makes it bounce up.
Related
Working on a program that consists of emoji's and you get an emoji that you can shoot, bit like Angry Birds but way more basic. At the moment the stand still emoji is falling down (increasing vertical velocity by gravity until it hits the ground). However this only happens when the main object has a greater horizontal position than the stand still object.
/**
* Represents an emoji that can move on a window.
*/
public class Emoji{
// Constants for all Emoji: size, position of the ground
public static final double SIZE = 40; // width/length of the emoji images
public static final double GROUND = EmojiLauncher.GROUND;
public static final double GRAVITY = 0.25; // how much to reduce the speed each step.
// Fields to store state of the Emoji:
private double horizontalPos;
private double aboveGround;
private double hSpeed;
private double vSpeed;
private String name;
// Constructor
/**
* Constructor
*/
public Emoji(double x, double h, String name){
this.horizontalPos = x;
this.aboveGround = h;
this.name = "emojis/"+name;
}
// Methods
/**
* Draws an emoji
*/
public void draw(){
UI.drawImage(this.name, this.horizontalPos, this.aboveGround , SIZE, SIZE);
}
/**
* Makes emoji take a step
*/
public void step(){
if(this.vSpeed != 0 || this.hSpeed != 0){
this.horizontalPos += hSpeed;
this.aboveGround += vSpeed;
this.vSpeed += GRAVITY;
if(this.aboveGround > GROUND - SIZE){
vSpeed = 0;
hSpeed = 0;
this.aboveGround = GROUND - SIZE;
}
}
}
/**
*
* Returns the height of the emoji above the floor.
*/
public double getHeight(){
return this.aboveGround;
}
/**
*
*
* Returns the horizontal position
*/
public double getX(){
return this.horizontalPos;
}
/**
* Returns the speed of the emoji
*/
public double getSpeed(){
return Math.hypot(hSpeed, vSpeed);
}
/**
*
* Set the horizontal and vertical speed of emoji
*/
public void launch(double xSpeed, double ySpeed){
this.hSpeed = xSpeed;
this.vSpeed = ySpeed;
}
/**
* return true if emoji is touching other emoji
*/
public boolean touching(Emoji other){
if(this.horizontalPos >= other.horizontalPos || this.aboveGround >= other.aboveGround){
return true;
}
else {
return false;
}
}
/**
* if emojis hit each other, the hit emoji starts moving
*/
public void bump(Emoji other){
if((this.hSpeed > 0 || vSpeed > 0) &&
(this.horizontalPos >= other.horizontalPos && this.aboveGround >= other.aboveGround)){
other.hSpeed = 1;
}
}
/**
* Main method
*/
public static void main(String[] args){
do {
Emoji bike = new Emoji(110, 150, "bicycle.png");
bike.draw();
Emoji moon = new Emoji(50, 200, "moon.png");
moon.draw();
moon.launch(5, 0);
UI.println("moon launched");
for (int i=0; i<=100; i++){
bike.step();
moon.step();
UI.clearGraphics();
UI.drawLine(0, GROUND, 500, GROUND);
bike.draw();
moon.draw();
if(moon.touching(bike)&& moon.getSpeed()>0){
moon.bump(bike);
UI.println(i+": moon touched and then bumped bike");
}
if(moon.getX() > 55 && moon.getX()<65){
UI.println(i+": moon has moved to the right");
}
if (moon.getHeight()==0){
UI.println(i+": moon at ground");
}
if (bike.getHeight()==0){
UI.println(i+": bike at ground");
}
UI.sleep(100);
if (bike.getHeight()==0 && moon.getHeight()==0){
break;
}
}
} while (UI.askBoolean("test again?"));
}
// END OF DRAFT CODE
}
This is the emoji class
Needing help with the touching and bump methods so that the stand still emoji gets bumped more realistically and based on the speed of the emoji controlled.
this is what it looks like when run
the moon in the bottom left was my object that I shot at the angry target. They both need to stop on the ground.
I have a UI import which makes things much easier to make.
I am learning Java following class CS106A and am having issues that GCompound object is not interacting with mouse events.
I noticed the issue while doing programming exercises in "the Art and Science of Java" and couldn't figure out the reason. So i tried to copy the sample code of the book and tried to run it in eclipse, and they didn't work either.
Below is GFace class defined in the book that extends GCompound.
import acm.graphics.*;
public class GFace extends GCompound{
/** Constants specifying feature size as a fraction of the head size*/
private static final double EYE_WIDTH = 0.15;
private static final double EYE_HEIGHT = 0.15;
private static final double NOSE_WIDTH = 0.15;
private static final double NOSE_HEIGHT = 0.10;
private static final double MOUTH_WIDTH = 0.50;
private static final double MOUTH_HEIGHT = 0.03;
/** Construct a new GFace object with the specified dimensions. */
public GFace (double width, double height){
head = new GOval (width, height);
leftEye = new GOval (EYE_WIDTH * width, EYE_HEIGHT * height);
rightEye = new GOval (EYE_WIDTH * width, EYE_HEIGHT * height);
nose = createNose (NOSE_WIDTH * width, NOSE_HEIGHT * height);
mouth = new GRect(MOUTH_WIDTH * width, MOUTH_HEIGHT * height);
add(head, 0, 0);
add(leftEye, 0.25 * width - EYE_WIDTH * width / 2,
0.25 * height - EYE_HEIGHT * height / 2);
add(rightEye, 0.75 * width - EYE_WIDTH * width / 2,
0.25 * height - EYE_HEIGHT * height / 2);
add(nose, 0.50 * width, 0.50 * height);
add(mouth, 0.50 * width - MOUTH_WIDTH * width / 2,
0.75 * height - MOUTH_HEIGHT * height / 2);
}
/** creates a triangle for the nose*/
private GPolygon createNose(double width, double height){
GPolygon poly = new GPolygon();
poly.addVertex(0, -height/2);
poly.addVertex(width / 2, height / 2);
poly.addVertex(-width / 2, height / 2);
return poly;
}
/*instance variables*/
private GOval head;
private GOval leftEye, rightEye;
private GPolygon nose;
private GRect mouth;
}
and then below program is supposed to create a GFace object on Canvas so that user can drag it around with mouse. But, when i ran the program, the GFace object on canvas does not respond to my mouse, while GRect object can ne dragged on canvas. I've also added a rectangle to see if by clicking on the GFace, the program returns null, as suggested in the comment(thanks for the advice!), and it does. It just seems the GCompound object cannot be selected.
import acm.graphics.*;
import acm.program.*;
import java.awt.event.*;
import java.awt.*;
import acm.util.*;
public class DragFace extends GraphicsProgram{
/** Width of the face */
private static final double FACE_WIDTH = 200;
/** Height of the face */
private static final double FACE_HEIGHT = 300;
/** Runs the program */
public void run(){
/*added a filled rectangle to the screen.
* if no object selected and returns null,
* rectangle changes color randomly*/
add(temp);
temp.setFillColor(Color.RED);
temp.setFilled(true);
GFace face = new GFace(FACE_WIDTH, FACE_HEIGHT);
double x1 = (getWidth() - FACE_WIDTH) / 2;
double y1 = (getHeight() - FACE_HEIGHT) / 2;
add(face, x1, y1);
GObject rect = new GRect(FACE_WIDTH, FACE_HEIGHT);
double x = (getWidth() - FACE_WIDTH) / 2;
double y = (getHeight() - FACE_HEIGHT) / 2;
add(rect, x, y);
rect.setColor(Color.RED);
addMouseListeners();
}
/** called on mouse press to record the coordinates of the click */
public void mousePressed(MouseEvent e){
lastX = e.getX();
lastY = e.getY();
gobj = getElementAt(lastX, lastY);
/* if no object selected and returns null,
* rectangle changes color randomly each time */
if(gobj == null){
temp.setFillColor(rgen.nextColor());
}
}
/** called on mouse drag to reposition the object*/
public void mouseDragged(MouseEvent e){
if(gobj != null){
gobj.move(e.getX() - lastX, e.getY() - lastY);
lastX = e.getX();
lastY = e.getY();
}
}
/** called on mouse click to move this object to the front*/
public void mouseClicked(MouseEvent e){
if(gobj != null) gobj.sendToFront();
}
/*private state*/
private GObject gobj; /*the object being dragged*/
private double lastX; /*the last mouse X position*/
private double lastY; /*the last mouse Y position*/
private GRect temp = new GRect(0,0,100,100);/* private rectangle*/
private RandomGenerator rgen = new RandomGenerator();
}
MY question is
does GCompound object works as a unit like a GRect? If so, can can anyone point out the cause of the issue in the code above? I don't know if it's my software that's causing the issue, or if I am missing something with the use of GCompound class.
the Gface is supposed to be centered on Canvas, but somehow it shows up on the button right corner. The x- and y- coordinate of the Gface is always twice of the coordinate specified in the add call. Any idea how this might have happened?
Any help will be greatly appreciated.
I'm trying to understand these code:
/*
* File: BouncingBallWalls.java
* ---------------------
* This is exercise 15 in chapter 4 of "The Art and Science of Java."
* It requires me to write a program that makes an animated bouncing
* ball on the screen, bouncing off the window edges.
*/
import java.awt.*;
import acm.program.*;
import acm.graphics.*;
public class BouncingBallWalls extends GraphicsProgram {
public void run() {
GOval ball = new GOval (getWidth()/2 - BALL_SIZE/2, getHeight()/2 - BALL_SIZE, BALL_SIZE, BALL_SIZE); /* Centers the ball */
ball.setFilled(true);
ball.setFillColor(Color.BLUE);
ball.setColor(Color.BLUE);
add(ball);
double dx = (getWidth()/N_STEPS);
double dy = (getWidth()/N_STEPS);
while(true) {
ball.move(dx, dy); /* Movement for the ball */
pause(PAUSE_TIME);
if (ball.getY() > getHeight() - BALL_SIZE) { /* Each "if" statement reverses the direction of the ball on one */
dy = dy * -1; /* axis if it hits a boundry */
}
if(ball.getX() > getWidth()- BALL_SIZE) {
dx = dx * -1;
}
if(ball.getY() < 0) {
dy = dy * -1;
}
if(ball.getX() < 0) {
dx = dx * -1;
}
}
}
private static final double N_STEPS = 1000;
private static final double PAUSE_TIME = 2;
private static final double BALL_SIZE = 50.0;
}
I understand everything except the following, why do you divide your gameWidth by N_STEPS? and what is N_STEPS?
double dx = (getWidth()/N_STEPS);
double dy = (getWidth()/N_STEPS);
private static final double N_STEPS = 1000;
Reference: http://tenasclu.blogspot.co.uk/2012/12/first-few-days-of-learning-to-program.html
You divide screen size by N_STEPS to get dx and dy, which represent the distance you want the ball to move during each loop. N_STEPS defines the movement in terms of the available screen width so that the relative movement/speed is the same regardless of screen size.
Another way of looking at N_STEPS, is that it controls the smoothness and speed of the ball. It does so in a way that makes the smoothness and speed consistent regardless of screen size. A higher N_STEPS will result in smoother/slower ball movement per loop.
Note that your code:
double dx = (getWidth()/N_STEPS);
double dy = (getWidth()/N_STEPS);
Should probably:
double dx = (getWidth()/N_STEPS);
double dy = (getHeight()/N_STEPS);
Basically what the tuorial is demonstrating is animating the motion of the ball. Now in each iteration of the while loop the ball has to move a certain distance in x and a certain distance in y. This incremental change is denoted as dx and dy.
To calculate how much the ball should move in each increment, the total distance the ball should move is divided by the number of iterations. This is to create the sensation of smooth movement. If the number of steps was too low and the total distance needed to travel was too high, then the ball would jump from one spot to the next.
N-STEPS is the distance in pixels/unit on screen. Different devices have different sizes. Say you have a device that has a screen of 800 pixels in width. Regardless of the device size, you may want to make an imaginary grid. Say if we divide the size by 20, we get 40 (800/20=40). This gives us 40 pixels or 1 unit. So, if we move something, we can move 40 pixels or 1 unit at a time horizontally. This helps when dealing with different screen sizes.
i am trying to figure out how Java know where to start according to this Graphics code when i run this code it showing ball moving from top to down but i can't understand why from top and why from this place and i know that java use math.random() to set the value but how it set the x and y
while when i trying to put any random number by my self it gives number that is bigger than the width it self (i am taking exactly about pos.x and pos.y)
this the first class
package movingball;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
/**
*
* #author isslam
*/
public class Ball {
private final int RADIUS = 10;
private final Point pos;
private final Color ballColor = Color.red;
private final int CHANGE = 3;
private final int height,
width;
public Ball(int frameWidth, int frameHight) {
width = frameWidth;
hight = frameHeight;
pos = new Point();
pos.x = (int)(Math.random() * (width - RADIUS)) + RADIUS;
pos.y = (int)(Math.random() * (height / 2 - RADIUS)) + RADIUS;
}
public void paint(Graphics g) {
g.setColor(ballColor);
g.fillOval(pos.x - RADIUS, pos.y - RADIUS, 2 * RADIUS, 2 * RADIUS);
}
public void move() {
if (pos.y < height - RADIUS) {
pos.translate(0, CHANGE);
}
}
}
this is the second class
package movingball;
import java.awt. * ;
import javax.swing. * ;
/**
*
* #author isslam
*/
public class ClassOfMoving extends JFrame {
protected final int FRAME_WIDTH = 240;
protected final int FRAME_HIGHT = 320;
private final Ball myBall = new Ball(FRAME_WIDTH, FRAME_HEIGHT);
public ClassOfMoving(String title) {
super(title);
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setDefaultCloseOperation(ClassOfMoving.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
myBall.paint(g);
}
public void move() {
while (true) {
myBall.move();
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
System.exit(0);
}
}
}
}
the main class
package movingball;
/**
*
* #author isslam
*/
public class MovingBall {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
ClassOfMoving is = new ClassOfMoving("isslam");
is.setVisible(true);
is.move();
}
I'm not entirely sure what the problem is, You seem a bit confused.
This line does the actual moving.
pos.translate(0, CHANGE);
The Ball position pos is translated with CHANGE pixels in the y-dimension. CHANGE is defined as 3 somewhere else. Top-Left position is normally (0,0) on a computer screen, so the pos.y will increase with 3 and the Ball will move downwards by three pixels*.
Math.random() returns a number between 0 and 1. The following line positions the ball on a random position between 0+r and width-r.
pos.x = (int)(Math.random() * (width - RADIUS)) + RADIUS;
If you want to specify a specific position, set pos.x directly instead of replacing Math.random().
The y-position is defined as the top half half of the window because the max value is defined as height/2.
pos.y = (int)(Math.random() * (height / 2- RADIUS)) + RADIUS;
*:The coordinate system of a computer display is flipped upside down compared to the conventional coordinate system where positive is up. The reason is perhaps to be found in how old cathode ray tubes paints (from top left) and also how line numbers increase downwards on line printers, and also later in character based display systems.
Independently these two classes when compiled and executed in an app won't do anything as it doesnt have either main method or static block. but if you are using it in conjuction with any framework , jars or any additional code, that might be helping execute it by means of creating their objects. Hope it answers.
I'm making a game where the player will (on release of mouseclick) shoot a "star" in a certain direction at an initial speed determined by how far he dragged the mouse before releasing. I have a "planet" (stationary circle) on the canvas that I want to exert a gravitational pull on the moving planet. I believe I'm using the right formulas for gravitational force and such, and I have it partially working - the planet affects the planet's trajectory up until a certain point, when the star seems to endlessly speed up and stop changing direction based on it's angle to the star. Any advice? (I know that stars aren't supposed to orbit planets, it's the other way around. I coded the whole thing with the names interchanged so forgive that).
main class:
import acm.graphics.GCompound;
import acm.graphics.GImage;
import acm.graphics.GLabel;
import acm.graphics.GLine;
import acm.graphics.GMath;
import acm.graphics.GObject;
import acm.graphics.GPen;
import acm.graphics.GPoint;
import acm.graphics.GRect;
import acm.graphics.GOval;
import acm.graphics.GRectangle;
import acm.program.GraphicsProgram;
import acm.util.RandomGenerator;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.util.*;
public class Space extends GraphicsProgram {
public static int APPLICATION_WIDTH = 1000;
public static int APPLICATION_HEIGHT = 1000;
private int size = 15;
public static double pMass = 1000;
public static int sMass = 20;
public static double G = 200;
private RandomGenerator rand = new RandomGenerator();
GOval planet, tempstar;
shootingStar star;
GLine line;
double accel, xAccel, yAccel, xspeed, yspeed, angle;
public void init(){
planet = new GOval(APPLICATION_WIDTH/2, APPLICATION_HEIGHT/2, 30, 30);
planet.setFilled(true);
planet.setFillColor(rand.nextColor());
add(planet);
}
public void mousePressed(GPoint point) {
// draw a line
tempstar = new GOval(point.getX() - size/2, point.getY() - size/2, size, size);
tempstar.setFilled(true);
tempstar.setColor(rand.nextColor());
add(tempstar);
line = new GLine(tempstar.getX() + size/2, tempstar.getY() + size/2,
point.getX(), point.getY());
add(line);
line.setVisible(true);
}
public void mouseDragged(GPoint point) {
line.setEndPoint(point.getX(), point.getY());
}
public void mouseReleased(GPoint point){
xspeed =
-.05*GMath.cosDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(),
line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
yspeed =
.05*GMath.sinDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(),
line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
System.out.println(xspeed + " " + yspeed);
star = new shootingStar(xspeed, yspeed, this);
if(xspeed != 0)
add(star, tempstar.getX(), tempstar.getY());
new Thread(star).start();
remove(tempstar);
remove(line);
}
private double getAngle(GLine line) {
return GMath.angle(line.getStartPoint().getX(), line.getStartPoint().getY(),
line.getEndPoint().getX(), line.getEndPoint().getY());
}
public void checkPlanet(){
accel = .06*GMath.distance(star.getX(), star.getY(), planet.getX(),
planet.getY());
angle = correctedAngle(GMath.angle(planet.getX(), planet.getY(), star.getX(),
star.getY()));
xAccel = accel*GMath.cosDegrees(GMath.angle(planet.getX(), planet.getY(),
star.getX(), star.getY()));
yAccel = accel*GMath.sinDegrees(GMath.angle(planet.getX(), planet.getY(),
star.getX(), star.getY()));
double newX = xspeed - xAccel*.01;
double newY = yspeed + yAccel*.01;
xspeed = newX + xAccel*Math.pow(.01, 2)/2;
yspeed = newY + yAccel*Math.pow(.01, 2)/2;
star.setSpeed(xspeed, yspeed);
}
public double correctedAngle(double x) {
return (x%360.0+360.0+180.0)%360.0-180.0;
}
}
Pertinent parts of shootingStar class:
public void run() {
// move the ball by a small interval
while (alive) {
oneTimeStep();
}
}
// a helper method, move the ball in each time step
private void oneTimeStep() {
game1.checkPlanet();
shootingStar.move(xSpeed, ySpeed);
pause(20);
}
public void setSpeed (double xspeed, double yspeed){
xSpeed = xspeed;;
ySpeed = yspeed;
}
}
EDIT:
Current Main Class Method:
public void checkPlanet(){
double xDistance = star.getX() - planet.getX();
double yDistance = star.getY() - planet.getY();
double distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
accel = G*pMass/Math.pow(distance, 2);
xAccel = accel * xDistance/distance;
yAccel = accel * yDistance/distance;
xspeed += xAccel;
yspeed += yAccel;
star.setSpeed(xspeed, yspeed);
}
Current Star class Method:
public void run() {
while (alive) {
oneTimeStep();
}
}
private void oneTimeStep() {
game1.checkPlanet();
shootingStar.move(xSpeed, ySpeed);
pause(20);
}
public void setSpeed (double xspeed, double yspeed){
xSpeed = xspeed;;
ySpeed = yspeed;
}
}
Wow, that's a lot more effort than what you "HAVE" to do.
If the thing is on the board calculate it's distance from the object. If it's farther away than D do nothing. If it's D away then it's within the objects gravitational pull. Just add a small amount of velocity to it pointing at the object. Let's say it was 1000 X away and 500 z away. Just do something simple like divide by 100, and add that to the objects velocity so it moves 10 x and 5 y towards the object. Each time you update add the velocity again.
You'll probably want a maximum velocity also. This is a LOT easier to calculate works well, and will give you effects like in the game STAR CONTROL where there's a planet, or the ships gravitationally pull towards each other a tiny bit. I did this with 10 planets and a star, and the user could basically do lunar lander with each planet. It was a blast but I never turned it into a real game. This has the advantage of being rockingly fast to calculate. There some edge conditions like if you make the map a torus so they warp through the sides of the map, but basically it's all just simple addition and subtraction.
It's GOOD enough for a game. You're not making a simulator. You're making a game.
I am not sure, but try to change the part where you calculate the xAccel and yAccel values to something like this.
xDistance = XComponentObject1 - XComponentObject2;
yDistance = YComponentObject1 - YComponentObject2;
(xDistance and yDistance can have negative values)
Distance = sqrt( xDistance^2 + yDistance^2 );
gConstant = constant Value for gravitational strenght in your world;
MassObject1 = some Mass;
MassObject2 = some other Mass;
Accel = gConstant*MassObject1*MassObject2 / (Distance^2 );
''NOW COMES THE IMPORTANT PART''
xAccel = Accel * xDistance/Distance;
yAccel = Accel * yDistance/Distance;
I think your whole yadayada with sine and cosine creates a whole bunch of hard-to-trackdown-errors.