Hello All,
I was wondering if I could get some help here. This is an applet to teach basic sailing skills (reading the wind, adjusting the boat direction and sails, etc.) You steer the boat by using the left and right arrow keys. But note, like driving a boat with a tiller, you push left to turn right and you push right to turn left. Right now, you can speed up and slow down by using the up and down arrow keys. I've ordered a book, "This physics of sailing" to help program how the sails work.
I have a blue JPanel with a proposed path of white dots on it. It has little black lines moving around which represent boats. Notice that when they turn they rotate around their bow - like a real boat when it turns. (I want to move the center (the boats location) to where the mast would be - about a third of the length behind the bow.)
What I need help with is using shapes to make the boat shape. (it might be easier to do without Shapes.) I think it is some combination of GeneralPath and the Shape interface. You can't extend GeneralPath and if I use Shape, I still need some kind of base object.
Some issues:
1) If I want to use AffineTransform, can I change the direction before drawing each boat?
2) Do I have to draw each boat in a buffer with a new AffineTransform and copy them to the JPanel using transparency to have the background dropout? (And turn off antialiasing until the copy.)
3) Shape wise, it should have one or two arcs for the bow and some lines or a rectangle for the stern. I'd like it to have a white fill with a black outline.
4) The rudder and sails are sub shapes - how do I do that?
5) To use the keys, I needed to set the focus, it doesn't work automatically - you still have to click on the JPanel to set the focus. Can someone tell me how to fix this?
6) Currently moveold() and drawold() are active so you can see how it works.
7) It has a main() so you can run it from NetBeans IDE.
8) Thanks in advance for any help.
Here is the Sailboat class
CODE
//Sailboat.java
package ruffner.peter.Sailboat;
//import java.awt.Rectangle;
import java.awt.Graphics2D;
import java.awt.geom.Arc2D;
import java.awt.geom.GeneralPath;
import java.awt.Color;
import java.awt.Graphics.*;
import java.awt.Shape;
import java.awt.Dimension;
//import java.awt.geom.GeneralPath;
//Arc2D.Double(double x, double y, double w, double h, double start, double extent, int type)
//public class Sailboat extends GeneralPath implements Shape {
public class Sailboat extends Object {
protected int x, x2;
protected int y, y2;
int length;
int width;
int panelWidth;
int panelHeight;
Dimension d;
double course;
double rudder = 0;
double speed;
double max_speed;
Boolean splitH = false;
Boolean splitV = false;
Arc2D myshape;
//only constructor used
public Sailboat(Dimension nd) {
d = nd; //edges of panel
x = (int)(Math.random() * d.width);
y = (int)(Math.random() * d.height);
panelWidth = nd.width;
panelHeight = nd.height;
length = 14;
width = 4;
course = (Math.random() * 360f);
speed = (Math.random() * 5f);
max_speed = 5;
}
//this constructor not used
public Sailboat(int nx, int ny, double ncourse, Dimension nd) {
//x = nx;
//y = ny;
x = (int)(Math.random() * 24);
y = (int)(Math.random() * 120);
length = 14;
width = 4;
course = ncourse;
d = nd;
panelWidth = nd.width;
panelHeight = nd.height - 30;
speed = 2;
max_speed = 5;
}
//this constructor not used
public Sailboat(int nx, int ny, int nl, int nw, double nc, double ns, double nms, Dimension nd) {
x = nx;
y = ny;
length = nl;
width = nw;
course = nc;
d = nd;
panelWidth = nd.width;
panelHeight = nd.height;
speed = ns;
max_speed = nms;
}
//public void moveTo(int nx, int ny){
// x = nx;
// y = ny;
//}
public void turnRight(){
rudder = addDegree(rudder, 2);
if (rudder > 45){
rudder = 45;
}
//System.out.println("x=" + x + "/y=" + y + "/course=" + course + "/rudder=" + rudder + "/speed=" + speed);
}
public void turnLeft(){
rudder = addDegree(rudder, -2);
if (rudder < -45){
rudder = -45;
}
//System.out.println("x=" + x + "/y=" + y + "/course=" + course + "/rudder=" + rudder + "/speed=" + speed);
}
public void incSpeed(){
speed = (int)speed + 1;
//System.out.println("x=" + x + "/y=" + y + "/course=" + course + "/rudder=" + rudder + "/speed=" + speed);
}
public void decSpeed(){
speed = (int)speed - 1;
//System.out.println("x=" + x + "/y=" + y + "/course=" + course + "/rudder=" + rudder + "/speed=" + speed);
}
//use sin, cos to get next ccordinate pair
public void moveold() {
course -= rudder;
//find the front of the boat
x = x + (int)(Math.sin(Math.toRadians(course)) * speed);
y = y + (int)(Math.cos(Math.toRadians(course)) * speed);
//find the back of the boat
x2 = (x + (int)(Math.sin(Math.toRadians(addDegree(course + rudder, 180d))) * (length + 3)));
y2 = (y + (int)(Math.cos(Math.toRadians(addDegree(course + rudder, 180d))) * (length + 3)));
//horizontal split
//right side
if (x > panelWidth || x2 > panelWidth) { //part is off right side
if (x > panelWidth && x2 > panelWidth){ //all is off right side
x = x - panelWidth; //reset position to left side of panel
splitH = false;
}else{ //back is off right side of panel
splitH = true; //boat straddels H - draw two boats
}
}
//left side
if (x < 0 || x2 < 0){ //part is off left side
if (x < 0 && x2 < 0){ //all is off left side
x = x + panelWidth; //reset position to right side of panel
splitH = false;
//System.out.println("reseting location to x=" + x + "/y=" + y + "/width=" + panelWidth);
}else{ //back is off left side of panel
splitH = true; //boat straddels H - draw two boats
}
}
//vertical split
//bottom
if (y > panelHeight || y2 > panelHeight) { //part is off right side
if (y > panelHeight && y2 > panelHeight){//all is not off right side
y = y - panelHeight; //reset position to left side of panel
splitV = false;
}else{ //back is off right side of panel
splitV = true; //boat straddels H - draw two boats
}
}
//top
if (y < 0 || y2 < 0){ //front is off left side
if (y < 0 && y2 < 0){ //all is not off left side
y = y + panelHeight; //reset position to right side of panel
splitV = false;
}else{ //back is off left side of panel
splitV = true; //boat straddels H - draw two boats
}
}
}
//use sin, cos to get next ccordinate pair
public void move() {
course = addDegree(course, rudder);
//find the front of the boat
//location plus 1/3 length
//location minus 2/3 length
/*
//check for wrap-around on screen
//horizontal split
//right side
if (x > panelWidth || x2 > panelWidth) { //part is off right side
if (x > panelWidth && x2 > panelWidth){ //all is off right side
x = x - panelWidth; //reset position to left side of panel
splitH = false;
}else{ //back is off right side of panel
splitH = true; //boat straddels H - draw two boats
}
}
//left side
if (x < 0 || x2 < 0){ //part is off left side
if (x < 0 && x2 < 0){ //all is off left side
x = x + panelWidth; //reset position to right side of panel
splitH = false;
//System.out.println("reseting location to x=" + x + "/y=" + y + "/width=" + panelWidth);
}else{ //back is off left side of panel
splitH = true; //boat straddels H - draw two boats
}
}
//vertical split
//bottom
if (y > panelHeight || y2 > panelHeight) { //part is off right side
if (y > panelHeight && y2 > panelHeight){//all is not off right side
y = y - panelHeight; //reset position to left side of panel
splitV = false;
}else{ //back is off right side of panel
splitV = true; //boat straddels H - draw two boats
}
}
//top
if (y < 0 || y2 < 0){ //front is off left side
if (y < 0 && y2 < 0){ //all is not off left side
y = y + panelHeight; //reset position to right side of panel
splitV = false;
}else{ //back is off left side of panel
splitV = true; //boat straddels H - draw two boats
}
}
*/
}
public void draw() {
}
public void draw(Graphics2D g2) {
int x1;
int y1;
//int x2;
//int y2;
int a1;
int b1;
int a2;
int b2;
//aft is course - 180 degrees
//draw hull
//draw rudder - start at the end of the boat and go 5 pixcels
/*
if (splitH || splitV){
a1 = x;
b1 = y;
if (splitH){ //split H
//split H
if (x > panelWidth) { //right
a1 = x - panelWidth;
}else { //left
a1 = x + panelWidth;
}
}
if (splitV){ //split V
//split v
if (y > panelHeight) { //bottom
b1 = y - panelHeight;
}else { //top
b1 = y + panelHeight;
}
}
g2.setColor(Color.red);
g2.drawLine(a1, b1, a2, b2);
g2.drawLine(a1, b1, a2, b2);
}
*/
}
//old version of draw backed up
public void drawold(Graphics2D g2) {
int x1;
int y1;
//int x2;
//int y2;
int a1;
int b1;
int a2;
int b2;
//aft is course - 180 degrees
g2.setColor(Color.black);
//draw hull
x1 = (x + (int)(Math.sin(Math.toRadians(addDegree(course, 180d))) * length));
y1 = (y + (int)(Math.cos(Math.toRadians(addDegree(course, 180d))) * length));
//x2 =;
//y2 =;
g2.drawLine(x, y, x1, y1);
//draw rudder - start at the end of the boat and go 5 pixcels
//x1 = (x + (int)(Math.sin(Math.toRadians(addDegree(course, 180d))) * (length + 2)));
//y1 = (y + (int)(Math.cos(Math.toRadians(addDegree(course, 180d))) * (length + 2)));
x2 = (x1 + (int)(Math.sin(Math.toRadians(addDegree(addDegree(course, rudder), 180d))) * (0 + 5)));
y2 = (y1 + (int)(Math.cos(Math.toRadians(addDegree(addDegree(course, rudder), 180d))) * (0 + 5)));
g2.drawLine(x1, y1, x2, y2);
if (splitH || splitV){
a1 = x;
b1 = y;
if (splitH){ //split H
//split H
if (x > panelWidth) { //right
a1 = x - panelWidth;
}else { //left
a1 = x + panelWidth;
}
}
if (splitV){ //split V
//split v
if (y > panelHeight) { //bottom
b1 = y - panelHeight;
}else { //top
b1 = y + panelHeight;
}
}
g2.setColor(Color.red);
a2 = (a1 + (int)(Math.sin(Math.toRadians(addDegree(course, 180d))) * length));
b2 = (b1 + (int)(Math.cos(Math.toRadians(addDegree(course, 180d))) * length));
g2.drawLine(a1, b1, a2, b2);
//a1 = (x2 + (int)(Math.sin(Math.toRadians(addDegree(course, 180d))) * (length + 2)));
//b1 = (y2 + (int)(Math.cos(Math.toRadians(addDegree(course, 180d))) * (length + 2)));
a2 = (a1 + (int)(Math.sin(Math.toRadians(addDegree(addDegree(course, rudder), 180d))) * (0 + 5)));
b2 = (b1 + (int)(Math.cos(Math.toRadians(addDegree(addDegree(course, rudder), 180d))) * (0 + 5)));
g2.drawLine(a1, b1, a2, b2);
}
}
public double addDegree(double a, double b) {
return((a + b) % 360d);
}
@Override
public String toString(){
String s = "x=" + x + "/y=" + y + "/course=" + course + "/rudder=" + rudder;
return (s);
}
}
The Sailing class doesn't seem to fit here so it is included in a zip file.
This post has been edited by peter.ruffner: 25 May, 2008 - 11:30 PM