44import com .codename1 .gaming .GameView ;
55import com .codename1 .gaming .Model ;
66import com .codename1 .gaming .Sprite ;
7+ import com .codename1 .gaming .TouchControls ;
78import com .codename1 .gpu .GraphicsDevice ;
89import com .codename1 .gpu .Material ;
910import com .codename1 .gpu .Mesh ;
1011import com .codename1 .gpu .Primitives ;
12+ import com .codename1 .gpu .Texture ;
1113import com .codename1 .io .Log ;
1214import com .codename1 .ui .Display ;
1315import com .codename1 .ui .Form ;
@@ -56,70 +58,114 @@ public void destroy() {
5658
5759 /// The 3D game surface.
5860 static class World3DView extends GameView {
59- private static final int COIN_COUNT = 8 ;
60- private static final float COIN_RING = 4f ;
61+ private static final int COIN_COUNT = 10 ;
62+ private static final float COIN_RING = 5f ;
63+ private static final int BUILDINGS = 8 ;
6164
62- private Model cube ;
65+ private final Model [] monument = new Model [3 ];
66+ private final Sprite [] coins = new Sprite [COIN_COUNT ];
6367 private double time ;
6468 private double orbit ;
65- private float camHeight = 6f ;
69+ private float camHeight = 7f ;
6670 private boolean controlsReady ;
6771
6872 World3DView () {
69- setClearColor (0xff101824 );
70- // perspective camera looking at the cube from above and behind
73+ setClearColor (0xff1a2a4a ); // dusk sky
7174 getCamera ()
72- .setPerspective (60f , 0.1f , 200f )
73- .setPosition (0f , 6f , 12f )
74- .setTarget (0f , 1f , 0f );
75+ .setPerspective (60f , 0.1f , 300f )
76+ .setPosition (0f , 7f , 15f )
77+ .setTarget (0f , 2.5f , 0f );
7578
76- // a ring of billboarded coins in 3D world space
79+ // a ring of billboarded coins floating in 3D world space
7780 Image coinImage = makeCoin (48 , 0xffffd54a );
7881 for (int i = 0 ; i < COIN_COUNT ; i ++) {
7982 double a = i * 2 * Math .PI / COIN_COUNT ;
80- Sprite coin = new Sprite (coinImage );
81- coin .setPosition (Math .cos (a ) * COIN_RING , 1.2 , Math .sin (a ) * COIN_RING );
82- coin .setSize (1.2f , 1.2f ); // world units, not pixels
83- getScene ().add (coin );
83+ coins [i ] = new Sprite (coinImage );
84+ coins [i ].setPosition (Math .cos (a ) * COIN_RING , 1.4 , Math .sin (a ) * COIN_RING );
85+ coins [i ].setSize (1.1f , 1.1f ); // world units, not pixels
86+ getScene ().add (coins [i ]);
87+ }
88+ // a few billboarded trees for scenery (always face the camera)
89+ Image treeImage = makeTree (72 );
90+ double [] tx = {-11 , 10 , -9 , 12 , 2 };
91+ double [] tz = {-10 , -8 , 9 , 7 , -13 };
92+ for (int i = 0 ; i < tx .length ; i ++) {
93+ Sprite tree = new Sprite (treeImage );
94+ tree .setPosition (tx [i ], 1.8 , tz [i ]);
95+ tree .setSize (3.6f , 3.6f );
96+ getScene ().add (tree );
8497 }
8598 }
8699
87100 protected void onSetup (GraphicsDevice device ) {
88- // ground plane: a quad rotated flat, lit and green
89- Mesh quad = Primitives .quad (device , 16f );
90- Material grass = new Material (Material .Type .LAMBERT ).setColor (0xff2f7d32 );
91- Model ground = new Model (quad , grass );
101+ // textured grid ground: a quad rotated flat, lit and tinted green
102+ Mesh groundMesh = Primitives .quad (device , 64f );
103+ Texture grid = device .createTexture (makeGrid (256 , 0xffe8efe8 , 0xff9fc0a0 , 8 ));
104+ Material groundMat = new Material (Material .Type .LAMBERT )
105+ .setColor (0xff3f7d4f ).setTexture (grid );
106+ Model ground = new Model (groundMesh , groundMat );
92107 ground .setRotation (-90f , 0f , 0f ); // XY quad -> horizontal XZ ground
93108 addModel (ground );
94109
95- // a gold spinning cube sitting on the ground
96- Mesh cubeMesh = Primitives .cube (device , 2f );
97- Material gold = new Material (Material .Type .PHONG ).setColor (0xffffcc33 ).setShininess (32f );
98- cube = new Model (cubeMesh , gold );
99- cube .setPosition (0f , 1f , 0f );
100- addModel (cube );
110+ // central spinning monument: three stacked, shiny cubes
111+ Mesh cubeMesh = Primitives .cube (device , 1f );
112+ int [] mcol = {0xffffcc33 , 0xff33c7c7 , 0xffff7043 };
113+ float [] msize = {2.6f , 1.7f , 1.0f };
114+ float y = 0f ;
115+ for (int i = 0 ; i < 3 ; i ++) {
116+ y += msize [i ] / 2f ;
117+ Material m = new Material (Material .Type .PHONG ).setColor (mcol [i ]).setShininess (24f );
118+ Model c = new Model (cubeMesh , m );
119+ c .setScale (msize [i ]);
120+ c .setPosition (0f , y , 0f );
121+ monument [i ] = c ;
122+ addModel (c );
123+ y += msize [i ] / 2f ;
124+ }
125+
126+ // a ring of colored "buildings" of varying height (one cube mesh, scaled)
127+ int [] bcol = {0xff5b8def , 0xffe06ca0 , 0xff8bd450 , 0xfff2b134 ,
128+ 0xff9b6cf0 , 0xff4fd1c5 , 0xffef6f6f , 0xffb0bec5 };
129+ for (int i = 0 ; i < BUILDINGS ; i ++) {
130+ double a = i * 2 * Math .PI / BUILDINGS ;
131+ float h = 1.6f + (i % 4 ) * 0.9f ;
132+ Material m = new Material (Material .Type .LAMBERT ).setColor (bcol [i % bcol .length ]);
133+ Model b = new Model (cubeMesh , m );
134+ b .setScale (1.5f , h , 1.5f );
135+ b .setPosition ((float ) (Math .cos (a ) * 9.5 ), h / 2f , (float ) (Math .sin (a ) * 9.5 ));
136+ addModel (b );
137+ }
101138
102- getLight ().setDirection (-0.5f , -1f , -0.4f ).setColor (0xffffffff ).setAmbientColor (0xff404048 );
139+ getLight ().setDirection (-0.4f , -1f , -0.3f ).setColor (0xfffff4e0 )
140+ .setAmbientColor (0xff3a4257 );
103141 }
104142
105143 protected void update (double dt ) {
106144 time += dt ;
107- if (cube != null ) {
108- cube .setRotation (0f , (float ) (time * 60 ), 0f ); // spin around Y
145+ // each monument tier spins at its own speed and direction
146+ for (int i = 0 ; i < monument .length ; i ++) {
147+ if (monument [i ] != null ) {
148+ float dir = (i % 2 == 0 ) ? 1f : -1f ;
149+ monument [i ].setRotation (0f , (float ) (time * (30 + i * 22 )) * dir , 0f );
150+ }
151+ }
152+ // bob the coins up and down
153+ for (int i = 0 ; i < COIN_COUNT ; i ++) {
154+ coins [i ].setY (1.4 + Math .sin (time * 2 + i ) * 0.3 );
109155 }
110156 if (!controlsReady && getWidth () > 0 ) {
111- getControls ().addJoystick (110 , getHeight () - 110 , 80 );
157+ getControls ().addJoystick (80 , TouchControls . LEFT , TouchControls . BOTTOM , 30 );
112158 controlsReady = true ;
113159 }
114160 // the joystick orbits the camera (x) and raises/lowers it (y); when
115- // untouched the camera drifts on its own.
161+ // untouched the camera drifts slowly on its own.
116162 float ax = getInput ().getAxisX ();
117163 float ay = getInput ().getAxisY ();
118- orbit += (ax != 0 ? ax * 1.5 : 0.3 ) * dt ;
119- camHeight = clamp (camHeight + ay * 6f * (float ) dt , 1 .5f , 14f );
120- float r = 12f ;
164+ orbit += (ax != 0 ? ax * 1.5 : 0.25 ) * dt ;
165+ camHeight = clamp (camHeight + ay * 7f * (float ) dt , 2 .5f , 18f );
166+ float r = 15f ;
121167 getCamera ().setPosition ((float ) (Math .sin (orbit ) * r ), camHeight ,
122- (float ) (Math .cos (orbit ) * r ));
168+ (float ) (Math .cos (orbit ) * r )). setTarget ( 0f , 2.5f , 0f ) ;
123169 }
124170
125171 private static float clamp (float v , float lo , float hi ) {
@@ -138,4 +184,34 @@ static Image makeCoin(int size, int color) {
138184 g .fillArc (size / 4 , size / 5 , size / 3 , size / 3 , 0 , 360 ); // highlight
139185 return img ;
140186 }
187+
188+ /// Builds a grid texture (a base fill crossed by `cells` evenly spaced lines each
189+ /// way) used to tint and detail the ground so the 3D space reads with depth.
190+ static Image makeGrid (int size , int baseColor , int lineColor , int cells ) {
191+ Image img = Image .createImage (size , size , baseColor );
192+ Graphics g = img .getGraphics ();
193+ g .setColor (lineColor );
194+ int step = size / cells ;
195+ for (int i = 0 ; i <= cells ; i ++) {
196+ int p = Math .min (size - 2 , i * step );
197+ g .fillRect (p , 0 , 2 , size ); // vertical line
198+ g .fillRect (0 , p , size , 2 ); // horizontal line
199+ }
200+ return img ;
201+ }
202+
203+ /// Builds a simple billboard tree (brown trunk, layered green canopy) on a
204+ /// transparent background.
205+ static Image makeTree (int size ) {
206+ Image img = Image .createImage (size , size , 0 );
207+ Graphics g = img .getGraphics ();
208+ g .setAntiAliased (true );
209+ g .setColor (0xff7a4a26 );
210+ g .fillRect (size / 2 - size / 14 , size * 3 / 5 , size / 7 , size * 2 / 5 ); // trunk
211+ g .setColor (0xff2f8f3f );
212+ g .fillArc (size / 6 , size / 5 , size * 2 / 3 , size * 2 / 3 , 0 , 360 ); // canopy
213+ g .setColor (0xff3fa84f );
214+ g .fillArc (size / 4 , size / 8 , size / 2 , size / 2 , 0 , 360 ); // highlight
215+ return img ;
216+ }
141217}
0 commit comments