JAVA implementa el juego "warcraft versión java"

prefacio

Rindiendo homenaje al clásico warcraft, la "versión java de warcraft" es un juego independiente de estrategia en tiempo real que utiliza el estilo y la mecánica originales de Warcraft. Reúne recursos, construye fortificaciones y destruye todas las tropas enemigas.
Humanos: La Alianza Humana de Lordaeron se formó desde que los orcos cruzaron por primera vez el Portal Oscuro. Son tenaces, valientes e intrépidos, visten armaduras fuertes y empuñan cuchillas afiladas, se enfrentan al enemigo con valentía.
Orcos: los orcos son una raza robusta y dura conocida por su estilo de lucha temerario y feroz, que visten pieles simples y armaduras de cuero con púas.

Está implementado en lenguaje java, utilizando tecnología swing para el procesamiento de la interfaz, y la idea de diseño utiliza el pensamiento orientado a objetos.

principales necesidades

1. Los jugadores pueden elegir sus propios campamentos: los humanos y los orcos pueden elegir entre dos campamentos.
2. Principales recursos:

  • Oro: El oro es el principal recurso en Warcraft. El oro se usa para construir nuevos edificios, entrenar unidades e investigar mejoras. El oro en edificios neutrales también se usa para comprar mercenarios, artículos de héroe o para habilitar servicios especiales.
  • Madera: Al igual que el oro, la madera también es uno de los recursos de consumo para las principales actividades. Todas las razas utilizan la madera para producir armas y máquinas de diferentes estructuras necesarias para la guerra.

3. Sistemas de construcción:
Los edificios varían en costo, tiempo y propósito. Los ayuntamientos pueden entrenar trabajadores y almacenar recursos, algunos edificios pueden entrenar unidades de combate y otros pueden permitir a los jugadores completar actualizaciones tecnológicas o desbloquear diferentes tipos de unidades.

3. Sistema operativo:

Seleccionar y mover: haz clic en una unidad o edificio con el botón izquierdo del ratón para ver el estado correspondiente y los comandos que se pueden dar. Después de seleccionar una unidad, el jugador puede comandar la unidad haciendo clic con el botón derecho del mouse para emitir un comando de movimiento, o haciendo clic en el botón del panel de comandos en la parte inferior de la interfaz (o presionando la tecla de acceso directo correspondiente).
Mantenga presionado el botón izquierdo del mouse y arrastre para sacar un cuadro rectangular. Los jugadores pueden seleccionar varias unidades de esta manera, lo que también se denomina "selección de cuadro". Después de seleccionar varias unidades, el jugador puede dar órdenes a todas las unidades seleccionadas a la vez. Los jugadores también pueden presionar la tecla Tab para recorrer los paneles de comando de cada unidad.
Formación: después de seleccionar varias unidades o edificios, los jugadores pueden presionar Ctrl+cualquier tecla numérica para formar un equipo con las unidades seleccionadas. Después de la formación, el jugador solo necesita presionar la tecla numérica para seleccionar nuevamente la formación correspondiente.

Captura de pantalla funcional

Comenzar el juego:
inserte la descripción de la imagen aquí

Configuración:
inserte la descripción de la imagen aquí
inicie la interfaz del juego:
inserte la descripción de la imagen aquí

Interfaz principal del juego:
inserte la descripción de la imagen aquí

Iniciar un nuevo juego:
inserte la descripción de la imagen aquí

Comience solo, comience el modo de cultivo
inserte la descripción de la imagen aquí
Bosque y mina de oro:
inserte la descripción de la imagen aquí
Construya fortificaciones:
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Atributos:
inserte la descripción de la imagen aquí

Código

Inicie la entrada:


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();
    }
}



Clase ModelAttacker:



/**
 * 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;
    }
}

Clase de unidad de modelo:



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;
    }
}

Resumir

A través de la implementación del juego "warcraft java version", tengo una mayor comprensión del conocimiento relevante del swing y una comprensión más profunda del lenguaje java que antes.

Algunas gramáticas básicas de Java, como tipos de datos, operadores, control de flujo de programas y matrices, se comprenden mejor. El núcleo de Java es la idea orientada a objetos, y finalmente se dio cuenta de algo acerca de este concepto.

Adquisición de código fuente

Después de seguir al blogger, puede chatear en privado con el blogger para obtenerlo gratis. Si
necesita orientación técnica, escribir programas de proyectos y más servicios, comuníquese con el blogger.

Hoy es el día 33/100 de escritura continua .
Puedes seguirme , dar me gusta , comentarme , marcarme .

Supongo que te gusta

Origin blog.csdn.net/qq_40869977/article/details/127040239
Recomendado
Clasificación