Game character movement
Hi,
I've got a system were I have constants for each of the compose points, and using a switch on that direction:
For example, if north - speed from y, is east + x, and so on.
This seems to work well, but I've always wanted to use degrees for the direction, rather then constants.
I've made a little image to show what I'm after, for some reason my browser was being redirected when trying to view it, so I've made a little html to display it and can be found here: http://acquiesce.awardspace.co.uk/temp/viewImg.html
In actual fact, the example i have there would be the equivalent of north-east in my current system.
I've also put what I've done so far, http://acquiesce.awardspace.co.uk/temp/MovementTester.java, the sheep.png is on the viewImg, just save as target.
I had this idea of having an up vector (Line2D), this vector could then be rotated by the characters direction to get a new line, then, say speed was 10, 10 units up this line would be the new position for the character.
Does that make sense to people?
I guess the only thing left to do is get the new pos that's 10 (or whatever speed is) units up the direction line, but I have no idea, how to do this.
Can anyone add any thoughts? I remember doing something like this before, so I'll see what I can think of.
Thanks,
Luke
[1381 byte] By [
dfgstga] at [2007-11-15]

Just thought, what I need to to get a sub-line, that is a, say, 10 units in length.
Just thinking, doesn't help much tho :?
after doing a bit of research on the topic, i've updated the image now, it's turning into a bit of a math issue rather then a java thing, sorry about that :(
I'll try some of the maths boffs, and shall post what i find out here :)
I do make my life needlessly complicated at times.
All i needed to do was change the length of the up line, so what was all this talk about circles and points on a circumference? I don't know... Anyway, here;s what I've ended up with, the sprite (sheep) follows the mouse around when moved:
import java.io.File;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.JFrame;
import javax.imageio.*;
public class MovementTester extends JFrame implements
MouseMotionListener,MouseWheelListener
{
public static void main(String[] args) {new MovementTester();}
// The point were the sheep is to be drawn
private Point2D pos=null;
// The sheep direction (in degrees)
private double dir=45;
// The speed the sheep is to move
private double speed=10;
// Face the direction
private boolean faceDir=true;
// The centre of the sheep
private Point2D sheepCentre=null;
// The sheep
private BufferedImage sheep=null;
// The up vector
private Point2D up=null;
// The centre of the frame
private Point2D centre=null;
public MovementTester()
{
this.setSize(800,600);
// Setup the sheep
setupSheep();
// Set the centre
centre=new Point2D.Double(this.getWidth()/2,this.getHeight()/2);
// Add the mouse thingys
this.addMouseMotionListener(this);
this.addMouseWheelListener(this);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
private void setupSheep()
{
try {
sheep=ImageIO.read(new File("tester\\Images\\sheep.png"));
} catch (Exception ex) {ex.printStackTrace();}
// Draw in the middle
double x=(this.getWidth()/2)-(sheep.getWidth()/2);
double y=(this.getHeight()/2)-(sheep.getHeight()/2);
pos=new Point2D.Double(x,y);
}
public void paint(Graphics g)
{
//super.paint(g);
// The buffer
BufferedImage buff=new BufferedImage(this.getWidth(),this.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR_PRE);
// Get the buff g
Graphics2D buffG=(Graphics2D)buff.getGraphics();
if (isOpaque()) { //paint background
buffG.setColor(getBackground());
buffG.fillRect(0, 0, getWidth(), getHeight());
}
// The up vector (sheep x and y - speed)
up=new Point2D.Double(pos.getX(),pos.getY()-speed);
// The up line from sheep to up
Line2D upLine=new Line2D.Double(pos,up);
// The direction line
Line2D dirLine=null;
// Draw the up line in blue
buffG.setPaint(Color.blue);
buffG.draw(upLine);
// Roate the up line
AffineTransform alf=AffineTransform.getRotateInstance(
Math.toRadians(dir),upLine.getX1(),upLine.getY1()
);
// Get the transformed shaoe as a line
dirLine=toLine(alf.createTransformedShape(upLine));
// Draw the direction line in red
buffG.setPaint(Color.red);
buffG.draw(dirLine);
// Move to end of the dir line
pos=new Point2D.Double(dirLine.getX2(),dirLine.getY2());
// The centre of the sheep
sheepCentre=new Point2D.Double(pos.getX()+(sheep.getWidth()/2),
pos.getY()+(sheep.getHeight()/2));
// If face dir
if (faceDir)
{
// Rotate to dir
//sheep=rotate(sheep,dir,pos.getX(),pos.getY(),null);
}
// Draw the sheep
buffG.drawImage(sheep,(int)pos.getX(),(int)pos.getY(),null);
// Draw the buff
g.drawImage(buff,0,0,null);
}
public void mouseMoved(MouseEvent e)
{
// Get the mouse x,y
double mX=e.getPoint().getX();
double mY=e.getPoint().getY();
// Make a point at the top middle of the frame
Point2D top=new Point2D.Double(centre.getX(),0);
// The dist of top to centre (side a)
double sideA=Point.distance(top.getX(),top.getY(),
centre.getX(),centre.getY());
// The dist pf centre to mouse point (side b)
double sideB=Point.distance(centre.getX(),centre.getY(),
mX,mY);
// Between mouse and top (side c)
double sideC=Point.distance(mX,mY,top.getX(),top.getY());
// We wanna find the angle abound the centre
// So the cos of angleCen
double cosCen=((sideA*sideA)+(sideB*sideB)-(sideC*sideC))/(
2*(sideA*sideB));
// Arc cos to get angle
dir=Math.toDegrees(Math.acos(cosCen));
// If mouse is on left side of centre
if (mX<centre.getX())
{
// - from 360 to get the reverse angle
dir=360-dir;
}
// Repaint
repaint();
}
public void mouseDragged(MouseEvent e) {}
public void mouseWheelMoved(MouseWheelEvent e)
{
// If up (away)
if (e.getWheelRotation()><0)
{
// More speed
speed=speed+4;
}
else {speed=speed-4;}
}
public static BufferedImage rotate(BufferedImage in,double angle,
double x,double y,RenderingHints rh)
{
//
AffineTransform aff = AffineTransform.getRotateInstance(angle,x,y);
// The transform op
AffineTransformOp op = new AffineTransformOp(aff,rh);
// Return the rotated bufferedImage
return op.filter(in,null);
}
public static Line2D toLine(Shape s)
{
return toLine(s.getPathIterator(null));
}
public static Line2D toLine(PathIterator path)
{
// The line
Line2D line=null;
// The start of the line
Point2D start=null;
// The end of the line
Point2D end=null;
// Two points (x1,y1,x2,y2)
double[] points=new double[2];
// Get the first segment, should be move to and the stat of the line
path.currentSegment(points);
// Make the start point
start=new Point2D.Double(points[0],points[1]);
// Move to the next segment
path.next();
// Get the next segment, line to and the end point
path.currentSegment(points);
// Make the end point
end=new Point2D.Double(points[0],points[1]);
// Make the line
line=new Line2D.Double(start,end);
// Return the line
return line;
}
}
I thought it would be cool if the image rotated to face the direction it's moving in, but when I tried that using the AffineTransformOp I got a RasterFormatException.
I've had problems with op's and image loaded using the ImageIO.read() before, but they work fine loaded from the JPEGDecoder ?
Guess I'll have to make a PNGDecoder next :|
Anyway, I'm happy for the time being watching my sheep dance about. :D
Luke
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.io.File;
import javax.imageio.*;
import javax.swing.JFrame;
public class MT extends JFrame implements MouseMotionListener,MouseWheelListener
{
public static void main(String[] args) {new MT();}
// The point were the sheep is to be drawn
private Point2D pos=null;
// The sheep direction (in degrees)
private double dir=45;
// The speed the sheep is to move
private double speed=10;
// Face the direction
private boolean faceDir=true;
// The centre of the sheep
private Point2D sheepCentre=null;
// The sheep
private BufferedImage sheep=null;
// The up vector
private Point2D up=null;
// The centre of the frame
private Point2D centre=null;
BufferedImage buff;
public MT()
{
this.setSize(800,600);
// Setup the sheep
setupSheep();
// Set the centre
centre=new Point2D.Double(this.getWidth()/2,this.getHeight()/2);
// Add the mouse thingys
this.addMouseMotionListener(this);
this.addMouseWheelListener(this);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
private void setupSheep()
{
try {
sheep=ImageIO.read(new File("sheep.png"));
} catch (Exception ex) {ex.printStackTrace();}
// Draw in the middle
double x=(this.getWidth()/2)-(sheep.getWidth()/2);
double y=(this.getHeight()/2)-(sheep.getHeight()/2);
pos=new Point2D.Double(x,y);
}
public void paint(Graphics g)
{
if(buff == null)
buff=new BufferedImage(this.getWidth(),this.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR_PRE);
// Draw the buff
g.drawImage(buff,0,0,null);
}
private void updateBuffer()
{
// Get the buff g
Graphics2D buffG=buff.createGraphics();
buffG.setColor(getBackground());
buffG.fillRect(0, 0, getWidth(), getHeight());
// The up vector (sheep x and y - speed)
up=new Point2D.Double(pos.getX(),pos.getY()-speed);
// The up line from sheep to up
Line2D upLine=new Line2D.Double(pos,up);
// The direction line
Line2D dirLine=null;
// Draw the up line in blue
buffG.setPaint(Color.blue);
buffG.draw(upLine);
// Roate the up line
AffineTransform alf=AffineTransform.getRotateInstance(
Math.toRadians(dir),upLine.getX1(),upLine.getY1()
);
// Get the transformed shaoe as a line
dirLine=toLine(alf.createTransformedShape(upLine));
// Draw the direction line in red
buffG.setPaint(Color.red);
buffG.draw(dirLine);
// Move to end of the dir line
pos=new Point2D.Double(dirLine.getX2(),dirLine.getY2());
// The centre of the sheep
sheepCentre=new Point2D.Double(pos.getX()+(sheep.getWidth()/2),
pos.getY()+(sheep.getHeight()/2));
// If face dir
if (faceDir)
{
AffineTransform at = getTransform(sheep,dir,pos.getX(),pos.getY());
buffG.drawRenderedImage(sheep, at);
} else {
// Draw the sheep
buffG.drawImage(sheep,(int)pos.getX(),(int)pos.getY(),null);
}
buffG.dispose();
}
public void mouseMoved(MouseEvent e)
{
if(buff == null) return;
// Get the mouse x,y
double mX=e.getPoint().getX();
double mY=e.getPoint().getY();
// Make a point at the top middle of the frame
Point2D top=new Point2D.Double(centre.getX(),0);
// The dist of top to centre (side a)
double sideA=Point.distance(top.getX(),top.getY(),
centre.getX(),centre.getY());
// The dist pf centre to mouse point (side b)
double sideB=Point.distance(centre.getX(),centre.getY(),
mX,mY);
// Between mouse and top (side c)
double sideC=Point.distance(mX,mY,top.getX(),top.getY());
// We wanna find the angle abound the centre
// So the cos of angleCen
double cosCen=((sideA*sideA)+(sideB*sideB)-(sideC*sideC))/(
2*(sideA*sideB));
// Arc cos to get angle
dir=Math.toDegrees(Math.acos(cosCen));
// If mouse is on left side of centre
if (mX<centre.getX())
{
// - from 360 to get the reverse angle
dir=360-dir;
}
// Repaint
updateBuffer();
repaint();
}
public void mouseDragged(MouseEvent e) {}
public void mouseWheelMoved(MouseWheelEvent e)
{
// If up (away)
if (e.getWheelRotation() > 0)
{
// More speed
speed=speed+4;
}
else {speed=speed-4;}
}
public AffineTransform getTransform(BufferedImage in,double angle,
double x,double y)
{
double theta = Math.toRadians(angle) - Math.PI/2;
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
int iw = in.getWidth();
int ih = in.getHeight();
double w = iw*cos + ih*sin;
double h = ih*cos + iw*sin;
double ix = x + (w - iw)/2;
double iy = y + (h - ih)/2;
AffineTransform aff = AffineTransform.getTranslateInstance(ix, iy);
aff.rotate(theta, iw/2, ih/2);
return aff;
}
public static Line2D toLine(Shape s)
{
return toLine(s.getPathIterator(null));
}
public static Line2D toLine(PathIterator path)
{
// The line
Line2D line=null;
// The start of the line
Point2D start=null;
// The end of the line
Point2D end=null;
// Two points (x1,y1,x2,y2)
double[] points=new double[2];
// Get the first segment, should be move to and the stat of the line
path.currentSegment(points);
// Make the start point
start=new Point2D.Double(points[0],points[1]);
// Move to the next segment
path.next();
// Get the next segment, line to and the end point
path.currentSegment(points);
// Make the end point
end=new Point2D.Double(points[0],points[1]);
// Make the line
line=new Line2D.Double(start,end);
// Return the line
return line;
}
}
Thanks,
I must say, that I didn't kno about the Graphics2D.drawRenderedImage() method, it looks really cool now.
I've stated applying the line movement thing into my Sprite class already, have to do the rotation thing now.
Looking back at my code, it was a real joy to delete all the line of code and replace them with this new much shorter method.
I have game idea a plenty now, I'll have to make a start on one :D
Thanks a lot,
Luke