1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package jme3test.games;
34
35import com.jme3.app.SimpleApplication;
36import com.jme3.bounding.BoundingVolume;
37import com.jme3.font.BitmapFont;
38import com.jme3.font.BitmapText;
39import com.jme3.input.KeyInput;
40import com.jme3.input.controls.AnalogListener;
41import com.jme3.input.controls.KeyTrigger;
42import com.jme3.material.Material;
43import com.jme3.math.ColorRGBA;
44import com.jme3.math.FastMath;
45import com.jme3.math.Quaternion;
46import com.jme3.math.Vector3f;
47import com.jme3.scene.Geometry;
48import com.jme3.scene.Node;
49import com.jme3.scene.Spatial.CullHint;
50import com.jme3.scene.shape.Box;
51import com.jme3.scene.shape.Dome;
52import java.util.ArrayList;
53import java.util.logging.Level;
54import java.util.logging.Logger;
55
56/**
57 * @author Kyle "bonechilla" Williams
58 */
59public class CubeField extends SimpleApplication implements AnalogListener {
60
61    public static void main(String[] args) {
62        CubeField app = new CubeField();
63        app.start();
64    }
65
66    private BitmapFont defaultFont;
67
68    private boolean START;
69    private int difficulty, Score, colorInt, highCap, lowCap,diffHelp;
70    private Node player;
71    private Geometry fcube;
72    private ArrayList<Geometry> cubeField;
73    private ArrayList<ColorRGBA> obstacleColors;
74    private float speed, coreTime,coreTime2;
75    private float camAngle = 0;
76    private BitmapText fpsScoreText, pressStart;
77
78    private boolean solidBox = true;
79    private Material playerMaterial;
80    private Material floorMaterial;
81
82    private float fpsRate = 1000f / 1f;
83
84    /**
85     * Initializes game
86     */
87    @Override
88    public void simpleInitApp() {
89        Logger.getLogger("com.jme3").setLevel(Level.WARNING);
90
91        flyCam.setEnabled(false);
92        setDisplayStatView(false);
93
94        Keys();
95
96        defaultFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
97        pressStart = new BitmapText(defaultFont, false);
98        fpsScoreText = new BitmapText(defaultFont, false);
99
100        loadText(fpsScoreText, "Current Score: 0", defaultFont, 0, 2, 0);
101        loadText(pressStart, "PRESS ENTER", defaultFont, 0, 5, 0);
102
103        player = createPlayer();
104        rootNode.attachChild(player);
105        cubeField = new ArrayList<Geometry>();
106        obstacleColors = new ArrayList<ColorRGBA>();
107
108        gameReset();
109    }
110    /**
111     * Used to reset cubeField
112     */
113    private void gameReset(){
114        Score = 0;
115        lowCap = 10;
116        colorInt = 0;
117        highCap = 40;
118        difficulty = highCap;
119
120        for (Geometry cube : cubeField){
121            cube.removeFromParent();
122        }
123        cubeField.clear();
124
125        if (fcube != null){
126            fcube.removeFromParent();
127        }
128        fcube = createFirstCube();
129
130        obstacleColors.clear();
131        obstacleColors.add(ColorRGBA.Orange);
132        obstacleColors.add(ColorRGBA.Red);
133        obstacleColors.add(ColorRGBA.Yellow);
134        renderer.setBackgroundColor(ColorRGBA.White);
135        speed = lowCap / 400f;
136        coreTime = 20.0f;
137        coreTime2 = 10.0f;
138        diffHelp=lowCap;
139        player.setLocalTranslation(0,0,0);
140    }
141
142    @Override
143    public void simpleUpdate(float tpf) {
144        camTakeOver(tpf);
145        if (START){
146            gameLogic(tpf);
147        }
148        colorLogic();
149    }
150    /**
151     * Forcefully takes over Camera adding functionality and placing it behind the character
152     * @param tpf Tickes Per Frame
153     */
154    private void camTakeOver(float tpf) {
155        cam.setLocation(player.getLocalTranslation().add(-8, 2, 0));
156        cam.lookAt(player.getLocalTranslation(), Vector3f.UNIT_Y);
157
158        Quaternion rot = new Quaternion();
159        rot.fromAngleNormalAxis(camAngle, Vector3f.UNIT_Z);
160        cam.setRotation(cam.getRotation().mult(rot));
161        camAngle *= FastMath.pow(.99f, fpsRate * tpf);
162    }
163
164    @Override
165    public void requestClose(boolean esc) {
166        if (!esc){
167            System.out.println("The game was quit.");
168        }else{
169            System.out.println("Player has Collided. Final Score is " + Score);
170        }
171        context.destroy(false);
172    }
173    /**
174     * Randomly Places a cube on the map between 30 and 90 paces away from player
175     */
176    private void randomizeCube() {
177        Geometry cube = fcube.clone();
178        int playerX = (int) player.getLocalTranslation().getX();
179        int playerZ = (int) player.getLocalTranslation().getZ();
180//        float x = FastMath.nextRandomInt(playerX + difficulty + 10, playerX + difficulty + 150);
181        float x = FastMath.nextRandomInt(playerX + difficulty + 30, playerX + difficulty + 90);
182        float z = FastMath.nextRandomInt(playerZ - difficulty - 50, playerZ + difficulty + 50);
183        cube.getLocalTranslation().set(x, 0, z);
184
185//        playerX+difficulty+30,playerX+difficulty+90
186
187        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
188        if (!solidBox){
189            mat.getAdditionalRenderState().setWireframe(true);
190        }
191        mat.setColor("Color", obstacleColors.get(FastMath.nextRandomInt(0, obstacleColors.size() - 1)));
192        cube.setMaterial(mat);
193
194        rootNode.attachChild(cube);
195        cubeField.add(cube);
196    }
197
198    private Geometry createFirstCube() {
199        Vector3f loc = player.getLocalTranslation();
200        loc.addLocal(4, 0, 0);
201        Box b = new Box(loc, 1, 1, 1);
202
203        Geometry geom = new Geometry("Box", b);
204        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
205        mat.setColor("Color", ColorRGBA.Blue);
206        geom.setMaterial(mat);
207
208        return geom;
209    }
210
211    private Node createPlayer() {
212        Dome b = new Dome(Vector3f.ZERO, 10, 100, 1);
213        Geometry playerMesh = new Geometry("Box", b);
214
215        playerMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
216        playerMaterial.setColor("Color", ColorRGBA.Red);
217        playerMesh.setMaterial(playerMaterial);
218        playerMesh.setName("player");
219
220        Box floor = new Box(Vector3f.ZERO.add(playerMesh.getLocalTranslation().getX(),
221                playerMesh.getLocalTranslation().getY() - 1, 0), 100, 0, 100);
222        Geometry floorMesh = new Geometry("Box", floor);
223
224        floorMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
225        floorMaterial.setColor("Color", ColorRGBA.LightGray);
226        floorMesh.setMaterial(floorMaterial);
227        floorMesh.setName("floor");
228
229        Node playerNode = new Node();
230        playerNode.attachChild(playerMesh);
231        playerNode.attachChild(floorMesh);
232
233        return playerNode;
234    }
235
236    /**
237     * If Game is Lost display Score and Reset the Game
238     */
239    private void gameLost(){
240        START = false;
241        loadText(pressStart, "You lost! Press enter to try again.", defaultFont, 0, 5, 0);
242        gameReset();
243    }
244
245    /**
246     * Core Game Logic
247     */
248    private void gameLogic(float tpf){
249    	//Subtract difficulty level in accordance to speed every 10 seconds
250    	if(timer.getTimeInSeconds()>=coreTime2){
251			coreTime2=timer.getTimeInSeconds()+10;
252			if(difficulty<=lowCap){
253				difficulty=lowCap;
254			}
255			else if(difficulty>lowCap){
256				difficulty-=5;
257				diffHelp+=1;
258			}
259		}
260
261        if(speed<.1f){
262            speed+=.000001f*tpf*fpsRate;
263        }
264
265        player.move(speed * tpf * fpsRate, 0, 0);
266        if (cubeField.size() > difficulty){
267            cubeField.remove(0);
268        }else if (cubeField.size() != difficulty){
269            randomizeCube();
270        }
271
272        if (cubeField.isEmpty()){
273            requestClose(false);
274        }else{
275            for (int i = 0; i < cubeField.size(); i++){
276
277            	//better way to check collision
278                Geometry playerModel = (Geometry) player.getChild(0);
279                Geometry cubeModel = cubeField.get(i);
280                cubeModel.updateGeometricState();
281
282                BoundingVolume pVol = playerModel.getWorldBound();
283                BoundingVolume vVol = cubeModel.getWorldBound();
284
285                if (pVol.intersects(vVol)){
286                    gameLost();
287                    return;
288                }
289                //Remove cube if 10 world units behind player
290                if (cubeField.get(i).getLocalTranslation().getX() + 10 < player.getLocalTranslation().getX()){
291                    cubeField.get(i).removeFromParent();
292                    cubeField.remove(cubeField.get(i));
293                }
294
295            }
296        }
297
298        Score += fpsRate * tpf;
299        fpsScoreText.setText("Current Score: "+Score);
300    }
301    /**
302     * Sets up the keyboard bindings
303     */
304    private void Keys() {
305        inputManager.addMapping("START", new KeyTrigger(KeyInput.KEY_RETURN));
306        inputManager.addMapping("Left",  new KeyTrigger(KeyInput.KEY_LEFT));
307        inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT));
308        inputManager.addListener(this, "START", "Left", "Right");
309    }
310
311    public void onAnalog(String binding, float value, float tpf) {
312        if (binding.equals("START") && !START){
313            START = true;
314            guiNode.detachChild(pressStart);
315            System.out.println("START");
316        }else if (START == true && binding.equals("Left")){
317            player.move(0, 0, -(speed / 2f) * value * fpsRate);
318            camAngle -= value*tpf;
319        }else if (START == true && binding.equals("Right")){
320            player.move(0, 0, (speed / 2f) * value * fpsRate);
321            camAngle += value*tpf;
322        }
323    }
324
325    /**
326     * Determines the colors of the player, floor, obstacle and background
327     */
328    private void colorLogic() {
329    	if (timer.getTimeInSeconds() >= coreTime){
330
331        	colorInt++;
332            coreTime = timer.getTimeInSeconds() + 20;
333
334
335	        switch (colorInt){
336	            case 1:
337	                obstacleColors.clear();
338	                solidBox = false;
339	                obstacleColors.add(ColorRGBA.Green);
340	                renderer.setBackgroundColor(ColorRGBA.Black);
341	                playerMaterial.setColor("Color", ColorRGBA.White);
342			floorMaterial.setColor("Color", ColorRGBA.Black);
343	                break;
344	            case 2:
345	                obstacleColors.set(0, ColorRGBA.Black);
346	                solidBox = true;
347	                renderer.setBackgroundColor(ColorRGBA.White);
348	                playerMaterial.setColor("Color", ColorRGBA.Gray);
349                        floorMaterial.setColor("Color", ColorRGBA.LightGray);
350	                break;
351	            case 3:
352	                obstacleColors.set(0, ColorRGBA.Pink);
353	                break;
354	            case 4:
355	                obstacleColors.set(0, ColorRGBA.Cyan);
356	                obstacleColors.add(ColorRGBA.Magenta);
357	                renderer.setBackgroundColor(ColorRGBA.Gray);
358                        floorMaterial.setColor("Color", ColorRGBA.Gray);
359	                playerMaterial.setColor("Color", ColorRGBA.White);
360	                break;
361	            case 5:
362	                obstacleColors.remove(0);
363	                renderer.setBackgroundColor(ColorRGBA.Pink);
364	                solidBox = false;
365	                playerMaterial.setColor("Color", ColorRGBA.White);
366	                break;
367	            case 6:
368	                obstacleColors.set(0, ColorRGBA.White);
369	                solidBox = true;
370	                renderer.setBackgroundColor(ColorRGBA.Black);
371	                playerMaterial.setColor("Color", ColorRGBA.Gray);
372                        floorMaterial.setColor("Color", ColorRGBA.LightGray);
373	                break;
374	            case 7:
375	                obstacleColors.set(0, ColorRGBA.Green);
376	                renderer.setBackgroundColor(ColorRGBA.Gray);
377	                playerMaterial.setColor("Color", ColorRGBA.Black);
378                        floorMaterial.setColor("Color", ColorRGBA.Orange);
379	                break;
380	            case 8:
381	                obstacleColors.set(0, ColorRGBA.Red);
382                        floorMaterial.setColor("Color", ColorRGBA.Pink);
383	                break;
384	            case 9:
385	                obstacleColors.set(0, ColorRGBA.Orange);
386	                obstacleColors.add(ColorRGBA.Red);
387	                obstacleColors.add(ColorRGBA.Yellow);
388	                renderer.setBackgroundColor(ColorRGBA.White);
389	                playerMaterial.setColor("Color", ColorRGBA.Red);
390	                floorMaterial.setColor("Color", ColorRGBA.Gray);
391	                colorInt=0;
392	                break;
393	            default:
394	                break;
395	        }
396        }
397    }
398    /**
399     * Sets up a BitmapText to be displayed
400     * @param txt the Bitmap Text
401     * @param text the
402     * @param font the font of the text
403     * @param x
404     * @param y
405     * @param z
406     */
407    private void loadText(BitmapText txt, String text, BitmapFont font, float x, float y, float z) {
408        txt.setSize(font.getCharSet().getRenderedSize());
409        txt.setLocalTranslation(txt.getLineWidth() * x, txt.getLineHeight() * y, z);
410        txt.setText(text);
411        guiNode.attachChild(txt);
412    }
413}