Untitled

public
denzelle.tagupa Nov 27, 2024 Never 32
Clone
Plaintext paste1.txt 438 lines (358 loc) | 15.91 KB
1
package io.github.some_example_name;
2
3
import com.badlogic.gdx.ApplicationListener;
4
import com.badlogic.gdx.Gdx;
5
import com.badlogic.gdx.InputAdapter;
6
import com.badlogic.gdx.Input.Keys;
7
import com.badlogic.gdx.graphics.Color;
8
import com.badlogic.gdx.graphics.GL20;
9
import com.badlogic.gdx.graphics.OrthographicCamera;
10
import com.badlogic.gdx.graphics.Texture;
11
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
12
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
13
import com.badlogic.gdx.maps.tiled.TiledMap;
14
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
15
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
16
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
17
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
18
import com.badlogic.gdx.math.MathUtils;
19
import com.badlogic.gdx.math.Rectangle;
20
import com.badlogic.gdx.math.Vector2;
21
import com.badlogic.gdx.utils.Array;
22
import com.badlogic.gdx.utils.Pool;
23
import com.badlogic.gdx.utils.ScreenUtils;
24
import com.badlogic.gdx.*;
25
import com.badlogic.gdx.graphics.*;
26
import com.badlogic.gdx.graphics.g2d.*;
27
import com.badlogic.gdx.math.*;
28
import com.badlogic.gdx.scenes.scene2d.ui.Label;
29
import com.badlogic.gdx.utils.*;
30
import com.badlogic.gdx.maps.*;
31
import com.badlogic.gdx.maps.tiled.*;
32
import com.badlogic.gdx.graphics.glutils.*;
33
34
35
/** Super Mario Brothers-like very basic platformer, using a tile map built using <a href="https://www.mapeditor.org/">Tiled</a> and a
36
* tileset and sprites by <a href="http://www.vickiwenderlich.com/">Vicky Wenderlich</a></p>
37
*
38
* Shows simple platformer collision detection as well as on-the-fly map modifications through destructible blocks!
39
* @author mzechner */
40
public class Main extends InputAdapter implements ApplicationListener {
41
private boolean gameOver = false; // Game Over flag
42
private String gameOverMessage = "Game Over press R to Restart";
43
/** The player character, has state and state time, */
44
static class Koala {
45
static float WIDTH;
46
static float HEIGHT;
47
static float MAX_VELOCITY = 10f;
48
static float JUMP_VELOCITY = 40f;
49
static float DAMPING = 0.87f;
50
51
enum State {
52
Standing, Walking, Jumping
53
}
54
55
final Vector2 position = new Vector2();
56
final Vector2 velocity = new Vector2();
57
State state = State.Walking;
58
float stateTime = 0;
59
boolean facesRight = true;
60
boolean grounded = false;
61
}
62
63
private TiledMap map;
64
private OrthogonalTiledMapRenderer renderer;
65
private OrthographicCamera camera;
66
private Texture koalaTexture;
67
private Animation<TextureRegion> stand;
68
private Animation<TextureRegion> walk;
69
private Animation<TextureRegion> jump;
70
private Koala koala;
71
private Pool<Rectangle> rectPool = new Pool<Rectangle>() {
72
@Override
73
protected Rectangle newObject () {
74
return new Rectangle();
75
}
76
};
77
private Array<Rectangle> tiles = new Array<Rectangle>();
78
79
private static final float GRAVITY = -2.5f;
80
81
private boolean debug = false;
82
private ShapeRenderer debugRenderer;
83
84
@Override
85
public void create () {
86
87
// load the koala frames, split them, and assign them to Animations
88
koalaTexture = new Texture("koalio.png");
89
TextureRegion[] regions = TextureRegion.split(koalaTexture, 18, 26)[0];
90
stand = new Animation<TextureRegion>(0, regions[0]);
91
jump = new Animation<TextureRegion>(0, regions[1]);
92
walk = new Animation<TextureRegion>(0.15f, regions[2], regions[3], regions[4]);
93
walk.setPlayMode(Animation.PlayMode.LOOP_PINGPONG);
94
95
// figure out the width and height of the koala for collision
96
// detection and rendering by converting a koala frames pixel
97
// size into world units (1 unit == 16 pixels)
98
Koala.WIDTH = 1 / 16f * regions[0].getRegionWidth();
99
Koala.HEIGHT = 1 / 16f * regions[0].getRegionHeight();
100
101
// load the map, set the unit scale to 1/16 (1 unit == 16 pixels)
102
map = new TmxMapLoader().load("level1.tmx");
103
renderer = new OrthogonalTiledMapRenderer(map, 1 / 16f);
104
105
// create an orthographic camera, shows us 30x20 units of the world
106
camera = new OrthographicCamera();
107
camera.setToOrtho(false, 30, 20);
108
camera.update();
109
110
// create the Koala we want to move around the world
111
koala = new Koala();
112
koala.position.set(20, 20);
113
114
debugRenderer = new ShapeRenderer();
115
}
116
117
@Override
118
public void render () {
119
// Clear the screen
120
ScreenUtils.clear(0.7f, 0.7f, 1.0f, 1);
121
122
if (gameOver) {
123
// Render Game Over screen
124
renderGameOver();
125
return; // Skip further updates
126
}
127
128
// Get the delta time
129
float deltaTime = Gdx.graphics.getDeltaTime();
130
131
// Update the koala (process input, collision detection, position update)
132
updateKoala(deltaTime);
133
134
// Let the camera follow the koala, x-axis only
135
camera.position.x = koala.position.x;
136
camera.update();
137
138
// Set the TiledMapRenderer view based on what the
139
// camera sees, and render the map
140
renderer.setView(camera);
141
renderer.render();
142
143
// Render the koala
144
renderKoala(deltaTime);
145
146
// Render debug rectangles
147
if (debug) renderDebug();
148
149
}
150
151
private void updateKoala (float deltaTime) {
152
153
if (deltaTime == 0) return;
154
155
if (gameOver) return; // Stop updates if game over
156
157
// Check for game over condition
158
if (koala.position.y < -10) { // Example: Falling below -10 triggers game over
159
gameOver = true;
160
return;
161
}
162
163
164
if (deltaTime == 0) return;
165
166
if (deltaTime > 0.1f)
167
deltaTime = 0.1f;
168
169
koala.stateTime += deltaTime;
170
171
// check input and apply to velocity & state
172
if ((Gdx.input.isKeyPressed(Keys.SPACE) || isTouched(0.5f, 1)) && koala.grounded) {
173
koala.velocity.y += Koala.JUMP_VELOCITY;
174
koala.state = Koala.State.Jumping;
175
koala.grounded = false;
176
}
177
178
if (Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A) || isTouched(0, 0.25f)) {
179
koala.velocity.x = -Koala.MAX_VELOCITY;
180
if (koala.grounded) koala.state = Koala.State.Walking;
181
koala.facesRight = false;
182
}
183
184
if (Gdx.input.isKeyPressed(Keys.RIGHT) || Gdx.input.isKeyPressed(Keys.D) || isTouched(0.25f, 0.5f)) {
185
koala.velocity.x = Koala.MAX_VELOCITY;
186
if (koala.grounded) koala.state = Koala.State.Walking;
187
koala.facesRight = true;
188
}
189
190
if (Gdx.input.isKeyJustPressed(Keys.B))
191
debug = !debug;
192
193
// apply gravity if we are falling
194
koala.velocity.add(0, GRAVITY);
195
196
// clamp the velocity to the maximum, x-axis only
197
koala.velocity.x = MathUtils.clamp(koala.velocity.x,
198
-Koala.MAX_VELOCITY, Koala.MAX_VELOCITY);
199
200
// If the velocity is < 1, set it to 0 and set state to Standing
201
if (Math.abs(koala.velocity.x) < 1) {
202
koala.velocity.x = 0;
203
if (koala.grounded) koala.state = Koala.State.Standing;
204
}
205
206
// multiply by delta time so we know how far we go
207
// in this frame
208
koala.velocity.scl(deltaTime);
209
210
// perform collision detection & response, on each axis, separately
211
// if the koala is moving right, check the tiles to the right of it's
212
// right bounding box edge, otherwise check the ones to the left
213
Rectangle koalaRect = rectPool.obtain();
214
koalaRect.set(koala.position.x, koala.position.y, Koala.WIDTH, Koala.HEIGHT);
215
int startX, startY, endX, endY;
216
if (koala.velocity.x > 0) {
217
startX = endX = (int)(koala.position.x + Koala.WIDTH + koala.velocity.x);
218
} else {
219
startX = endX = (int)(koala.position.x + koala.velocity.x);
220
}
221
startY = (int)(koala.position.y);
222
endY = (int)(koala.position.y + Koala.HEIGHT);
223
getTiles(startX, startY, endX, endY, tiles);
224
koalaRect.x += koala.velocity.x;
225
for (Rectangle tile : tiles) {
226
if (koalaRect.overlaps(tile)) {
227
koala.velocity.x = 0;
228
break;
229
}
230
}
231
koalaRect.x = koala.position.x;
232
233
// if the koala is moving upwards, check the tiles to the top of its
234
// top bounding box edge, otherwise check the ones to the bottom
235
if (koala.velocity.y > 0) {
236
startY = endY = (int)(koala.position.y + Koala.HEIGHT + koala.velocity.y);
237
} else {
238
startY = endY = (int)(koala.position.y + koala.velocity.y);
239
}
240
startX = (int)(koala.position.x);
241
endX = (int)(koala.position.x + Koala.WIDTH);
242
getTiles(startX, startY, endX, endY, tiles);
243
koalaRect.y += koala.velocity.y;
244
for (Rectangle tile : tiles) {
245
if (koalaRect.overlaps(tile)) {
246
// we actually reset the koala y-position here
247
// so it is just below/above the tile we collided with
248
// this removes bouncing :)
249
if (koala.velocity.y > 0) {
250
koala.position.y = tile.y - Koala.HEIGHT;
251
// we hit a block jumping upwards, let's destroy it!
252
TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get("walls");
253
layer.setCell((int)tile.x, (int)tile.y, null);
254
} else {
255
koala.position.y = tile.y + tile.height;
256
// if we hit the ground, mark us as grounded so we can jump
257
koala.grounded = true;
258
}
259
koala.velocity.y = 0;
260
break;
261
}
262
}
263
rectPool.free(koalaRect);
264
265
// unscale the velocity by the inverse delta time and set
266
// the latest position
267
koala.position.add(koala.velocity);
268
koala.velocity.scl(1 / deltaTime);
269
270
// Apply damping to the velocity on the x-axis so we don't
271
// walk infinitely once a key was pressed
272
koala.velocity.x *= Koala.DAMPING;
273
}
274
275
// DIsplay
276
277
private void renderGameOver() {
278
// Switch to a UI camera for rendering the "Game Over" text
279
float screenWidth = Gdx.graphics.getWidth();
280
float screenHeight = Gdx.graphics.getHeight();
281
282
// Create a new orthographic camera that matches the screen size
283
OrthographicCamera uiCamera = new OrthographicCamera();
284
uiCamera.setToOrtho(false, screenWidth, screenHeight); // Set the camera to match the screen size
285
uiCamera.update(); // Update the camera to apply the changes
286
287
// Now, set the batch to use the UI camera's projection matrix
288
Batch batch = renderer.getBatch();
289
batch.setProjectionMatrix(uiCamera.combined);
290
batch.begin();
291
292
// Create a new BitmapFont
293
BitmapFont font = new BitmapFont();
294
295
// Set the font color (you can keep it red or change it)
296
font.setColor(Color.RED);
297
298
// Set the font scale to make it smaller
299
font.getData().setScale(2f); // Adjust this scale value to make it smaller (0.5f makes it half the normal size)
300
301
// Get the width and height of the "GAME OVER" text
302
GlyphLayout layout = new GlyphLayout(font, "GAME OVER");
303
float textWidth = layout.width;
304
float textHeight = layout.height;
305
306
// Calculate the center position for the text
307
float x = (screenWidth - textWidth) / 2; // Horizontal centering
308
float y = (screenHeight + textHeight) / 2; // Vertical centering (adjusted to be more centered)
309
310
// Log the position to check if the coordinates are correct
311
Gdx.app.log("GameOver", "Drawing 'GAME OVER' at x: " + x + ", y: " + y);
312
313
314
// Draw the "Game Over" text at the calculated position
315
font.draw(batch, "Game Over", x, y); // Render at the centers
316
317
font.draw(batch, "Press C to Restart", x-40, y-35); // Render at the center
318
319
batch.end();
320
321
if (Gdx.input.isKeyPressed(Keys.C)) {
322
restartGame();
323
}
324
325
326
}
327
328
329
private void restartGame() {
330
gameOver = false;
331
332
// Reset Koala position and state
333
koala.position.set(20, 20);
334
koala.velocity.set(0, 0);
335
koala.state = Koala.State.Standing;
336
337
// Reload map or reset game state as necessary
338
map = new TmxMapLoader().load("level1.tmx");
339
renderer.setMap(map);
340
}
341
342
private boolean isTouched (float startX, float endX) {
343
// Check for touch inputs between startX and endX
344
// startX/endX are given between 0 (left edge of the screen) and 1 (right edge of the screen)
345
for (int i = 0; i < 2; i++) {
346
float x = Gdx.input.getX(i) / (float)Gdx.graphics.getBackBufferWidth();
347
if (Gdx.input.isTouched(i) && (x >= startX && x <= endX)) {
348
return true;
349
}
350
}
351
return false;
352
}
353
354
private void getTiles (int startX, int startY, int endX, int endY, Array<Rectangle> tiles) {
355
TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get("walls");
356
rectPool.freeAll(tiles);
357
tiles.clear();
358
for (int y = startY; y <= endY; y++) {
359
for (int x = startX; x <= endX; x++) {
360
Cell cell = layer.getCell(x, y);
361
if (cell != null) {
362
Rectangle rect = rectPool.obtain();
363
rect.set(x, y, 1, 1);
364
tiles.add(rect);
365
}
366
}
367
}
368
}
369
370
private void renderKoala (float deltaTime) {
371
// based on the koala state, get the animation frame
372
TextureRegion frame = null;
373
switch (koala.state) {
374
case Standing:
375
frame = stand.getKeyFrame(koala.stateTime);
376
break;
377
case Walking:
378
frame = walk.getKeyFrame(koala.stateTime);
379
break;
380
case Jumping:
381
frame = jump.getKeyFrame(koala.stateTime);
382
break;
383
}
384
385
// draw the koala, depending on the current velocity
386
// on the x-axis, draw the koala facing either right
387
// or left
388
Batch batch = renderer.getBatch();
389
batch.begin();
390
if (koala.facesRight) {
391
batch.draw(frame, koala.position.x, koala.position.y, Koala.WIDTH, Koala.HEIGHT);
392
} else {
393
batch.draw(frame, koala.position.x + Koala.WIDTH, koala.position.y, -Koala.WIDTH, Koala.HEIGHT);
394
}
395
batch.end();
396
}
397
398
private void renderDebug () {
399
debugRenderer.setProjectionMatrix(camera.combined);
400
debugRenderer.begin(ShapeType.Line);
401
402
debugRenderer.setColor(Color.RED);
403
debugRenderer.rect(koala.position.x, koala.position.y, Koala.WIDTH, Koala.HEIGHT);
404
405
debugRenderer.setColor(Color.YELLOW);
406
TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get("walls");
407
for (int y = 0; y <= layer.getHeight(); y++) {
408
for (int x = 0; x <= layer.getWidth(); x++) {
409
Cell cell = layer.getCell(x, y);
410
if (cell != null) {
411
if (camera.frustum.boundsInFrustum(x + 0.5f, y + 0.5f, 0, 1, 1, 0))
412
debugRenderer.rect(x, y, 1, 1);
413
}
414
}
415
}
416
debugRenderer.end();
417
}
418
419
@Override
420
public void dispose () {
421
}
422
423
@Override
424
public void resume () {
425
}
426
427
@Override
428
public void resize(int width, int height) {
429
}
430
431
@Override
432
public void pause() {
433
}
434
435
436
437
438
}