package com.me.skifun.model; import java.util.ArrayList; import java.util.Map; import java.util.Random; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Pool; import com.me.skifun.NextpeerPlugin; import com.me.skifun.P2PMessage; import com.me.skifun.P2PMessage.PlayerPosition; import com.me.skifun.P2PMessage.PlayerScore; import com.me.skifun.model.Bob.State; import com.me.skifun.model.Rocks.Rock; import com.me.skifun.model.Trees.PineHigh; import com.me.skifun.model.Trees.PineLow; import com.me.skifun.model.Trees.PineMid; import com.me.skifun.model.Trees.Tree; import com.nextpeer.libgdx.NextpeerTournamentCustomMessage; /** * The main game's world. The total game's environment. */ public class World { /** The player **/ Bob bob; /** Constants **/ public static float WORLD_WIDTH = 5; public static float WORLD_HEIGHT = 7*200 ; public static final int WORLD_STATE_RUNNING = 0; public static final int WORLD_STATE_GAME_OVER = 2; /** The world's state **/ public int state; /** The world's bounds **/ static final float BOUND_x = 5f; static final float BOUND_Y = 7f; /** ArrayLists and Pools of objects **/ public final ArrayList<Tree> trees; public final Pool<Tree> treesPool; public final ArrayList<Rock> rocks; public final Pool<Rock> rocksPool; public final ArrayList<Platform> platforms; public final Pool<Platform> platformsPool; public final ArrayList<CableCar> cableCars; public final Pool<CableCar> cableCarsPool; public final ArrayList<LiftPole> poles; public final Pool<LiftPole> polesPool; public final ArrayList<Hill> hills=null; public final Pool<Hill> hillsPool=null; public final ArrayList<GameObject> objects; /** The position last updated **/ public float lastUpdatePosition; /** Random class **/ public final Random rand; /** The player's score **/ public int score; /** How often to send data to the other players * on the multiplayer game */ public float deltaUpdateInterval=0.2f; public float interval=0; // The timer used in this section. /** The score of the player when the last yeti showed up **/ public double lastYeti=0; /** Maps of the opponents players **/ public Map<String, PlayerInfoPackage> opponents; // Contains the opponents positions at first public Map<String,PlayerInfoPackage> opponents2; // Contains the opponents positions after deltaUpdateInterval time /** Opponents flag. Used to know to which map we should insert the position. **/ public int flagOp; /** notesString is a vector of strings which contains data of the player on the multiplayer mode * being showed on the screen. */ public Vector<String> notesString; public float heartBeatTime=0; public boolean gameShouldBeOver=false; public float stateTime=0; public int lastMeters=0; /// 5 X 7 world public Bob getBob() { return bob; } public World() { /** * Constructor */ createDemoWorld(); opponents= new ConcurrentHashMap<String,PlayerInfoPackage>(); opponents2= new ConcurrentHashMap<String,PlayerInfoPackage>(); flagOp=0; notesString=new Vector<String>(); objects= new ArrayList<GameObject>(); this.trees=null; treesPool= new Pool<Tree>() { @Override protected Tree newObject() { int x= rand.nextInt(3); if (x==0) return new PineLow(); else if (x==1) return new PineMid(); else return new PineHigh(); } }; this.rocks=null; rocksPool= new Pool<Rock>() { @Override protected Rock newObject() { int x= rand.nextInt(3); return new Rock(x); } }; this.platforms=null; platformsPool= new Pool<Platform>() { @Override protected Platform newObject() { return new Platform(); } }; this.cableCars=null; cableCarsPool= new Pool<CableCar>() { @Override protected CableCar newObject() { return new CableCar(); } }; this.poles=null; polesPool= new Pool<LiftPole>() { @Override protected LiftPole newObject() { return new LiftPole(); } }; if (NextpeerPlugin.isAvailable()) { rand= new Random(NextpeerPlugin.instance().lastKnownTournamentRandomSeed); } else { rand= new Random(); } generateLevel(-4); // generate the world objects score=0; } private void createDemoWorld() { /** * Create the world. */ float x; if (NextpeerPlugin.isCurrentlyInTournament()) { // if its a multiplayer mode then the player will be drawn on random position of the x axis Random randPositionX= new Random(); x= randPositionX.nextInt(5)+0.5f; } else { // else, it will be drawn on the middle of the screen x=2.5f; } bob = new Bob(new Vector2(x, 5f)); PlayerPosition msg = new PlayerPosition(bob.getPosition().x,bob.getPosition().y,0); try{ // Nextpeer has two different means to push data to the other players, reliable and unreliable. // Unreliable is faster, but you'll usually have around 1-5% message lost. // Reliable is slower, but each message that you'll send will get to the other players. // You should use the unreliable protocol for messages that your game can do without for a few frames. For example, player positions. // Use the reliable protocol for messages that your game cannot do without, for example information about the name of the player. NextpeerPlugin.unreliablePushDataToOtherPlayers(msg.encode()); } catch(Exception e) { e.printStackTrace(); } } public void update(float deltaTime, float accelerometerX) { /** * Updates the game's world. */ interval+=deltaTime; heartBeatTime+=deltaTime; if (heartBeatTime>10 && NextpeerPlugin.isCurrentlyInTournament()) gameShouldBeOver=true; if (!bob.isBobDead()) {checkCollisions();} score=bob.getMeters(); deleteObjects(false); updateObjects(deltaTime); if (!(Bob.state==Bob.State.DYING||Bob.state==Bob.State.DEAD)) { bob.setState(State.SKIING); float vel=-accelerometerX/4*Bob.SPEED; if (Math.abs(vel)<0.05f) bob.velocity.x=0; else { if (stateTime<4) bob.velocity.x = -accelerometerX/5 * Bob.SPEED; else bob.velocity.x= -accelerometerX/4*Bob.SPEED; } if (bob.velocity.x>0.3f) { bob.setFacingRight(true); bob.setFacingLeft(false); } else if (bob.velocity.x<-0.3f) { bob.setFacingRight(false); bob.setFacingLeft(true); } else if (Math.abs(bob.velocity.x)<0.1f) { bob.setFacingRight(false); bob.setFacingLeft(false); } } updateOpponents(deltaTime); updateBob(deltaTime); stateTime+=deltaTime; } public void pause () { deleteObjects(false); } public void updateOpponents (float delta) { /** * Updating the Opponents data, in order to draw * a vector between the first and last position of the opponents. */ Map<String,PlayerInfoPackage> map= opponents; Map<String,PlayerInfoPackage> map2= opponents2; for (Map.Entry<String, PlayerInfoPackage> entry : map.entrySet()) { /** * Iterates over the two maps entries */ for (Map.Entry<String,PlayerInfoPackage> entry2: map2.entrySet()) { if (entry.getKey().equals(entry2.getKey())) // searching for the player who appears in both. { /** * Get the location of the opponent */ float x1=entry.getValue().getPosition().x; float x2=entry2.getValue().getPosition().x; float y1=entry.getValue().getPosition().y; float y2=entry2.getValue().getPosition().y; /** * Calculate the velocity of the opponent */ float deltaY=y2-y1; float speedY=deltaY/(deltaUpdateInterval); float deltaX=x2-x1; float speedX=deltaX/(deltaUpdateInterval); /** * Booleans */ boolean right=false; boolean left=false; /*boolean downSpeed=false; if (Math.abs(speedY)>1.7f) { downSpeed=true; }*/ if (x2>x1+0.1f) { right=true; left=false; } else if (x2<x1-0.1f) { right=false; left=true; } else { right=false; left=false; } Vector2 newPos= new Vector2(x1,y1); // The last position of the opponent Vector2 velocity= new Vector2(speedX,speedY); // The velocity of the opponent if (x1!=x2||y1!=y2) { newPos.add(velocity.cpy().scl(delta)); // update the position } /** Create an info package **/ PlayerInfoPackage p; p= new PlayerInfoPackage(newPos, entry.getValue().getState(),right,left,false,entry.getValue().playerName); /** Put the updated info package in the first map **/ opponents.put(entry.getKey(),p); } } } } public void updateObjects (float delta) { /** * Update the game objects */ int len= objects.size(); for (int i=len-1;i>=0;i--) { GameObject object= objects.get(i); object.update(delta); if (!object.alive) { objects.remove(i); if (object instanceof Tree) { treesPool.free((Tree) object); } else if (object instanceof Rock) { rocksPool.free((Rock) object); } else if (object instanceof Platform) { platformsPool.free((Platform) object); } else if (object instanceof LiftPole) { polesPool.free((LiftPole)object); } else if (object instanceof Hill) { hillsPool.free((Hill)object); } else if (object instanceof CableCar) { cableCarsPool.free((CableCar)object); } } } } public void updateBob(float delta) { /** * Update the player */ bob.update(delta); if (bob.getPosition().y<=lastUpdatePosition-94) { // check if we should generate new obstacles generateLevel(6); deleteObjects(false); } if (bob.meters-lastMeters>5000 && NextpeerPlugin.isCurrentlyInTournament()) { /** * Send info of the player's score every a few meters */ PlayerScore msg= new PlayerScore(bob.meters-bob.meters%1000); try{ // Nextpeer has two different means to push data to the other players, reliable and unreliable. // Unreliable is faster, but you'll usually have around 1-5% message lost. // Reliable is slower, but each message that you'll send will get to the other players. // You should use the unreliable protocol for messages that your game can do without for a few frames. For example, player positions. // Use the reliable protocol for messages that your game cannot do without, for example information about the name of the player. NextpeerPlugin.unreliablePushDataToOtherPlayers(msg.encode()); } catch(Exception e) { e.printStackTrace(); } lastMeters=bob.meters; } float state1; if (Bob.state==Bob.State.DEAD) state1=2; else if (Bob.state==Bob.State.DYING) state1=1; else if (bob.isGodMode()) state1=3; else state1=0; /** * Send info of the player position every deltaUpdateInterval seconds. */ PlayerPosition msg = new PlayerPosition(bob.getPosition().x,bob.getPosition().y,state1); if (interval>=deltaUpdateInterval) { try{ // Nextpeer has two different means to push data to the other players, reliable and unreliable. // Unreliable is faster, but you'll usually have around 1-5% message lost. // Reliable is slower, but each message that you'll send will get to the other players. // You should use the unreliable protocol for messages that your game can do without for a few frames. For example, player positions. // Use the reliable protocol for messages that your game cannot do without, for example information about the name of the player. NextpeerPlugin.unreliablePushDataToOtherPlayers(msg.encode()); } catch(Exception e) { e.printStackTrace(); } interval=0; } /** * If bob is dead send an update */ if (Bob.state==Bob.State.DEAD) { try{ // Nextpeer has two different means to push data to the other players, reliable and unreliable. // Unreliable is faster, but you'll usually have around 1-5% message lost. // Reliable is slower, but each message that you'll send will get to the other players. // You should use the unreliable protocol for messages that your game can do without for a few frames. For example, player positions. // Use the reliable protocol for messages that your game cannot do without, for example information about the name of the player. NextpeerPlugin.unreliablePushDataToOtherPlayers(msg.encode()); } catch(Exception e) { e.printStackTrace(); } state=WORLD_STATE_GAME_OVER; } } private void deleteObjects (boolean all) { /** * Delete unused objects */ int len= objects.size(); for (int i=0;i<len;i++) { GameObject object= objects.get(i); if (all||bob.position.y<object.position.y-2.4f) { object.alive=false; } } } private void generateLevel (int p) { /** * Generate the game's objects every P distance from the last bob update position */ generateBonuses(p); generateObstacles(p); lastUpdatePosition=bob.getPosition().y; } public void generateBonuses(int p) { /** * Generate the game's bonuses */ generatePlatforms(p); } public void generatePlatforms(int p) { /** * Generate the game's platforms */ float y = bob.position.y-p; while (y > bob.position.y - 100 && y<300) { float x = rand.nextFloat() * (WORLD_WIDTH - PineLow.WIDTH); Platform platform= platformsPool.obtain(); platform.init(x,y); objects.add(platform); y -= 4.8f; y += rand.nextFloat() * (0.3); } } private void generateObstacles(int p) { /** * Generate the game's obstacles */ generateRocks(p); generateTrees(p); generateCableCars(p); generateLiftPoles(p); } private void generateTrees (int p) { /** * Generate the game's treess */ float y = bob.position.y-p; if (y>5.3f) { y=5.3f; } while (y > bob.position.y - 100) { float x1 = rand.nextFloat() * (WORLD_WIDTH - PineLow.WIDTH);// + Tree.SIZE / 2; float x2 = rand.nextFloat() * (WORLD_WIDTH - PineLow.WIDTH);// + Tree.SIZE / 2; Tree tree=treesPool.obtain(); Tree tree2= treesPool.obtain(); tree.init(x1,y); tree2.init(x2+0.2f,y); objects.add(tree); objects.add(tree2); y -= 1.9f; y += rand.nextFloat() * (0.3); } } private void generateRocks (int p) { /** * Generate the rocks */ float y = bob.position.y-p; if (y>5.3f) { y=5.3f; } while (y > bob.position.y - 100) { float x = rand.nextFloat() * (WORLD_WIDTH - Rock.WIDTH);// + Tree.SIZE / 2; Rock rock=rocksPool.obtain(); rock.init(x,y); objects.add(rock); // y -= 2.7f; y += rand.nextFloat() * (0.3); } } private void generateLiftPoles(int p) { /** * Generate the lift poles */ float y = bob.position.y-p; if (y>5.3f) { y=5.3f; } while (y > bob.position.y - 100) { float x = rand.nextFloat() * (WORLD_WIDTH - LiftPole.WIDTH); LiftPole pole=polesPool.obtain(); pole.init(x,y); objects.add(pole); y -= 7f; y += rand.nextFloat() * (0.3); } } /***/ private void generateCableCars (int p) { /** * Generate the cable cars */ float y = bob.position.y-p; if (y>5.3f) { y=5.3f; } while (y > bob.position.y - 100) { float x = rand.nextFloat() * (WORLD_WIDTH - CableCar.WIDTH); CableCar cable=cableCarsPool.obtain(); cable.init(x,y); objects.add(cable); y -= 15f; y += rand.nextFloat() * (0.3); } } private void checkObjectsCollisions() { /** * Check for collisions between bob and the game's obstacles */ int len =objects.size(); Rectangle bobRect= new Rectangle(bob.position.x,bob.position.y,bob.bounds.width,bob.bounds.height); Rectangle objectRect= new Rectangle(); for (int i=0;i<len;i++) { /** * Iterate over the obstacles ArrayList */ GameObject object= objects.get(i); objectRect.x=object.position.x; objectRect.y=object.position.y; objectRect.width=object.bounds.width; objectRect.height=object.bounds.height; if (OverlapTester.overlapRectangles(bobRect,objectRect)) { { // if there is a collision if (object instanceof Platform) { if (!bob.isJumpMode()) bob.jumpMode(); else { break; } } else { bob.hit(); } break; } } } } private void checkCollisions() { /** * Check for collisions */ checkObjectsCollisions(); } public void onReceiveTournamentCustomMessage(NextpeerTournamentCustomMessage message) { // Try to decode the custom message P2PMessage msg = P2PMessage.tryToDecodeOrNull(message.customMessage); if (msg != null) { String name=message.playerName; if (name.length()>8) { // shorten the name of the player name=name.substring(0,5); name+=".."; } switch(msg.type) { case P2PMessage.Types.PLAYER_POSITION: { PlayerPosition positionMsg = (PlayerPosition)msg; Vector2 opponentPosition=new Vector2 (positionMsg.x,positionMsg.y); float state= positionMsg.state; /** Creates a pack according to the message **/ PlayerInfoPackage pack= new PlayerInfoPackage(opponentPosition,state,false,false,false,message.playerName); if (opponents.get(message.playerId) == null) opponents.put(message.playerId,pack); else { if (opponents2.get(message.playerId)!=null) { Vector2 op=opponents2.get(message.playerId).getPosition(); if (!(op.x==opponentPosition.x&&op.y==opponentPosition.y)) { if (state==1) // hit { notesString.add(name+" got hit\n"); } else if (state==2) // dead { notesString.add(name+" died\n"); } } } opponents2.put(message.playerId,pack); } heartBeatTime=0; flagOp=1; } break; case P2PMessage.Types.PLAYER_SCORE: { PlayerScore playerScore= (PlayerScore)msg; int score= playerScore.score; notesString.add(name+":"+score+" ps"); } break; default: break; } } } }