/******************************************************************************* * Copyright 2013 Pawel Pastuszak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package pl.kotcrab.gdxcombat.fighters; import pl.kotcrab.gdxcombat.Assets; import pl.kotcrab.gdxcombat.fighters.ai.BotInterface; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.g2d.Animation; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.PolygonShape; import com.badlogic.gdx.physics.box2d.World; public abstract class AbstractFighter { public enum State { IDLE, LEFT, RIGHT, JUMP, DUCK, PUNCH, HIT, KICK, END, BLOCK } private AbstractFighter oponent; // przeciwnik private static final int movementForceAmount = 4; // predkosc poruszania sie protected TextureRegion texture; // jedna klatka z g�ownej animacji dla oblicze� box2d protected Sound winsSound; // dzwiek odtwarzany przy wygraniu // Animacje protected Animation currentAnim; // aktualna animacja protected Animation stanceAnim; // idle protected Animation walkAnim; // chodzenie protected Animation jumpAnim; // skok w gore protected Animation jumpFAnim; // skok na boki protected Animation duckAnim; // kucanie protected Animation punchAnim; // piesci protected Animation kickAnim; // kopniak protected Animation hitAnim; // gdy uderzony protected Animation blockAnim; // blok protected Animation winAnim; // przy wygraniu protected Animation loseAnim; // przy przegraniu private float stateTime; // czas aktualnej animacji private boolean blockedAnim; // zmienna u�ywane przez niekt�re animacje private int groundLevel; // poziom pod�ogi private boolean player = false; // czy ten obiekt jest sterowany przez gracza private BotInterface bot; protected float x, y; protected Body body; private int health = 100; // �ycie // Klawisze private static final int KEY_JUMP = 0; private static final int KEY_DUCK = 1; private static final int KEY_LEFT = 2; private static final int KEY_RIGHT = 3; private static final int KEY_PUNCH = 4; private static final int KEY_KICK = 5; private static final int KEY_BLOCK = 6; private boolean[] keys = { false, false, false, false, false, false, false }; private State state = State.IDLE; long startTime; // dla cios�w public abstract String getName(); public AbstractFighter(boolean player) { this.player = player; } public void render(SpriteBatch batch) { if (!player && (state == State.PUNCH || state == State.KICK)) batch.draw(currentAnim.getKeyFrame(stateTime), x - 30, y); else batch.draw(currentAnim.getKeyFrame(stateTime), x, y); } public void update() { stateTime += Gdx.graphics.getDeltaTime(); switch (state) { case IDLE: stateIdle(); break; case RIGHT: stateRight(); break; case LEFT: stateLeft(); break; case JUMP: stateJump(); break; case DUCK: stateDuck(); break; case PUNCH: statePunch(); break; case KICK: stateKick(); break; case HIT: stateHit(); break; case BLOCK: stateBlock(); break; default: break; } if (bot != null) bot.update(keys, this, oponent); x = body.getPosition().x * 10 - texture.getRegionWidth() / 2; y = body.getPosition().y * 10 - texture.getRegionHeight() / 2; } private void stateRight() { if (keys[KEY_RIGHT]) { body.setLinearVelocity(movementForceAmount, body.getLinearVelocity().y); } else { state = State.IDLE; switchAnimation(stanceAnim); } if (keys[KEY_JUMP] && isOnGround()) { state = State.JUMP; switchAnimation(jumpFAnim); if (player) jumpFAnim.setPlayMode(Animation.LOOP); else jumpFAnim.setPlayMode(Animation.LOOP_REVERSED); body.applyLinearImpulse(new Vector2(0, 2300), body.getWorldCenter(), true); return; } } private void stateLeft() { if (keys[KEY_LEFT]) { body.setLinearVelocity(-1 * movementForceAmount, body.getLinearVelocity().y); } else { state = State.IDLE; switchAnimation(stanceAnim); } if (keys[KEY_JUMP] && isOnGround()) { state = State.JUMP; switchAnimation(jumpFAnim); if (player) jumpFAnim.setPlayMode(Animation.LOOP_REVERSED); else jumpFAnim.setPlayMode(Animation.LOOP); body.applyLinearImpulse(new Vector2(0, 2300), body.getWorldCenter(), true); return; } } private void stateDuck() { if (blockedAnim && duckAnim.isAnimationFinished(stateTime)) { state = State.IDLE; switchAnimation(stanceAnim); blockedAnim = false; return; } if (blockedAnim) return; if (!keys[KEY_DUCK]) { switchAnimation(duckAnim); duckAnim.setPlayMode(Animation.REVERSED); blockedAnim = true; return; } } private void stateBlock() { if (blockedAnim && blockAnim.isAnimationFinished(stateTime)) { state = State.IDLE; switchAnimation(stanceAnim); blockedAnim = false; return; } if (blockedAnim) return; if (!keys[KEY_BLOCK]) { switchAnimation(blockAnim); blockAnim.setPlayMode(Animation.REVERSED); blockedAnim = true; return; } } private void statePunch() { if (!keys[KEY_PUNCH]) { state = State.IDLE; switchAnimation(stanceAnim); return; } if (System.currentTimeMillis() - startTime > 400) { startTime = System.currentTimeMillis(); if (isOponentInRange()) { oponent.hit(5); isOponentDead(); } } } private void stateKick() { if (currentAnim.isAnimationFinished(stateTime) && !blockedAnim) { blockedAnim = true; currentAnim.setPlayMode(Animation.REVERSED); switchAnimation(currentAnim); if (isOponentInRange()) { oponent.hit(10); isOponentDead(); } return; } if (currentAnim.isAnimationFinished(stateTime) && blockedAnim) { blockedAnim = false; state = State.IDLE; switchAnimation(stanceAnim); } } private void stateJump() { if (isOnGround() && body.getLinearVelocity().y == 0) { state = State.IDLE; switchAnimation(stanceAnim); } } private void stateHit() { if (currentAnim.isAnimationFinished(stateTime)) { state = State.IDLE; switchAnimation(stanceAnim); } } private void stateIdle() { if (keys[KEY_LEFT]) { state = State.LEFT; switchAnimation(walkAnim); if (player) walkAnim.setPlayMode(Animation.LOOP_REVERSED); else walkAnim.setPlayMode(Animation.LOOP); return; } if (keys[KEY_RIGHT]) { state = State.RIGHT; switchAnimation(walkAnim); if (player) walkAnim.setPlayMode(Animation.LOOP); else walkAnim.setPlayMode(Animation.LOOP_REVERSED); return; } if (keys[KEY_DUCK]) { state = State.DUCK; switchAnimation(duckAnim); duckAnim.setPlayMode(Animation.NORMAL); return; } if (keys[KEY_BLOCK]) { state = State.BLOCK; switchAnimation(blockAnim); blockAnim.setPlayMode(Animation.NORMAL); return; } if (keys[KEY_PUNCH]) { state = State.PUNCH; switchAnimation(punchAnim); startTime = System.currentTimeMillis(); return; } if (keys[KEY_JUMP] && isOnGround()) { state = State.JUMP; switchAnimation(jumpAnim); jumpAnim.setPlayMode(Animation.NORMAL); body.setLinearVelocity(0, 0); body.applyLinearImpulse(new Vector2(0, 2300), body.getWorldCenter(), true); return; } if (keys[KEY_KICK]) { state = State.KICK; kickAnim.setPlayMode(Animation.NORMAL); switchAnimation(kickAnim); } } public void switchAnimation(Animation newAnim) { currentAnim = newAnim; stateTime = 0; } public void hit(int damage) { if (state == State.JUMP || state == State.DUCK) { // 2 return; } Assets.getRandomHitSound().play(); // 1 if (bot != null) // 3 bot.beingHit(keys, this); if (state == State.BLOCK) { // 4 damage /= 2; } health -= damage; // 5 if (health > 0) { // 6 state = State.HIT; switchAnimation(hitAnim); } else { state = State.END; switchAnimation(loseAnim); } } public void initPhys(World world) { BodyDef bodyDef = new BodyDef(); bodyDef.type = BodyType.DynamicBody; bodyDef.position.set((x + texture.getRegionWidth()) / 10f, (y + texture.getRegionHeight()) / 10f); // samo x i y oznaczalo by dolny lewy rog sprite'a body = world.createBody(bodyDef); body.setFixedRotation(true); PolygonShape shape = new PolygonShape(); shape.setAsBox(76 / 2 / 10f, 136 / 2 / 10f); FixtureDef fixtureDef = new FixtureDef(); fixtureDef.shape = shape; fixtureDef.density = 1f; fixtureDef.friction = 100f; // w og�le nie bedzie sie slizgac fixtureDef.restitution = 0f; body.createFixture(fixtureDef); shape.dispose(); } public void initAi(BotInterface bot) { this.bot = bot; } public boolean isOponentInRange() { int distance = (int) Math.abs(x - oponent.getX()); return distance < 86; } private void isOponentDead() { if (oponent.getHealth() <= 0) { state = State.END; switchAnimation(winAnim); } } private boolean isOnGround() { return y < groundLevel; } public boolean isCurrentAnimFinished() { return currentAnim.isAnimationFinished(stateTime); } public void setGroundLevel(int groundLevel) { this.groundLevel = groundLevel; } public void setOponent(final AbstractFighter oponent) { this.oponent = oponent; } public State getState() { return state; } public void setState(State state) { this.state = state; } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public void setPosition(float x, float y) { this.x = x; this.y = y; } public int getWidth() { return texture.getRegionHeight(); } public int getHeight() { return texture.getRegionHeight(); } public Sound getWinsSound() { return winsSound; } public int getHealth() { return health; } public void keyDown(int key) { if (player) { switch (key) { case Keys.UP: keys[KEY_JUMP] = true; break; case Keys.DOWN: keys[KEY_DUCK] = true; break; case Keys.LEFT: keys[KEY_LEFT] = true; break; case Keys.RIGHT: keys[KEY_RIGHT] = true; break; case Keys.A: keys[KEY_PUNCH] = true; break; case Keys.S: keys[KEY_KICK] = true; break; case Keys.Q: keys[KEY_BLOCK] = true; break; default: break; } } } public void keyUp(int key) { if (player) { switch (key) { case Keys.UP: keys[KEY_JUMP] = false; break; case Keys.DOWN: keys[KEY_DUCK] = false; break; case Keys.LEFT: keys[KEY_LEFT] = false; break; case Keys.RIGHT: keys[KEY_RIGHT] = false; break; case Keys.A: keys[KEY_PUNCH] = false; break; case Keys.S: keys[KEY_KICK] = false; break; case Keys.Q: keys[KEY_BLOCK] = false; break; default: break; } } } public void dispose() { } }