import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.MouseEvent;
import java.awt.image.*;
public class AutoAiming extends Applet implements MouseMotionListener{
public Vector3D mouse; //position of the mouse
public BufferedImage backBuffer;
private static class Ball{
private Vector3D x,v; //position, velocity
private double r; //radius
private double m; //mass
private double e; //elasticity
private double f; //friction
private Color color;
public Ball(Vector3D _x, Vector3D _v, double _r, double _m, double _e, double _f, Color _color){
x=_x; v=_v; r=_r; m=_m; f=_f; e=_e; color=_color;
}
public void move(double dt, Rectangle rect, Vector3D center){
/*COLLISION
//check collision with bound-rectangle
if(x.x<r){
x.x=r; v.x=-v.x;
}else if(x.x>rect.width-r){
x.x=rect.width-r; v.x=-v.x;
}else if(x.y<r){
x.y=r; v.y=-v.y;
}else if(x.y>rect.height-r){
x.y=rect.height-r; v.y=-v.y;
}//*/
//*Teleport
//AUTOAIMING: only big balls "respawn"
if(m>1){
if(x.x<-r){
x.x=rect.width+r;
}else if(x.x>rect.width+r){
x.x=-r;
}else if(x.y<-r){
x.y=rect.height+r;
}else if(x.y>rect.height+r){
x.y=-r;
}
}//*/
//move
Vector3D a=new Vector3D(v.mul(-f));
v=v.add(a.mul(dt));
x=x.add(v.mul(dt));
}
public void collision(Ball b){
//check if the balls collide
Vector3D connection=x.sub(b.x);
double distSq=connection.getSqLength();
double radiusSumSq=(r+b.r); radiusSumSq*=radiusSumSq;
if(distSq<radiusSumSq){
//TOUCH
//normalize the vector connecting the middle points of the two balls
connection=connection.normalize();
//now calculate all the components parallel to the connection
double this_parallel=v.dot(connection);
double b_parallel=b.v.dot(connection);
//check if the balls are moving towards each other
if(this_parallel-b_parallel<0){
//COLLISION
//ortho-components of the velocities do not change
Vector3D this_ortho=v.sub(connection.mul(this_parallel));
Vector3D b_ortho=b.v.sub(connection.mul(b_parallel));
//now some physics are required to calculate new parallel components
//it is the velocity of the b-ball after the collision:
double temp=(2*m*this_parallel+(b.m-m)*b_parallel)/(m+b.m)*b.e;
//and this is the new velocity of "this":
this_parallel=(2*b.m*b_parallel+(m-b.m)*this_parallel)/(m+b.m)*e;
//copying temp into b_parallel: not necessary but better for the reader
b_parallel=temp;
//combine all components to new velocities again
v=connection.mul(this_parallel).add(this_ortho);
b.v=connection.mul(b_parallel).add(b_ortho);
}
}
}
public void draw(Graphics g){
g.setColor(color);
g.fillOval((int)(x.x-r),(int)(x.y-r), (int)(2*r), (int)(2*r));
}
}
private static class BallMotionThread extends Thread{
private AutoAiming component;
private Graphics imageGraphics;
private Rectangle bounds;
private long timer;
private Ball[] balls;
private final static int SHOTS=80;
public BallMotionThread(AutoAiming c, Rectangle rect){
component=c;
bounds=rect;
imageGraphics=c.backBuffer.getGraphics();
//the "shots"
balls=new Ball[SHOTS+2];
for(int i=0; i<balls.length; i++){
balls[i]=new Ball(new Vector3D(20+i*7,900,0),
new Vector3D(0,0,0),
3, 0.0001, 1, 0, Color.BLACK);
}
//the "victim"
balls[0]=new Ball(new Vector3D(20,20,0),
new Vector3D(0.1,0.07,0),
15, 100,1,0,Color.RED);
//the "canon"
balls[1]=new Ball(new Vector3D(50,550,0),
new Vector3D(0,0,0),
15, 500,1,0,Color.GREEN);
}
public void run(){
long elapsedTime;
timer=System.currentTimeMillis();
long timeSinceLastShot=0;
int lastShotIndex=2;
while(true){
elapsedTime=-timer+(timer=System.currentTimeMillis());
timeSinceLastShot+=elapsedTime;
//cls
imageGraphics.setColor(Color.WHITE);
imageGraphics.fillRect(bounds.x,bounds.y,bounds.width,bounds.height);
for(int i=0; i<balls.length; i++){
for(int j=i+1; j<balls.length; j++){
balls[i].collision(balls[j]);
}
balls[i].move(elapsedTime, bounds, component.mouse);
balls[i].draw(imageGraphics);
}
//AUTOAIMING
double shotVelocity=0.17;
Ball victim=balls[0];
Ball cannon=balls[1];
if(timeSinceLastShot>60){
//bureaucracy
timeSinceLastShot=0;
lastShotIndex++;
lastShotIndex=(lastShotIndex>=2+SHOTS)?(2):(lastShotIndex);
//shoot
Vector3D connection=victim.x.sub(cannon.x); //connection vector cannon-victim
Vector3D ortho=Vector3D.eZ.cross(connection); //orthogonal to the connection Vector
ortho.z=0; //just to make sure that everything is still on the 2D-plane...
double connectionLength=connection.getLength();
double f_ortho=victim.v.dot(ortho)/(shotVelocity*connectionLength);
double f_parallel=Math.sqrt(1-f_ortho*f_ortho); //normalized direction-vector component-factors
Vector3D shotVelocityVector=ortho.mul(shotVelocity*f_ortho/connectionLength).
add(connection.mul(shotVelocity*f_parallel/connectionLength));
balls[lastShotIndex].x=cannon.x.add(shotVelocityVector.normalize().mul(victim.r*0.9));
balls[lastShotIndex].v=shotVelocityVector;
}
// AUTOAIMING-END
component.getGraphics().drawImage(
component.backBuffer,0,0,component.getWidth(),component.getHeight(),component);
try{
sleep(1);
}catch(InterruptedException e){}
}
}
}
//member vars
BallMotionThread thread;
public void init(){
backBuffer=new BufferedImage(this.getWidth(),this.getHeight(),BufferedImage.TYPE_INT_RGB);
mouse=new Vector3D(0,0,0);
addMouseMotionListener(this);
thread=new BallMotionThread(this, this.getBounds());
thread.start();
}
public void mouseMoved(MouseEvent e){
mouse.x=e.getX();
mouse.y=e.getY();
}
public void mouseDragged(MouseEvent e){}
public void destroyed(){}
}