Java tutorial
/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.fonotext.rong; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.InputAdapter; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Vector2; /** A simple Pong remake showing how easy it is to quickly prototype a game with libgdx. * * @author mzechner */ public class RongGDXGame extends InputAdapter implements ApplicationListener { /** the camera **/ private OrthographicCamera camera; /** the MeshRenderer for the paddles **/ private Mesh paddleMesh; /** the MeshRenderer for the ball **/ private Mesh ballMesh; /** the Font **/ // private Font font; /** sprite batch **/ private SpriteBatch spriteBatch; /** the position of the two paddles **/ private Vector2 leftPaddle = new Vector2(); private Vector2 rightPaddle = new Vector2(); /** the scores of the left and right paddle **/ private int leftScore = 0; private int rightScore = 0; /** the left paddle speed multiplicator, used so that the ai is not perfect **/ private float leftPaddleMulti = 1; /** some constants **/ private final int BALL_SPEED = 100; /** the position of the ball **/ private Vector2 ball = new Vector2(); /** the ball direction **/ private Vector2 ballDirection = new Vector2(); /** the current ball speed **/ private int ballSpeed = BALL_SPEED; /** score string **/ private String score = ""; /** Here we setup all the resources. A MeshRenderer for the paddles which we use for both, a MeshRenderer for the ball and a * Text for rendering the score. */ @Override public void create() { setupGraphics(); setupGame(); } /** This method sets up all the graphics related stuff like the Meshes, the camera and the Font */ private void setupGraphics() { // // We first construct the paddle mesh which consists of // four 2D vertices forming a vertically elongated rectangle // constructed around the origin. We don't use colors, normals // texture coordinates or indices. Note that we use a fixed // point Mesh here. The paddle has dimensions (10, 60). // paddleMesh = new Mesh(true, 4, 0, new VertexAttribute(Usage.Position, 2, "a_position")); paddleMesh.setVertices(new float[] { -5, -30, 5, -30, 5, 30, -5, 30 }); // // We do the same for the ball which has dimensions (10,10) // ballMesh = new Mesh(true, 4, 0, new VertexAttribute(Usage.Position, 2, "a_position")); ballMesh.setVertices(new float[] { -5, -5, 5, -5, 5, 5, -5, 5 }); // // We construct a new font from a system font. We assume // Arial is installed on both the desktop and Android. // // font = Gdx.graphics.newFont("Arial", 30, FontStyle.Plain); score = "0 : 0"; spriteBatch = new SpriteBatch(); // // Finally we construct an {@link OrthographicCamera} which // will scale our scene to 480x320 pixels no matter what the // real screen dimensions. This will of course squish the scene // on devices like the Droid. The screen center will be at (0,0) // so that's the reference frame for our scene. // camera = new OrthographicCamera(480, 320); } /** This sets up the game data like the initial paddle positions and the ball position and direction. */ private void setupGame() { leftPaddle.set(-200, 20); rightPaddle.set(200, 0); ball.set(0, 0); ballDirection.set(-1, 0); } @Override public void render() { // we update the game state so things move. updateGame(); // First we clear the screen GL10 gl = Gdx.graphics.getGL10(); gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // Next we update the camera and set the camera matrix camera.update(); camera.apply(Gdx.gl10); // Now we render the ball, we remember that we // Defined 4 vertices so we use a triangle fan // We also push and pop the matrix. This is not really // necessary as the model view matrix doesn't contain // anything at this point. gl.glPushMatrix(); gl.glTranslatef(ball.x, ball.y, 0); ballMesh.render(GL10.GL_TRIANGLE_FAN); gl.glPopMatrix(); // Rendering the two paddles works analogous gl.glPushMatrix(); gl.glTranslatef(leftPaddle.x, leftPaddle.y, 0); paddleMesh.render(GL10.GL_TRIANGLE_FAN); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(rightPaddle.x, rightPaddle.y, 0); paddleMesh.render(GL10.GL_TRIANGLE_FAN); gl.glPopMatrix(); // Finally we render the text centered at the top // of the screen. We use the text bounds for this. // For text to be transparent we have to enable blending and texturing. // We could setup blending once but i'm lazy :) spriteBatch.begin(); // spriteBatch.drawText(font, score, Gdx.graphics.getWidth() / 2 - font.getStringWidth(score) / 2, Gdx.graphics.getHeight() // - font.getLineHeight(), Color.WHITE); spriteBatch.end(); } /** Updates the game state, moves the ball, checks for collisions or whether the ball has left the playfield. */ private void updateGame() { // the delta time so we can do frame independant time based movement float deltaTime = Gdx.graphics.getDeltaTime(); // move the ball with a velocity of 50 pixels // per second. The ballDirection is a unit vector // we simply scale by the velocity. ball.add(ballSpeed * ballDirection.x * deltaTime, ballSpeed * ballDirection.y * deltaTime); System.out.println(ball); // Next we check whether the ball left the field to // the left or to the right and update the score if (ball.x < -240) { ball.set(0, 0); // reset to center ballSpeed = BALL_SPEED; // reset the ball speed ballDirection.set((float) Math.random() + 0.1f, (float) Math.random()).nor(); // new ball direction, must be unit length rightScore++; // right paddle scored! score = leftScore + " : " + rightScore; // we set the left paddle multiplicator here which governs // how fast the left paddle can follow the ball. leftPaddleMulti = (float) Math.min(1, Math.random() + 0.3f); } if (ball.x > 240) { ball.set(0, 0); // reset to center ballSpeed = BALL_SPEED; // reset the ball speed ballDirection.set((float) Math.random() + 0.1f, (float) Math.random()).nor(); // new ball direction, must be unit length leftScore++; // left paddle scored! score = leftScore + " : " + rightScore; // we set the left paddle multiplicator here which governs // how fast the left paddle can follow the ball. leftPaddleMulti = (float) Math.min(1, Math.random() + 0.3f); } // if the ball is hitting the bottom or top we // reverse its direction in y so that it bounces if (ball.y > 160) { ballDirection.y = -ballDirection.y; ball.y = 160; } if (ball.y < -160) { ballDirection.y = -ballDirection.y; ball.y = -160; } // if the ball is heading towards the right paddle and // has hit it we reflect it if (ballDirection.x > 0 && ball.x > rightPaddle.x - 5 && ball.x < rightPaddle.x + 5 && ball.y > rightPaddle.y - 30 && ball.y < rightPaddle.y + 30) { ball.x = rightPaddle.x - 6; // set the position of a little so we don't get to this code in the next frame ballDirection.x = -ballDirection.x; float sign = Math.signum(ball.y - rightPaddle.y); ballDirection.y = sign * (float) Math.abs(ball.y - rightPaddle.y) / 30; // reflect it depending on where the paddle was // hit ballDirection.nor(); ballSpeed += 10; // and faster! if (ballSpeed > 300) ballSpeed = 300; } // and the same for the left paddle if (ballDirection.x < 0 && ball.x < leftPaddle.x + 5 && ball.x > leftPaddle.x - 5 && ball.y > leftPaddle.y - 30 && ball.y < leftPaddle.y + 30) { ball.x = leftPaddle.x + 6; // set the position of a little so we don't get to this code in the next frame ballDirection.x = -ballDirection.x; float sign = (float) Math.signum(ball.y - leftPaddle.y); ballDirection.y = sign * (float) Math.abs(ball.y - leftPaddle.y) / 30; // reflect it depending on where the paddle was hit ballDirection.nor(); ballSpeed += 10; // and faster! if (ballSpeed > 300) ballSpeed = 300; // we set the left paddle multiplicator here which governs // how fast the left paddle can follow the ball. leftPaddleMulti = (float) Math.min(1, Math.random() + 0.3f); } // Has the user touched the screen? then position the paddle if (Gdx.input.isTouched()) { // get the touch coordinates and translate them // to the game coordinate system. float touchX = 480 * (Gdx.input.getX() / (float) Gdx.graphics.getWidth() - 0.5f); float touchY = 320 * (0.5f - Gdx.input.getY() / (float) Gdx.graphics.getHeight()); if (touchX > rightPaddle.x) rightPaddle.y = touchY; } // very very simple ai. moves when the ball is heading towards // the left paddle if (ballDirection.x < 0) { float dir = (float) Math.signum(ball.y - leftPaddle.y); leftPaddle.y += dir * deltaTime * (ballSpeed * leftPaddleMulti); if (dir > 0 && leftPaddle.y > ball.y) leftPaddle.y = ball.y; if (dir < 0 && leftPaddle.y < ball.y) leftPaddle.y = ball.y; } } public boolean needsGL20() { return false; } @Override public void resize(int width, int height) { // TODO Auto-generated method stub } @Override public void pause() { // TODO Auto-generated method stub } @Override public void resume() { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } }