Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (527)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (594)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Character States and Animation  (Read 2171 times)
0 Members and 1 Guest are viewing this topic.
Offline ChouChou

Senior Newbie





« Posted 2010-02-07 14:01:14 »

Hi, I'm ChouChou, I've been lurking around this great forum for a while and this is my first post.

I have a question regarding the character states and animation, I' ve read some great posts from
http://www.java-gaming.org/topics/making-the-character-attack-once/21788/view.html
and
http://www.java-gaming.org/topics/simple-sprite-animation-loop/16829/view.html

I'm doing a side scroller game like rockmanX4(using Zero's light saber as weapon) and hopefully the control/animation will be smooth like it in the future, but I felt like I coded my character states and animation class wrong as I need a bunch of if statements just to get things working. Following is the code and I'm seeking advice on how to improve my state/animation system to make things better, thanks in advance!

P.S I will post additional code if required.

States Class
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
public class States {
   /** Character actions */
   public static final int IDLE = 0;
   public static final int RUNNING = 1;
   public static final int JUMPING = 2;
   public static final int HIT = 3;
   public static final int ATTACKING = 4;
   
   /** Directoin player is facing */
   public static final int LEFT = -1;
   public static final int RIGHT = -2;
}


Animation 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  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
public class Animation {
   private BufferedImage img;
   private int frameDuration = 60;
   private int frameNumberY, frameNumberX, frameX, frameY, charWidth, charHeight, sheetWidth, sheetHeight, playStyle;
   private long lastFrameChange;
   private long lastLoopTime = System.currentTimeMillis();
   /** Boolean to check if an animation has finished playing */
   private boolean isFinished = false;
   
   /** Play animation once */
   public static final int PLAY_ONCE = 0;
   /** Loop animation */
   public static final int LOOPING = 1;
   
   /** Entity's animation current state */
   private int currentState = States.IDLE;
   /** Current playing animation state */
   private int animState = States.IDLE;
   
   
   
   
   
   /** Creates animation for entity*/
   public void createAnimation(BufferedImage img, int x, int y, int offsetX, int offsetY, int charWidth, int charHeight,
          int sheetWidth, int sheetHeight, int frameDuration, int startFrame, int playStyle) {
   
      if(currentState > animState || currentState == States.IDLE) {
         animState = currentState;
         frameNumberX = 0;
         lastFrameChange = 0;
         this.img = img;
         this.charWidth = charWidth;
         this.charHeight = charHeight;
         this.sheetWidth = sheetWidth;
         this.sheetHeight = sheetHeight;
         this.frameDuration = frameDuration;
         this.playStyle = playStyle;
      }
   }
   
   public void update() {
      if(currentState == animState && !isFinished) {
         /** Difference between current time and last loop time */
         long delta = System.currentTimeMillis() - lastLoopTime;
         
         /** Last loop time */
         lastLoopTime = System.currentTimeMillis();
         
         /** Variable to check if frame > duration */
         lastFrameChange += delta;
         
         /** Change frame */
         if (lastFrameChange > frameDuration) {
            /** Reset frame */
            lastFrameChange = 0;
           
            /** update the frame X */
            frameNumberX++;
            if (frameNumberX >= sheetWidth) {
               if(playStyle == PLAY_ONCE) {
                  isFinished = true;
                  currentState = States.IDLE;
                  animState = States.IDLE;
               } else if(playStyle == LOOPING) {
                  frameNumberX = 0;
               }
            }
           
            /** update the frame Y */
            frameNumberY++;
            if (frameNumberY >= sheetHeight) {
               frameNumberY = 0;
            }
         }
         /** Current frame X */
         frameX = (frameNumberX % sheetWidth) * charWidth;
         
         /** Current frame Y */
         frameY = (frameNumberY % sheetHeight) * charHeight;
      }
     
      /** When animation finished change states to IDLE*/
      if(isFinished) {
         isFinished = false;
      }
   }
   
   /** Get current image */
   public BufferedImage getCurrentImage() {
      return img.getSubimage(frameX, frameY, charWidth, charHeight);
   }
   
   /** Set playing animation state */
   public int getAnimState() {
      return animState;
   }
   
   /** Get current entity animation state */
   public int getCurrentState() {
      return currentState;
   }
   
   /** Set entity animation state */
   public void setCurrentState(int state) {
      this.currentState = state;
   }
   
   /** Set entity animation state */
   public void setAnimState(int state) {
      this.animState = state;
   }
   
   /** Return if animation has finished playing or not */
   public boolean isFinished() {
      return isFinished;
   }
   
   public void setFinished(boolean isFin) {
      isFinished = isFin;
   }
}

Offline ChouChou

Senior Newbie





« Reply #1 - Posted 2010-02-07 14:02:56 »

Part of the Player 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  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
219  
220  
221  
222  
223  
224  
225  
226  
227  
228  
229  
230  
231  
232  
233  
234  
235  
236  
237  
238  
239  
240  
241  
242  
243  
244  
245  
246  
247  
248  
249  
250  
251  
252  
253  
int key = -1;
   /** Update player */
   public void update(long elapsedTime) {
      float dx = 0, dy = 0;
     
     
      /** Set player states */
      setPlayerState(dx, dy);
     
      /** Check player collision with enemies */
      enemyCollision();
     
      /** Change player status */
      changeStatus(elapsedTime);
     
      /** check if player is falling */
      fallCheck();
     
      /** Make player jump */
      jump();
     
     
      /** Offset X for player */
      offsetX = (int)((GameCore.mapPosX + GameCore.fixX)* Map.TILE_SIZE);
      /** Offset Y for player */
      offsetY = (int)((GameCore.mapPosY + GameCore.fixY) * Map.TILE_SIZE);
     
      /** Current pos of player*/
      xp = (int) (Map.TILE_SIZE * px);
      yp = (int) (Map.TILE_SIZE * py);
     
      /** Update animation */
      updateAnim();
   }
   
   /** Changes player status */
   long totalDuration = 0;
   private void changeStatus(long elapsedTime) {
      if(status == Status.INVINCIBLE) {
         totalDuration += elapsedTime;
         if(totalDuration > 1000) {
            status = Status.NORMAL;
            totalDuration = 0;
         }
      }
   }

   /** Makes player jump */
   private void jump() {
      /** Check if player is jumping */
      if(jumping) {
         idle = false;
         /** Increase gravity */
         jumpDistance += gravity;
         //jumping up
         if(jumpDistance < 0 && space) {
            if(validLocation(px, py - moveSPeed)) {
               moveY(-moveSPeed);
            } else {
               space = false;
            }
         // Falling down
         } else if(jumpDistance > 0 || !space) {
            moveY(moveSPeed);
         }
         anim.setCurrentState(States.JUMPING);
      }
   }

   /** Check if player is falling */
   private void fallCheck() {
      if(!jumping) {
         if(validLocation(px, py + moveSPeed)) {
            jumpDistance = 0;
            jumping = true;
         }
      }
   }
   
   /** Set player state */
   private void setPlayerState(float dx, float dy) {
      /** Player getting hit */
      if(hit) {
         if(status != Status.INVINCIBLE) {
            idle = false;
            left = false;
            right = false;
            jumping = false;
            hp -= 1;
            anim.setCurrentState(States.HIT);
            status = Status.INVINCIBLE;
         }
         hit = false;
      }
     
      /** Player attacking */
      if(attacking) {
         if(States.ATTACKING > anim.getCurrentState()) {
            idle = false;
            anim.setCurrentState(States.ATTACKING);
         }
//         attacking = false;
      }
     
      /** Player jumping*/
      if(space && !jumping) {
         if(anim.getAnimState() == States.ATTACKING || anim.getAnimState() == States.HIT) {
         } else {
            idle = false;
            jumping = true;
            jumpDistance = maxJumpHeight;
         }
      }
     
      /** Player moving left */
      if(left) {
         idle = false;
         faceDir = States.LEFT;
         if(anim.getAnimState() == States.ATTACKING || anim.getAnimState() == States.HIT) {
            /** When hit while running, don't change state */
         } else if(jumping) {
            dx = -moveSPeed;
         } else {
            if(States.RUNNING >= anim.getCurrentState()) {
               anim.setCurrentState(States.RUNNING);
               dx = -moveSPeed;
            } else if(attacking) {
            } else {
               idle = true;
            }
         }
      }
     
      /** Player moving right */
      if(right) {
         idle = false;
         faceDir = States.RIGHT;
         /** When hit while running, don't change state */
         if(anim.getAnimState() == States.ATTACKING || anim.getAnimState() == States.HIT) {
         } else if(jumping) {
            dx = moveSPeed;
         } else {
            if(States.RUNNING >= anim.getCurrentState()) {
               anim.setCurrentState(States.RUNNING);
               dx = moveSPeed;
            } else if(attacking) {
            } else {
               idle = true;
            }
         }
      }
     
      /** Player Standing */
      if(idle) {
         anim.setCurrentState(States.IDLE);
      }
     
      /** Move player and shift map in the opposite direction */
      if(moveX(dx)) {
      }
   }
   
   public void keyPressed(KeyEvent e) {
      /** Attacking */
      if (e.getKeyCode() == KeyEvent.VK_C && !pressAttack) {
         attacking = true;
         pressAttack = true;
      }
      /** Jumping */
      if (e.getKeyCode() == KeyEvent.VK_SPACE && !jumping && !attacking && !pressSpace) {
         space = true;
         pressSpace = true;
      }
      /** Left */
      if (e.getKeyCode() == KeyEvent.VK_LEFT) {
         left = true;
      }
      /** Right */
      if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
         right = true;
      }
      /** Up */
      if (e.getKeyCode() == KeyEvent.VK_UP) {
      }
      /** Down */
      if (e.getKeyCode() == KeyEvent.VK_DOWN) {
      }
   }
   
   public void keyReleased(KeyEvent e) {
      /** Moving left */
      if (e.getKeyCode() == KeyEvent.VK_LEFT) {
         left = false;
         idle = true;
      }
      /** Moving left */
      if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
         right = false;
         idle = true;
      }
      if (e.getKeyCode() == KeyEvent.VK_UP) {
      }
      if (e.getKeyCode() == KeyEvent.VK_DOWN) {
      }
      /** Jumping */
      if(e.getKeyCode() == KeyEvent.VK_SPACE) {
         space = false;
         pressSpace = false;
      }
      /** Attacking */
      if (e.getKeyCode() == KeyEvent.VK_C) {
         attacking = false;
         pressAttack = false;
      }
   }
   
   
   /** Update animation */
   private void updateAnim() {
      if(anim.getCurrentState() == States.HIT) {
         if(faceDir == States.LEFT) {
            anim.createAnimation(img.getPlayerAnim()[img.GET_HIT_L], xp, yp, offsetX, offsetY, 56, 53, 6, 1, 80, 0, Animation.PLAY_ONCE);
         } else {
            anim.createAnimation(img.getPlayerAnim()[img.GET_HIT_R], xp, yp, offsetX, offsetY, 56, 53, 6, 1, 80, 0, Animation.PLAY_ONCE);
         }
      } else if(anim.getCurrentState() == States.ATTACKING) {
         if(faceDir == States.LEFT) {
            anim.createAnimation(img.getPlayerAnim()[img.ATTACK_L], xp, yp, offsetX, offsetY - 20, 103, 71, 5, 1, 60, 0, Animation.PLAY_ONCE);
         } else {
            anim.createAnimation(img.getPlayerAnim()[img.ATTACK_R], xp, yp, offsetX, offsetY - 20, 103, 71, 5, 1, 60, 0, Animation.PLAY_ONCE);
         }
      } else if(anim.getCurrentState() == States.RUNNING) {
         if(faceDir == States.LEFT) {
            anim.createAnimation(img.getPlayerAnim()[img.RUN_L], xp, yp, offsetX, offsetY, 54, 45, 15, 1, 60, 0, Animation.PLAY_ONCE);
         } else {
            anim.createAnimation(img.getPlayerAnim()[img.RUN_R], xp, yp, offsetX, offsetY, 54, 45, 15, 1, 60, 0, Animation.PLAY_ONCE);
         }
      } else if(anim.getCurrentState() == States.JUMPING) {
         if(faceDir == States.LEFT) {
            anim.createAnimation(img.getPlayerAnim()[img.JUMP_L], xp, yp, offsetX, offsetY, 54, 58, 5, 1, 60, 0, Animation.PLAY_ONCE);
         } else {
            anim.createAnimation(img.getPlayerAnim()[img.JUMP_R], xp, yp, offsetX, offsetY, 54, 58, 5, 1, 60, 0, Animation.PLAY_ONCE);
         }
      } else if(anim.getCurrentState() == States.IDLE) {
         if(faceDir == States.LEFT) {
            anim.createAnimation(img.getPlayerAnim()[img.IDLE_L], xp, yp, offsetX, offsetY, 54, 45, 1, 1, 60, 0, Animation.LOOPING);
         } else {
            anim.createAnimation(img.getPlayerAnim()[img.IDLE_R], xp, yp, offsetX, offsetY, 54, 45, 1, 1, 60, 0, Animation.LOOPING);
         }
      }
     
      anim.update();
   }

Offline zoto

Senior Devvie


Medals: 4



« Reply #2 - Posted 2010-02-07 15:32:07 »

You should probably just use the same update signature on the animation as you do for the player, then you can pass the elapsed time instead of recalculating it.

In your animation update function it looks like you increase frameNumberY every time instead of just if(frameNumberX >= sheetWidth), basically traversing diagonally across the sprite sheet.

I'm not sure how your sprite sheets are setup but the way I usually do it is to have a separate sheet for each action. The animation class has no player logic in it all it does is update and draw. The player class has an animation object for each action and the player class chooses what animation to update/draw based on its current state.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Swattkidd7

Junior Devvie





« Reply #3 - Posted 2010-02-07 20:28:58 »

It seems like every time you update you create a new animation, you should try loading the animations once and then just setting the currentAnimation to whichever animation is happening at the time. For example have a jumping animation, running, etc, etc and a currentAnimation. Then when you check if the character is "running" set the currentAnimation to running.

But as you can tell by the first post you linked to, this method may not be the best method or even a correct method.
Offline ChouChou

Senior Newbie





« Reply #4 - Posted 2010-02-08 04:39:28 »

Thanks for the replies! My sprite sheet is set up with image after image horizontally(but each action has a separate sheet ), so Y never increases( keep it simple for now), only X will need to change. something like this: [0 1 2 3 4 5 6 7] with numbers representing each image. 

 I also have a LoadImage class to load the sprite sheet and store them into an array, so that the images are only loaded once. I can play most of the animations correctly but when I switch from left button to right button really quickly( I have a faceDir boolean in the player class to show which direction the player is currently facing  ) I have a problem that the correct running animation wont be played unless the previous direction animation has finished playing, is that the problem of my animation class or did i somehow set up the character states wrong in the player class?
Offline ChouChou

Senior Newbie





« Reply #5 - Posted 2010-02-08 04:40:54 »

You should probably just use the same update signature on the animation as you do for the player, then you can pass the elapsed time instead of recalculating it.

I'm going to implement that next .
Offline ChouChou

Senior Newbie





« Reply #6 - Posted 2010-02-09 13:47:07 »

After I implemented elapsedTime(delta for some people) to my moveSpeed variables I start seeing multiple images for my running animation, is there a reason for that?  Undecided
Offline zoto

Senior Devvie


Medals: 4



« Reply #7 - Posted 2010-02-09 14:32:58 »

Do you mean multiple images off the sprite sheet? drawing the same image multiple places? Regardless it's hard to say what the problem is without seeing the code.
Offline ChouChou

Senior Newbie





« Reply #8 - Posted 2010-02-09 14:34:54 »

Do you mean multiple images off the sprite sheet? drawing the same image multiple places? Regardless it's hard to say what the problem is without seeing the code.


Yea, mutiple images drawing near where the sprite is, do you want me to send you the code?
Offline zoto

Senior Devvie


Medals: 4



« Reply #9 - Posted 2010-02-09 14:37:25 »

Sure you can send it to me or just post it some public place so more people can help. Multiple images off the sprite sheet probably means your sub image is just too big.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ChouChou

Senior Newbie





« Reply #10 - Posted 2010-02-09 14:40:37 »

This is my new Animation class, changed delta to elapsedTime as you suggested  Smiley
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  
   /** Creates animation for entity*/
   public void createAnimation(BufferedImage img, int x, int y, int offsetX, int offsetY, int charWidth, int charHeight,
          int sheetWidth, int sheetHeight, int frameDuration, int startFrame, int playStyle) {
   
      animState = currentState;
      this.img = img;
      this.charWidth = charWidth;
      this.charHeight = charHeight;
      this.sheetWidth = sheetWidth;
      this.sheetHeight = sheetHeight;
      this.frameDuration = frameDuration;
      this.playStyle = playStyle;
   }
   
   public void update(long elapsedTime) {
      if(currentState == animState && !isFinished) {
         /** Difference between current time and last loop time */
         lastFrameChange += elapsedTime;
         
         /** Change frame */
         if (lastFrameChange > frameDuration) {
            /** Reset frame */
            lastFrameChange = 0;
           
            /** update the frame X */
            frameNumberX++;
            if (frameNumberX >= sheetWidth) {
               if(playStyle == PLAY_ONCE) {
                  isFinished = true;
                  frameNumberX = 0;
                  lastFrameChange = 0;
                  currentState = States.IDLE;
                  animState = States.IDLE;
               } else if(playStyle == LOOPING) {
                  frameNumberX = 0;
               }
            }
           
            /** update the frame Y */
            frameNumberY++;
            if (frameNumberY >= sheetHeight) {
               frameNumberY = 0;
            }
         }
         /** Current frame X */
         frameX = (frameNumberX % sheetWidth) * charWidth;
         
         /** Current frame Y */
         frameY = (frameNumberY % sheetHeight) * charHeight;
      }
     
      /** When animation finished change states to IDLE*/
      if(isFinished) {
         isFinished = false;
      }
   }




This is part of the player class, I've made some modification and trying things out, I moved the setting animation methods into here, they were originally in the updateAnim method:
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  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
/** Set player state 
    * @param elapsedTime */

   private void setPlayerState(float dx, float dy, long elapsedTime) {
      /** Player getting hit */
      if(hit) {
         if(status != Status.INVINCIBLE) {
            idle = false;
            left = false;
            right = false;
            jumping = false;
            hp -= 1;
            anim.setCurrentState(States.HIT);
            status = Status.INVINCIBLE;
           
            /** Hit animation */
            if(faceDir == States.LEFT) {
               anim.createAnimation(img.getPlayerAnim()[img.GET_HIT_L], xp, yp, offsetX, offsetY, 56, 53, 6, 1, 80, 0, Animation.PLAY_ONCE);
            } else {
               anim.createAnimation(img.getPlayerAnim()[img.GET_HIT_R], xp, yp, offsetX, offsetY, 56, 53, 6, 1, 80, 0, Animation.PLAY_ONCE);
            }
         }
         hit = false;
      }
     
      /** Player attacking */
      if(attacking) {
         if(States.ATTACKING > anim.getCurrentState()) {
            idle = false;
         }
         /** Set attack animation*/
         anim.setCurrentState(States.ATTACKING);
         
         if(faceDir == States.LEFT) {
            anim.createAnimation(img.getPlayerAnim()[img.ATTACK_L], xp, yp, offsetX, offsetY - 20, 103, 71, 5, 1, 60, 0, Animation.PLAY_ONCE);
         } else {
            anim.createAnimation(img.getPlayerAnim()[img.ATTACK_R], xp, yp, offsetX, offsetY - 20, 103, 71, 5, 1, 60, 0, Animation.PLAY_ONCE);
         }
         
         if(book != null) {
            book = null;
         }
         book = new SpellBook(px, py, faceDir);
         book.enemyCollision();
         attacking = false;
      }
     
      /** Player jumping*/
      if(space && !jumping) {
         if(anim.getAnimState() == States.ATTACKING || anim.getAnimState() == States.HIT) {
         } else {
            idle = false;
            jumping = true;
            jumpDistance = maxJumpHeight;
         }
      }
     
      /** Player moving left */
      if(left) {
         idle = false;
         faceDir = States.LEFT;
         dx = -moveSPeed * elapsedTime * 0.05f;
         /** Set running animation */
         if(States.RUNNING >= anim.getCurrentState()) {
            anim.setCurrentState(States.RUNNING);
            anim.createAnimation(img.getPlayerAnim()[img.RUN_L], xp, yp, offsetX, offsetY, 54, 45, 15, 1, 60, 0, Animation.PLAY_ONCE);
         }
      }
     
      /** Player moving right */
      if(right) {
         idle = false;
         faceDir = States.RIGHT;
         dx = moveSPeed * elapsedTime * 0.05f;
         if(States.RUNNING >= anim.getCurrentState()) {
            /** Set running animation */
            anim.setCurrentState(States.RUNNING);
            anim.createAnimation(img.getPlayerAnim()[img.RUN_R], xp, yp, offsetX, offsetY, 54, 45, 15, 1, 60, 0, Animation.PLAY_ONCE);
         }
      }
     
      /** Player Standing */
      if(idle) {
         anim.setCurrentState(States.IDLE);
         
         if(faceDir == States.LEFT) {
            anim.createAnimation(img.getPlayerAnim()[img.IDLE_L], xp, yp, offsetX, offsetY, 54, 45, 1, 1, 60, 0, Animation.LOOPING);
         } else {
            anim.createAnimation(img.getPlayerAnim()[img.IDLE_R], xp, yp, offsetX, offsetY, 54, 45, 1, 1, 60, 0, Animation.LOOPING);
         }
      }
     
      /** Move player and shift map in the opposite direction */
      if(moveX(dx)) {
      }
   }



Thanks alot for the help, greatly appreciated!
Offline ChouChou

Senior Newbie





« Reply #11 - Posted 2010-02-09 14:53:49 »

Sure you can send it to me or just post it some public place so more people can help. Multiple images off the sprite sheet probably means your sub image is just too big.

Sorry I copied wrong, it was "drawing the same image multiple places?"  They are closely overlapped so it seems like 1 image with "shadows" of the same image around it.
Offline zoto

Senior Devvie


Medals: 4



« Reply #12 - Posted 2010-02-09 15:04:38 »

I don't see the drawing code in there.

You can probably safely move the state out of the animation class. Once all the player specific code is out of the animation class it will be a lot more useful to you as you will be able to use it for all the game animations.

Is your game multi-threaded?
Offline ChouChou

Senior Newbie





« Reply #13 - Posted 2010-02-09 15:08:02 »

I don't see the drawing code in there.

You can probably safely move the state out of the animation class. Once all the player specific code is out of the animation class it will be a lot more useful to you as you will be able to use it for all the game animations.

Is your game multi-threaded?

My game is single-threaded, the actual drawing code is in the GameCore class which I'll post below, and yea you are right about seperating states with animation class, I'll implement that next.  Grin
My game loop is based on Kevin Glass's awesome tutorial on his site(coke and code) and abit of killer programming in java.

GameCore.java

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  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;


public class GameCore extends Canvas implements KeyListener {
   private static final long serialVersionUID = 1L;
   
   /** Screen width */
   public static final int WINDOWS_WIDTH = 1024;
   /** Screen Height */
   public static final int WINDOWS_HEIGHT = 768;
   /** The buffered strategy used for accelerated rendering */
   private BufferStrategy strategy;
   public boolean gameRunning = true;
   
   LoadImage img;
   Map map;
   Player player;
   Enemy1 enemy1;
   Enemy1 enemy2;
   Animation anim = new Animation();
   public static float mapPosX;
   public static float mapPosY;
   public static float fixX, fixY, fixX1, fixY1;

   
   
   static ArrayList<Enemy> enemyList = new ArrayList<Enemy>();
   
   GameCore() {
      Frame frame = new Frame("Side Scroller");
      frame.setLayout(null);
      setBounds(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
      frame.add(this);
      frame.setSize(WINDOWS_WIDTH,WINDOWS_HEIGHT);
      frame.setResizable(false);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
      frame.addKeyListener(this);
      addKeyListener(this);
      //Exit windows
      frame.addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
     
      /** create the strategy used for accelerated rendering. */
      createBufferStrategy(2);
      strategy = getBufferStrategy();
     
      /** Load images */
      img = new LoadImage();
      img.load();
     
      /** Create map */
      map = new Map(img);
     
      /** Start pos */
      enemyList.add(new Enemy1(map, 8, 20, img));
      enemyList.add(new Enemy1(map, 13, 20, img));
      player = new Player(map, 3, 2, img, anim);
     
     
      /** Center the map relative to player */
      mapPosX = Player.visibleX - Player.px;
      mapPosY = Player.visibleY - Player.py;
     
      gameLoop();
   }
   
   public static void main(String[] args) {
      new GameCore();
   }

   private void gameLoop() {
      long lastLoopTime = System.currentTimeMillis();
      while(gameRunning) {
         long elapsedTime = System.currentTimeMillis() - lastLoopTime;
         lastLoopTime = System.currentTimeMillis();

         gameUpdate(elapsedTime);
         gameRender();
         try {
            Thread.sleep(calcSleepTime());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }

   private void gameUpdate(long elapsedTime) {
      /** X and Y offsets based on player's position*/
      mapPosX = Player.visibleX - Player.px;
      mapPosY = Player.visibleY - Player.py;
      cornerShift();
      /** Update enemies */
      for(int i = 0; i < enemyList.size(); i++) {
         enemyList.get(i).update(elapsedTime);
      }
      /** Update player */
      player.update(elapsedTime);
   }

   /** Checking if player is near the edge, if yes shift the map so things
    outside the wall is not shown */

   private void cornerShift() {
      if(Player.visibleX > Player.px - 1) {
         // Minus 1 to not show wall
         fixX = Player.px - Player.visibleX - 1;
      } else if(Player.px > Map.MAP_WIDTH - Player.visibleX - 1) {
         fixX = Player.px - Map.MAP_WIDTH + Player.visibleX + 1;
      }
      if(Player.visibleY > Player.py - 1) {
         fixY = Player.py - Player.visibleY - 1;
      } else if(Player.py > Map.MAP_HEIGHT- Player.visibleY - 1 ) {
         fixY = Player.py - Map.MAP_HEIGHT + Player.visibleY + 1;
      }
   }
   
   
   private void gameRender() {
      Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
     
      // clear the screen
      g.setColor(Color.BLACK);
      g.fillRect(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
      g.translate(0, 30);
     
      map.paint(g);
     
      /** paint enemy from list */
      for(int i = 0; i < enemyList.size(); i++) {
         if(enemyList.get(i).isAlive()) {
            enemyList.get(i).paint(g);
         }
      }
      /** paint player */
      player.paint(g);
      // flip the buffer so we can see the rendering
      g.dispose();
      strategy.show();
   }

   /**Calculates sleep time*/
   private long calcSleepTime() {
      long beforeTime, timeDiff, sleepTime;
      beforeTime = System.currentTimeMillis();
     
      timeDiff = System.currentTimeMillis() - beforeTime;
      sleepTime = 10 - timeDiff;
     
      if(sleepTime <= 0) {
         sleepTime = 5;
      }
      return sleepTime;
   }
   
   @Override
   public void keyPressed(KeyEvent e) {
      player.keyPressed(e);
   }
   
   @Override
   public void keyReleased(KeyEvent e) {
      player.keyReleased(e);
   }

   @Override
   public void keyTyped(KeyEvent e) {}
   
   /** Return Enemy list */
   public static ArrayList<Enemy> getEnemyList() {
      return enemyList;
   }
}

Offline zoto

Senior Devvie


Medals: 4



« Reply #14 - Posted 2010-02-09 21:27:25 »

There are a few problems I noticed when quickly looking over GameCore mostly in the calcSleepTime()  method. The function is returning how long the System.currentTimeMillis() took to execute when it should be calculating how long the game took to update and render for the previous tick. The System.currentTimeMillis() is not recommended for a game System.nanoTime() should be used instead as it is much more accurate, and math corrected for the change of course.

 You may wish to check out this post http://www.java-gaming.org/topics/basic-game/21919/view.html.

Hope this helps.
Offline ChouChou

Senior Newbie





« Reply #15 - Posted 2010-02-10 03:05:39 »

There are a few problems I noticed when quickly looking over GameCore mostly in the calcSleepTime()  method. The function is returning how long the System.currentTimeMillis() took to execute when it should be calculating how long the game took to update and render for the previous tick. The System.currentTimeMillis() is not recommended for a game System.nanoTime() should be used instead as it is much more accurate, and math corrected for the change of course.

 You may wish to check out this post http://www.java-gaming.org/topics/basic-game/21919/view.html.

Hope this helps.

Thanks for the reply! I'll go fix that up as soon as I get off work  =D
Offline ChouChou

Senior Newbie





« Reply #16 - Posted 2010-02-10 13:14:37 »

Yea, after implementing the loop from that thread my multiple image problem is gone, thanks!  Grin  I don't get some of the maths tho, why is he dividing by 1000 * 1000? Isnt nano 1000*1000*1000?

1  
update((int) ((currentUpdateTime - lastUpdateTime)/(1000*1000)));

Offline Gudradain
« Reply #17 - Posted 2010-02-11 15:10:43 »

Dividing nanoseconds by (1000*1000) give you milliseconds. The deltaTime in the update method is usually in milliseconds for game.
Offline ChouChou

Senior Newbie





« Reply #18 - Posted 2010-02-12 01:41:03 »

Dividing nanoseconds by (1000*1000) give you milliseconds. The deltaTime in the update method is usually in milliseconds for game.

Ah I understand now, that makes alot of sense. Thanks for your loop!
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

PocketCrafter7 (13 views)
2014-11-28 16:25:35

PocketCrafter7 (9 views)
2014-11-28 16:25:09

PocketCrafter7 (10 views)
2014-11-28 16:24:29

toopeicgaming1999 (76 views)
2014-11-26 15:22:04

toopeicgaming1999 (66 views)
2014-11-26 15:20:36

toopeicgaming1999 (15 views)
2014-11-26 15:20:08

SHC (29 views)
2014-11-25 12:00:59

SHC (27 views)
2014-11-25 11:53:45

Norakomi (32 views)
2014-11-25 11:26:43

Gibbo3771 (28 views)
2014-11-24 19:59:16
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!