Java-Gaming.org Java4K winners: [ by our judges | by the community ]         
Featured games (67)
games approved by the League of Dukes
Games in Showcase (∞)
games submitted by our members



News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  Print  
  Drawing sprites and animation  (Read 1087 times)
0 Members and 1 Guest are viewing this topic.
Offline DavidW

JGO n00b
*

Posts: 47
Medals: 1



« on: 2011-10-17 20:10:11 »

Hey all, it's me again asking for more object oriented help.  Roll Eyes

I have an abstract sprite class (used to be called "Entity" but I changed it to sprite for some reason) and I wasn't sure how each type of sprite would draw itself, so I made a DrawStrategy interface and each Sprite holds one of these.  So for instance, some sprites have 8 different images depending on what direction they are heading, some always use the same.  Some have an animation cycle, some do not.  I created different DrawStrategy classes for each type of drawing needed, and just add this to the Sprite when I create it.

The thing is, some strategies need more info than others.  So I add methods like setDirection(Direction d) to a DirectionAnimationStrategy class (Direction is an Enum, BTW).  But if a certain sprite child class (like Enemy) needs to call this, then I am forced to cast the DrawStrategy to DirectionAnimationStrategy.  Here is what I am talking about:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
package towerdefence.sprite;

import java.awt.geom.Point2D;
import towerdefence.GameWorld;
import towerdefence.graphics.DirectionAnimationStrategy;
import towerdefence.graphics.DrawStrategy;
import towerdefence.path.Path;


public class Enemy extends Sprite {
   
   private Path path;
   private double dist = 0;
   private double speed = 3;

   public Enemy(Point2D.Double l, double w, double h, GameWorld wo, DrawStrategy d) {
      super(l, w, h, wo, d);
      path = wo.getLevel().getPath();
   }

   public  void updateMe() {
     
      Point2D.Double lastLoc = location;
     
      setBounds();
     
      dist += speed;
     
      if(dist > path.length())
         dist = 0;
     
      location = path.getPointFromDistance(dist);
     
      double angle = Math.atan2(location.y - lastLoc.y, location.x - lastLoc.x);
     
      ((DirectionAnimationStrategy)drawStrat).setDirection(Direction.directionFromAngle(angle));
      ((DirectionAnimationStrategy)drawStrat).update();
   }

}


This seems a little messy to me.  Is there a better way to do this?

By the way, Path is a class which tells the Enemy how it is to walk around the game world.  I am making a tower defense game, just in case you missed my earlier thread, so enemies just walk along a predetermined path.  I figured the best way to do this is to store the path as a spline.

EDIT:

For reference, here is my Sprite class:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
package towerdefence.sprite;

import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import towerdefence.GameWorld;
import towerdefence.graphics.DrawStrategy;

public abstract class Sprite {

   protected Point2D.Double location;
   protected GameWorld world;
   protected DrawStrategy drawStrat;
   private Rectangle2D.Double bounds;
   private double width, height;
   
   private boolean drawingBounds;
   
   public Sprite(Point2D.Double l, double w, double h, GameWorld wo, DrawStrategy d) {
      location = l;
      world = wo;
      drawStrat = d;
     
      width = w;
      height = h;
     
      bounds = new Rectangle2D.Double();
      setBounds();
   }
   
   public void setDrawStrategy(DrawStrategy d) {
      drawStrat = d;
   }
   
   public void drawMe(Graphics2D g) {
      g.translate(location.x - width/2, location.y - height/2);
      drawStrat.draw(g);
     
      g.translate(-location.x + width/2, -location.y + height/2);
     
      if(drawingBounds)
         g.draw(bounds);
   }
   
   public abstract void updateMe();
   
   protected void setBounds() {
      bounds.setRect(location.x - width/2.0, location.y - height/2.0, width, height);
   }
   
   // Methods for collision detection:
 
   public Rectangle2D getBounds() {
      return bounds;
   }
   
   public boolean collidesWith(Rectangle2D r) {
      return bounds.intersects(r);
   }
   
   public boolean collidesWith(Sprite s) {  
      return collidesWith(s.getBounds());
   }

   public boolean isDrawingBounds() {
      return drawingBounds;
   }

   public void setDrawingBounds(boolean drawingBounds) {
      this.drawingBounds = drawingBounds;
   }
   
}
Offline sproingie

JGO Strike Force
***

Posts: 894
Medals: 55



« Reply #1 on: 2011-10-17 20:24:16 »

There is no way that the code in enemy.updateMe can work unless the DrawStrategy it is given in the constructor is a DirectionAnimationStrategy.  So the constructor should take a DirectionAnimationStrategy, and not a plain DrawStrategy.  You can still treat it as a DrawStrategy (without any casting) for other methods that only need a DrawStrategy and don't otherwise need to be aware of the direction.

Offline DavidW

JGO n00b
*

Posts: 47
Medals: 1



« Reply #2 on: 2011-10-17 20:44:36 »

Oh so I should just edit the constructor in Enemy?  I didn't think of that...   Clueless
Games published by our own members! Go get 'em!
Offline DavidW

JGO n00b
*

Posts: 47
Medals: 1



« Reply #3 on: 2011-10-17 20:52:48 »

Would you say the way I have set all this business up is a good way to do it?
Offline sproingie

JGO Strike Force
***

Posts: 894
Medals: 55



« Reply #4 on: 2011-10-17 22:43:37 »

I tend to think of a Sprite as the mechanism for drawing in the first place, so a drawing strategy like how to animate is simply a property of the sprite. If I had a class that selected a different sprite based on its facing or position or whatever state, I might call it a Model, similar to a 3D model with rigging that can put into different poses.  This is just my particular design taste, and I don't write action games (my experience is with MUDs) so take my design notes with a grain of salt...
Offline h3ckboy

JGO Kernel
*****

Posts: 1645
Medals: 4



« Reply #5 on: 2011-10-18 01:59:40 »

I can't right now, but if you want later on I can post some simple animation code I wrote?
Offline DavidW

JGO n00b
*

Posts: 47
Medals: 1



« Reply #6 on: 2011-10-18 11:38:45 »

Sure, I would appreciate it if you have the time.  Grin
Offline h3ckboy

JGO Kernel
*****

Posts: 1645
Medals: 4



« Reply #7 on: 2011-10-18 15:15:20 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
/**
 * This class is the class that is used for animtions.
 * @author Pearce Keesling aka h3ckboy
 *
 */

import java.awt.*;

import java.awt.image.BufferedImage;
import java.awt.Container;
public class Animation implements Cloneable {
   //the frames for the animation
  public BufferedImage[] images;
   //the time between each frame
  int time;
   //time that has passed since last frame
  int elapsedTime = 0;
   int currentFrame;
   public Animation(BufferedImage[] images,int time)
   {
      this.images = images;
      this.time = time;
      currentFrame = 0;
   }
   //advance animation each frame
  public void advance(int time)
   {
      elapsedTime+=time;
      if(elapsedTime>=this.time)
      {
         elapsedTime -=this.time;
         currentFrame++;
         if(currentFrame>=images.length)
         {
            currentFrame = 0;
         }
      }
   }
   //render the animation's current frame
  public void render(Graphics g,int x, int y,Container container)
   {
      g.drawImage(images[currentFrame],x,y,container);
   }
   public void render(Graphics g,int x, int y,int direction,Container container)
   {
      BufferedImage[] images = setDirection(direction,container);
      g.drawImage(images[currentFrame],x,y,container);
   }
   public BufferedImage getCurrentFrame()
   {
      return images[currentFrame];
   }
   public int getCurrentFrameInt()
   {
      return currentFrame;
   }
}


This is the animation class that I use, I tried to cut out some extra stuff I had in that wasn't exactly relevant to animation. feel free to use any or all of it, it was designed to be stand-alone from my programs.

If you have any questions about implementations just ask.
Pages: [1]
  Print  
 
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.16 | SMF © 2011, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.128 seconds with 20 queries.