OSDN Git Service

b15d4a50976ec94a71e424f4af09dea0a02a418a
[mikumikustudio/MikuMikuStudio.git] / src / jmetest / flagrushtut / lesson9 / Flag.java
1 /*
2  * Copyright (c) 2003-2009 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
33 package jmetest.flagrushtut.lesson9;
34
35 import jmetest.effects.cloth.TestCloth;
36
37 import com.jme.image.Texture;
38 import com.jme.light.LightNode;
39 import com.jme.light.PointLight;
40 import com.jme.math.FastMath;
41 import com.jme.math.Quaternion;
42 import com.jme.math.Vector3f;
43 import com.jme.math.spring.SpringPoint;
44 import com.jme.math.spring.SpringPointForce;
45 import com.jme.renderer.ColorRGBA;
46 import com.jme.renderer.Renderer;
47 import com.jme.scene.Node;
48 import com.jme.scene.shape.Cylinder;
49 import com.jme.scene.state.CullState;
50 import com.jme.scene.state.LightState;
51 import com.jme.scene.state.TextureState;
52 import com.jme.system.DisplaySystem;
53 import com.jme.util.TextureManager;
54 import com.jmex.effects.cloth.ClothPatch;
55 import com.jmex.effects.cloth.ClothUtils;
56 import com.jmex.terrain.TerrainBlock;
57
58 /**
59  * Flag maintains the object that is the "goal" of the game. The
60  * drivers are to try to grab the flags for points. The main job of 
61  * the class is to build the flag geometry, and position itself randomly
62  * within the level after a period of time.
63  * @author Mark Powell
64  *
65  */
66 public class Flag extends Node{
67         private static final long serialVersionUID = 1L;
68
69     //10 second life time
70     private static final int LIFE_TIME = 10;
71     //start off with a full life time
72     float countdown = LIFE_TIME;
73     //reference to the level terrain for placement
74     TerrainBlock tb;
75     //the cloth that makes up the flag.
76     private ClothPatch cloth;
77     //parameters for the wind
78     private float windStrength = 15f;
79     private Vector3f windDirection = new Vector3f(0.8f, 0, 0.2f);
80     private SpringPointForce gravity, wind;
81     
82     /**
83      * Constructor builds the flag, taking the terrain as the parameter. This
84      * is just the reference to the game's terrain object so that we can 
85      * randomly place this flag on the level.
86      * @param tb the terrain used to place the flag.
87      */
88     public Flag(TerrainBlock tb) {
89         super("flag");
90         this.tb = tb;
91         //create a cloth patch that will handle the flag part of our flag.
92         cloth = new ClothPatch("cloth", 25, 25, 1f, 10);
93         // Add our custom flag wind force to the cloth
94         wind = new RandomFlagWindForce(windStrength, windDirection);
95         cloth.addForce(wind);
96         // Add a simple gravitational force:
97         gravity = ClothUtils.createBasicGravity();
98         cloth.addForce(gravity);
99         
100         //Create the flag pole
101         Cylinder c = new Cylinder("pole", 10, 10, 0.5f, 50 );
102         this.attachChild(c);
103         Quaternion q = new Quaternion();
104         //rotate the cylinder to be vertical
105         q.fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0));
106         c.setLocalRotation(q);
107         c.setLocalTranslation(new Vector3f(-12.5f,-12.5f,0));
108
109         //create a texture that the flag will display.
110         //Let's promote jME! 
111         TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
112         ts.setTexture(
113             TextureManager.loadTexture(
114             TestCloth.class.getClassLoader().getResource(
115             "jmetest/data/images/Monkey.jpg"),
116             Texture.MinificationFilter.Trilinear,
117             Texture.MagnificationFilter.Bilinear));
118         
119         //We'll use a LightNode to give more lighting to the flag, we use the node because
120         //it will allow it to move with the flag as it hops around.
121         //first create the light
122         PointLight dr = new PointLight();
123         dr.setEnabled( true );
124         dr.setDiffuse( new ColorRGBA( 1.0f, 1.0f, 1.0f, 1.0f ) );
125         dr.setAmbient( new ColorRGBA( 0.5f, 0.5f, 0.5f, 1.0f ) );
126         dr.setLocation( new Vector3f( 0.5f, -0.5f, 0 ) );
127         //next the state
128         LightState lightState = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
129         lightState.setEnabled(true);
130         lightState.setTwoSidedLighting( true );
131         lightState.attach(dr);
132         //last the node
133         LightNode lightNode = new LightNode( "light" );
134         lightNode.setLight( dr );
135         lightNode.setLocalTranslation(new Vector3f(15,10,0));
136
137         this.setRenderState(lightState);
138         this.attachChild(lightNode);
139         
140         cloth.setRenderState(ts);
141         //We want to see both sides of the flag, so we will turn back facing culling OFF.
142         CullState cs = DisplaySystem.getDisplaySystem().getRenderer().createCullState();
143         cs.setCullFace(CullState.Face.None);
144         cloth.setRenderState(cs);
145         this.attachChild(cloth);
146         
147         //We need to attach a few points of the cloth to the poll. These points shouldn't
148         //ever move. So, we'll attach five points at the top and 5 at the bottom. 
149         //to make them not move the mass has to be high enough that no force can move it.
150         //I also move the position of these points slightly to help bunch up the flag to
151         //give it better realism.
152         for (int i = 0; i < 5; i++) {
153             cloth.getSystem().getNode(i*25).position.y *= .8f;
154             cloth.getSystem().getNode(i*25).setMass(Float.POSITIVE_INFINITY);
155             
156         }
157         
158         for (int i = 24; i > 19; i--) {
159             cloth.getSystem().getNode(i*25).position.y *= .8f;
160             cloth.getSystem().getNode(i*25).setMass(Float.POSITIVE_INFINITY);
161             
162         }
163         this.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
164         this.setLocalScale(0.25f);
165         
166     }
167     
168     /**
169      * During the update, we decrement the time. When it reaches zero, we will
170      * reset the flag.
171      * @param time the time between frame.
172      */
173     public void update(float time) {
174         countdown -= time;
175         
176         if(countdown <= 0) {
177             reset();
178         }
179     }
180     
181     /**
182      * reset sets the life time back to 10 seconds, and then randomly places the flag
183      * on the terrain.
184      *
185      */
186     public void reset() {
187         countdown = LIFE_TIME;
188         placeFlag();
189     }
190     
191     /**
192      * place flag picks a random point on the terrain and places the flag there. I
193      * set the values to be between (45 and 175) which places it within the force field
194      * level.
195      *
196      */
197     public void placeFlag() {
198         float x = 45 + FastMath.nextRandomFloat() * 130;
199         float z = 45 + FastMath.nextRandomFloat() * 130;
200         float y = tb.getHeight(x,z) + 7.5f;
201         localTranslation.x = x;
202         localTranslation.y = y;
203         localTranslation.z = z;
204         
205     }
206     
207     /**
208      * RandomFlagWindForce defines a SpringPointForce that will slighly adjust the
209      * direction of the wind and the force of the wind. This will cause the flag
210      * to flap in the wind and rotate about the flag pole slightly, giving it a
211      * realistic movement.
212      * @author Mark Powell
213      *
214      */
215     private class RandomFlagWindForce extends SpringPointForce{
216         
217         private final float strength;
218         private final Vector3f windDirection;
219
220         /**
221          * Creates a new force with a defined max strength and a starting direction.
222          * @param strength the maximum strength of the wind.
223          * @param direction the starting direction of the wind.
224          */
225         public RandomFlagWindForce(float strength, Vector3f direction) {
226             this.strength = strength;
227             this.windDirection = direction;
228         }
229         
230         /**
231          * called during the update of the cloth. Will adjust the direction slightly
232          * and adjust the strength slightly.
233          */
234         public void apply(float dt, SpringPoint node) {
235             windDirection.x += dt * (FastMath.nextRandomFloat() - 0.5f);
236             windDirection.z += dt * (FastMath.nextRandomFloat() - 0.5f);
237             windDirection.normalize();
238             float tStr = FastMath.nextRandomFloat() * strength;
239             node.acceleration.addLocal(windDirection.x * tStr, windDirection.y
240                     * tStr, windDirection.z * tStr);
241         }
242     };
243
244 }