foreword
Paying tribute to the classic warcraft, "warcraft java version" is a real-time strategy theme stand-alone game, using the original Warcraft style and mechanics. Gather resources, build fortifications and destroy all enemy troops.
Humans: The Human Alliance of Lordaeron has been formed since the orcs first passed through the Dark Portal. They are tenacious, brave and fearless, wearing strong armor and holding sharp blades, they face the enemy bravely.
Orcs: Orcs are a rugged and tough race known for their reckless and ferocious fighting style, wearing simple fur and spiked leather armor.
It is implemented in java language, using swing technology for interface processing, and the design idea uses object-oriented thinking.
main needs
1. Players can choose their own camps: Humans and Orcs can choose from two camps.
2. Main resources:
- Gold: Gold is the primary resource in Warcraft. Gold is used to build new buildings, train units and research upgrades. Gold in neutral buildings is also used to buy mercenaries, hero items, or to enable special services.
- Wood: Similar to gold, wood is also one of the consuming resources for major activities. All races use wood to produce weapons and machines of many different structures required for warfare.
3. Building systems:
Buildings vary in cost, time and purpose. Town halls can train workers and store resources, some buildings can train combat units, and others can allow players to complete technology upgrades or unlock different types of units.
3. Operating system:
Select and move: Click on a unit or building with the left mouse button to view the corresponding status and commands that can be given. After selecting a unit, the player can command the unit by clicking the right mouse button to issue a movement command, or by clicking the button on the command panel at the bottom of the interface (or pressing the corresponding shortcut key).
Hold down the left mouse button and drag to pull out a rectangular box. Players can select multiple units in this way, which is also called "box selection". After selecting multiple units, the player can issue orders to all selected units at once. Players can also press the Tab key to cycle through the command panels for each unit.
Formation: After selecting multiple units or buildings, players can press Ctrl+any number key to form the selected units into a team. After the formation, the player only needs to press the number key to select the corresponding formation again.
Functional screenshot
Start the game:
Configuration:
start the game interface:
Game main interface:
Start a new game:
Start alone, start farming mode
Forest and Gold Mine:
Build Fortifications:
Attributes:
Code
Start the entry:
public class Main {
public static final String PROGRAM = "Warcraft java版";
public static final String VERSION = "1.0.0";
private static final long serialVersionUID = 1L;
private Main() {
}
public static Initializer initialize(boolean jar) {
if (jar) {
Media.loadFromJar(Main.class);
}
Engine.start(PROGRAM, VERSION, "ressources", true, Theme.SYSTEM);
return ENGINE.createInitializer(320, 200, 32, 60);
}
public static void main(String[] args) {
boolean jar = false;
try {
jar = Boolean.parseBoolean(args[0]);
} catch (Exception e) {
}
Launcher launcher = new Launcher(null, initialize(jar));
launcher.start();
}
}
ModelAttacker class:
/**
* Main abstraction representing any unit with the ability of attacking.
*/
public abstract class ModelAttacker extends ModelUnit implements AttackerAbility<Tile, ModelSkill, Attributes> {
private final List<AbstractEntry<Tile, ModelSkill, Attributes>> guards;
private int orderX, orderY;
private boolean assault, riposte;
private boolean defend;
private long guardTimer;
public ModelAttacker(Map map, RessourcesHandler rsch, MediaRessource<BufferedImage> rsc) {
super(map, rsch, rsc.file, rsc.ressource);
this.guards = new ArrayList<AbstractEntry<Tile, ModelSkill, Attributes>>(1);
this.damages.setMin(this.getDataInt("DMG_MIN"));
this.damages.setMax(this.getDataInt("DMG_MAX"));
this.riposte = true;
this.assault = false;
this.defend = false;
this.orderX = -1;
this.orderY = -1;
}
public void setDamages(int min, int max) {
this.damages.setMin(min);
this.damages.setMax(max);
}
@Override
public void update(Keyboard keyboard, Mouse mouse, float extrp) {
super.update(keyboard, mouse, extrp);
this.updateAttack(extrp);
if (this.isAlive() && (!this.hasTarget() || this.isMoving())) {
// Reset defense state when its over
if (this.isDefending() && !this.isAttacking()) {
this.defend = false;
this.assault = false;
}
// Check guard area when not defending & attacking or assault
if (!this.isDefending() && (this.assault || (!this.isAttacking() && !this.isMoving()))) {
if (Maths.time() - this.guardTimer > 500) {
if (this.player instanceof AI) {
this.guard();
} else {
if (!this.isMoving()) {
this.guard();
}
}
this.guardTimer = Maths.time();
}
}
}
}
@Override
public boolean assignDestination(int tx, int ty) {
boolean found = super.assignDestination(tx, ty);
if (this.orderX == -1 && this.assault) {
this.orderX = tx;
this.orderY = ty;
}
return found;
}
public void reAssignDestination() {
if (this.orderX != -1 && this.orderY != -1) {
this.stopAttack();
this.setTarget(null);
super.assignDestination(this.orderX, this.orderY);
} else {
this.stopAttack();
this.stopMoves();
}
}
@Override
public void stop() {
this.stopAttack();
super.stop();
}
protected void guard() {
int fov = this.getFieldOfView() - 1;
for (int v = this.getYInTile() - fov; v <= this.getYInTile() + fov; v++) {
for (int h = this.getXInTile() - fov; h <= this.getXInTile() + fov; h++) {
try {
int eid = this.map.getRef(v, h);
if (eid > 0 && eid != this.id) {
AbstractEntry<Tile, ModelSkill, Attributes> e = ModelUnit.get(eid);
if (e == null) {
e = ModelBuilding.get(eid);
}
if (e.isAlive() && e.isVisible() && e.getOwnerID() != this.getOwnerID() && e.getOwnerID() > 0 && e.isActive()) {
this.guards.add(e);
}
}
} catch (ArrayIndexOutOfBoundsException e) {
continue;
}
}
}
int min = Integer.MAX_VALUE;
AbstractEntry<Tile, ModelSkill, Attributes> closest = null;
for (AbstractEntry<Tile, ModelSkill, Attributes> e : this.guards) {
int dist = this.getDistance(e);
// Priority to unit
if (closest instanceof AbstractBuilding && e instanceof AbstractUnit) {
min = dist;
closest = e;
} else if (!(closest instanceof AbstractUnit && e instanceof AbstractBuilding) || closest == null) {
if (dist < min) {
min = dist;
closest = e;
}
}
}
this.guards.clear();
if (closest != null) {
this.guardAction(closest);
}
}
protected void guardAction(AbstractEntry<Tile, ModelSkill, Attributes> e) {
// Priority to attacker model
if (this.getTarget() instanceof ModelAttacker && !(e instanceof ModelAttacker)) {
return;
}
this.attack(e);
}
@Override
public void onHit(AbstractEntry<Tile, ModelSkill, Attributes> attacker) {
super.onHit(attacker);
if (this.isAlive() && this.riposte) {
// AI gives priority to unit riposte
if (attacker instanceof AbstractUnit && this.getTarget() instanceof AbstractBuilding && this.player instanceof AI) {
this.attack(attacker);
return;
}
// Keep closest target only
boolean closest = false;
if (this.hasTarget()) {
closest = this.getDistance(attacker) < this.getDistance(this.getTarget());
}
if ((this.hasTarget() || closest) && this.getOwnerID() != attacker.getOwnerID()) {
this.attack(attacker);
}
}
}
@Override
public void onKilled(AbstractEntry<Tile, ModelSkill, Attributes> attacker) {
if (this.assault) {
this.reAssignDestination();
}
}
public void setRiposte(boolean state) {
this.riposte = state;
}
public void setAssault(boolean state) {
this.assault = state;
}
public boolean getAssault() {
return this.assault;
}
public void setDefend(boolean state) {
this.defend = state;
}
public boolean isDefending() {
return this.defend;
}
@Override
public boolean isPassive() {
return super.isPassive() && !this.isAttacking();
}
public boolean hasTarget() {
return this.getTarget() != null;
}
}
ModelUnit class:
public abstract class ModelUnit extends AbstractUnit<Tile, ModelSkill, Attributes> {
private static final TreeMap<Integer, ModelUnit> ENTRYS = new TreeMap<Integer, ModelUnit>();
public static ModelUnit get(int id) {
return ENTRYS.get(id);
}
public static void clear() {
ENTRYS.clear();
}
public static List<ModelUnit> getByOwner(int ownerID) {
List<ModelUnit> list = new ArrayList<ModelUnit>(1);
Collection<ModelUnit> c = ENTRYS.values();
for (ModelUnit u : c) {
if (u.getOwnerID() == ownerID) {
list.add(u);
}
}
return list;
}
private void manage() {
ENTRYS.put(this.id, this);
}
private static final int CORPSE_TIME = 5000;
private static final int CORPSE_NUMBER = 3;
private static final int CORPSE_OFFSET = 8;
private static final Orientation[] orientations = Orientation.values();
public final Map map;
public final UnitType type;
public final Race faction;
protected Player player;
private boolean isOnScreen;
private TiledSprite corpse;
private long deadTimer, angleTimer, nextAngleTimer;
private boolean dead;
private int deadIndex, deadOffset;
public ModelUnit(Map map, RessourcesHandler rsch, String data, BufferedImage surface) {
super(data, map, surface, new Attributes());
this.map = map;
this.type = UnitType.valueOf(this.getDataString("TYPE").toUpperCase());
this.setFieldOfView(this.getDataInt("FOV"));
this.setFrame(this.getDataInt("DEFAULT_FRAME"));
this.setSkipLastFrameOnReverse(true);
this.faction = Race.valueOf(this.getDataString("FACTION").toLowerCase());
this.life.setMax(this.getDataInt("MAX_LIFE"));
this.life.set(this.life.getMax());
this.addSkill(new Move(0, this));
this.addSkill(new Stop(1, this));
this.setSpeed(1.5f, 1.5f);
this.setLayer(2);
this.corpse = Drawable.DRAWABLE.loadTiledSprite(rsch.get("CORPSE").ressource, 32, 32);
this.corpse.load(false);
this.deadTimer = -1L;
this.dead = false;
this.deadIndex = 0;
if (this.faction == Race.orcs) {
this.deadOffset = 8;
} else {
this.deadOffset = 0;
}
this.map.fogOfWar.updateEntryFOV(this);
this.angleTimer = Maths.time();
this.nextAngleTimer = Maths.random(0, 2000) + 5000L;
this.manage();
}
@Override
public void place(int tx, int ty) {
super.place(tx, ty);
this.map.fogOfWar.updateEntryFOV(this);
}
@Override
public void update(Keyboard keyboard, Mouse mouse, float extrp) {
int otx = this.getXInTile();
int oty = this.getYInTile();
super.update(keyboard, mouse, extrp);
// Apply mirror depending of the orientation
Orientation o = this.getOrientation();
if (o.ordinal() > 4) {
if (!this.getMirror()) {
this.mirror(true);
}
} else {
if (this.getMirror()) {
this.mirror(false);
}
}
if (!this.isAlive()) {
// Handle dead corps effect
if (!this.dead) {
if (this.deadTimer == -1L) {
this.deadTimer = Maths.time();
}
if (Maths.time() - this.deadTimer > CORPSE_TIME) {
this.setVisibility(false);
this.dead = true;
this.deadIndex = 0;
this.deadTimer = Maths.time();
}
} else {
if (this.deadIndex <= CORPSE_NUMBER && Maths.time() - this.deadTimer > CORPSE_TIME) {
this.deadIndex++;
this.deadTimer = Maths.time();
}
}
if (this.deadIndex > CORPSE_NUMBER) {
this.remove();
}
} else {
// Update fog when unit moved
if (otx != this.getXInTile() || oty != this.getYInTile()) {
this.map.fogOfWar.updateEntryFOV(this);
}
// Apply a random angle unit entry is still idle too much time
if (this.isPassive() && Maths.time() - this.angleTimer > this.nextAngleTimer) {
this.setAnimation("IDLE");
this.setOrientation(orientations[Maths.random(0, orientations.length - 1)]);
this.angleTimer = Maths.time();
this.nextAngleTimer = Maths.random(0, 2000) + 5000L;
}
}
if (this.animName != null) {
CollisionArea area = this.getCollArea(this.animName);
this.updateCollision(area.getX(), area.getY(), area.getWidth(), area.getHeight());
} else {
this.updateCollision(16, 16, 0, 0);
}
}
@Override
public void render(Graphics2D g, Camera camera) {
super.render(g, camera);
if (this.dead && this.deadIndex <= CORPSE_NUMBER) {
int o = 0;
if (this.getOrientation().ordinal() > 0) {
o = 4;
}
this.corpse.render(g, this.deadIndex + this.deadOffset + o, this.getX() - camera.getX() - CORPSE_OFFSET,
this.getY() - camera.getY() - CORPSE_OFFSET);
}
if (this.getX() >= camera.getX() && this.getX() <= camera.getX() + 320 && this.getY() >= camera.getY() && this.getY() <= camera.getY() + 200) {
this.isOnScreen = true;
} else {
this.isOnScreen = false;
}
}
@Override
public void setOwnerID(int id) {
super.setOwnerID(id);
if (id > 0) {
this.player = (Player) AbstractPlayer.get(id);
}
}
public Player player() {
return this.player;
}
@Override
public void stop() {
super.stop();
this.clearIgnoredID();
this.angleTimer = Maths.time();
}
@Override
public void onStartMove() {
this.setAnimation("MOVE");
}
@Override
public void onMove() {
if (!this.animName.equals("MOVE")) {
this.setAnimation("MOVE");
}
}
@Override
public void onArrived() {
this.setAnimation("IDLE");
this.angleTimer = Maths.time();
}
@Override
public void onDied() {
if (this.getOrientation().ordinal() < 4) {
this.setOrientation(Orientation.NORTH);
} else {
this.setOrientation(Orientation.NORTH_EAST);
}
this.setAnimation("DIE");
this.player.removeUnit(this);
if (this.isOnScreen()) {
ControlPanel.playSfx(0, this.faction, SFX.die);
}
}
@Override
public void onSelection() {
ControlPanel.playSfx(this.getOwnerID(), this.faction, SFX.select);
}
@Override
public void onOrderedFail(ModelSkill skill) {
}
@Override
public void onKilled(AbstractEntry<Tile, ModelSkill, Attributes> attacker) {
}
public boolean isPassive() {
return !this.isMoving();
}
public boolean isOnScreen() {
return this.isOnScreen;
}
}
Summarize
Through the implementation of the "warcraft java version" game, I have a further understanding of the relevant knowledge of swing, and a deeper understanding of the java language than before.
Some basic grammars of java, such as data types, operators, program flow control and arrays, are more thoroughly understood. The core of java is the object-oriented idea, and finally realized something about this concept.
Source code acquisition
After following the blogger, you can privately chat with the blogger to get it for free. If
you need technical guidance, write project programs, and more services, please contact the blogger
Today is the 33rd /100th day of continuous writing .
You can follow me, like me, comment me, bookmark me.