Crossfire JXClient, Trunk  R20561
AnimationState.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.map;
23 
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.Set;
30 import org.jetbrains.annotations.NotNull;
31 
36 public class AnimationState implements Iterable<Location> {
37 
41  @NotNull
42  private final Animation animation;
43 
47  private int speed = 1;
48 
52  private int tickNo;
53 
58  private int index;
59 
63  private int lastFace = -1;
64 
68  @NotNull
69  private final Set<Location> locations = new HashSet<>();
70 
76  public AnimationState(@NotNull final Animation animation, final int index) {
77  this.animation = animation;
78  this.index = index%animation.getFaces();
79  }
80 
86  public void setSpeed(@NotNull final MapUpdaterState mapUpdaterState, final int speed) {
87  assert speed > 0;
88  if (this.speed == speed) {
89  return;
90  }
91  final int tmpIndex = index/this.speed;
92  final int tmpDelay = Math.min(index%this.speed, speed-1);
93  this.speed = speed;
94  index = tmpIndex*speed+tmpDelay;
95  updateFace(mapUpdaterState);
96  }
97 
102  public void setTickNo(final int tickNo) {
103  this.tickNo = tickNo;
104  }
105 
111  public void updateTickNo(@NotNull final MapUpdaterState mapUpdaterState, final int tickNo) {
112  final int diff = tickNo-this.tickNo;
113  if (tickNo < this.tickNo) {
114  System.err.println("Ignoring inconsistent tick value: current tick number is "+tickNo+", previous tick number was "+this.tickNo+".");
115  } else {
116  index = (index+diff)%(speed*animation.getFaces());
117  }
118  this.tickNo = tickNo;
119  updateFace(mapUpdaterState);
120  }
121 
126  private void updateFace(@NotNull final MapUpdaterState mapUpdaterState) {
127  final int face = animation.getFace(index/speed);
128  if (face == lastFace) {
129  return;
130  }
131  lastFace = face;
132  for (final Location location : locations) {
133  mapUpdaterState.mapFace(location, face, false);
134  }
135  }
136 
142  public void allocate(@NotNull final MapUpdaterState mapUpdaterState, @NotNull final Location location) {
143  if (!locations.add(location)) {
144  throw new IllegalArgumentException("duplicate location "+location);
145  }
146  if (lastFace != -1) {
147  mapUpdaterState.mapFace(location, lastFace, false);
148  }
149  }
150 
155  public void free(@NotNull final Location location) {
156  if (!locations.remove(location)) {
157  throw new IllegalArgumentException("undefined location "+location);
158  }
159  }
160 
164  @NotNull
165  @Override
166  public Iterator<Location> iterator() {
167  return Collections.unmodifiableSet(locations).iterator();
168  }
169 
177  public void scroll(final int dx, final int dy, final int width, final int height) {
178  final Collection<Location> tmp = new HashSet<>();
179  //noinspection Convert2streamapi
180  for (final Location location : locations) {
181  if (0 <= location.getX() && location.getX() < width && 0 <= location.getY() && location.getY() < height) { // out-of-map bounds animations are dropped, not scrolled
182  final int newX = location.getX()-dx;
183  final int newY = location.getY()-dy;
184  if (0 <= newX && newX < width && 0 <= newY && newY < height) { // in-map bounds animations are dropped if scrolled off the visible area
185  final Location newLocation = new Location(newX, newY, location.getLayer());
186  tmp.add(newLocation);
187  }
188  }
189  }
190  locations.clear();
191  locations.addAll(tmp);
192  }
193 
194 }
final Set< Location > locations
All map locations this animation is displayed at.
int getFace(final int index)
Returns one face of this animation.
Definition: Animation.java:85
void allocate(@NotNull final MapUpdaterState mapUpdaterState, @NotNull final Location location)
Adds this animation state to a map Location.
AnimationState(@NotNull final Animation animation, final int index)
Creates a new instance.
int getFaces()
Returns the number of faces of this animation.
Definition: Animation.java:76
void updateTickNo(@NotNull final MapUpdaterState mapUpdaterState, final int tickNo)
Sets the tick number and update affected faces.
void setTickNo(final int tickNo)
Sets the tick number.
void free(@NotNull final Location location)
Removes this animation state from a map Location.
The state of an Animation on a map.
Update a CfMap model from protocol commands.
int index
The face index currently shown.
int tickNo
The face was updated last in this tick number.
final Animation animation
The Animation to display.
Manages animations received from the server.
Definition: Animation.java:31
void updateFace(@NotNull final MapUpdaterState mapUpdaterState)
Updates the map face from the state.
void scroll(final int dx, final int dy, final int width, final int height)
Scrolls all map locations.
void setSpeed(@NotNull final MapUpdaterState mapUpdaterState, final int speed)
Sets the animation speed.