module pong; import dsfml.system.all; import dsfml.audio.all; import dsfml.window.all; import dsfml.graphics.all; version (Tango) { import tango.io.Stdout; import tango.math.Math; } else { import std.math; import std.perf; import std.random; } void main() { // Defines PI const float PI = 3.14159f; // Create the window of the application RenderWindow app = new RenderWindow(VideoMode(800, 600, 32), "SFML Pong"); app.useVerticalSync(false); Input i = app.input; // Load the sounds used in the game Sound BallSound = new Sound(new SoundBuffer("Data/ball.wav")); // Load the images used in the game Image PaddleImage = new Image("Data/paddle.tga"); Image BallImage = new Image("Data/ball.tga"); // Initialize the end text Text End = new Text(""c); Font font = new Font("Data/cheeseburger.ttf"); End.font = font; End.characterSize = 60; End.move(150.f, 200.f); End.color = Color(50, 50, 250); Text fps = new Text(""c, font, 30); fps.move(50.f, 50.f); fps.color = Color.BLACK; // Create the sprites of the background, the paddles and the ball Sprite LeftPaddle = new Sprite(PaddleImage); Sprite RightPaddle = new Sprite(PaddleImage); Sprite Ball = new Sprite(BallImage); LeftPaddle.move(10, (app.view.getHeight() - LeftPaddle.size.y) / 2); RightPaddle.move(app.view.getWidth() - RightPaddle.size.x - 10, (app.view.getHeight() - RightPaddle.size.y) / 2); Ball.move((app.view.getWidth() - Ball.size.x) / 2, (app.view.getHeight() - Ball.size.y) / 2); // Define the paddles properties auto AITimer = new PerformanceCounter(); const long AITime = 100; // 100 ms float LeftPaddleSpeed = 400.f; float RightPaddleSpeed = 400.f; // Define the ball properties float BallSpeed = 400.f; float BallAngle = 0.f; do { // Make sure the ball initial angle is not too much vertical BallAngle = uniform(0.f, 2 * PI); } while (abs(cos(BallAngle)) < 0.7f); bool IsPlaying = true; Event evt; uint iFps = 0; auto fpsClock = new PerformanceCounter(); while (app.isOpened()) { app.clear(Color(255, 255, 255, 255)); // Handle events while (app.getEvent(evt)) { // Window closed or escape key pressed : exit if ((evt.Type == EventType.Closed) || ((evt.Type == EventType.KeyPressed) && (evt.Key.Code == KeyCode.Escape))) { app.close(); break; } } if (IsPlaying) { // Move the player's paddle if (i.isKeyDown(KeyCode.Up) && (LeftPaddle.position.y > 5.f)) LeftPaddle.move(0.f, -LeftPaddleSpeed * app.frameTime); if (i.isKeyDown(KeyCode.Down) && (LeftPaddle.position.y < app.view.getHeight() - LeftPaddle.size.y - 5.f)) LeftPaddle.move(0.f, LeftPaddleSpeed * app.frameTime); // Move the computer's paddle if (((RightPaddleSpeed < 0.f) && (RightPaddle.position.y > 5.f)) || ((RightPaddleSpeed > 0.f) && (RightPaddle.position.y < app.view.getHeight() - RightPaddle.size.y - 5.f))) { RightPaddle.move(0.f, RightPaddleSpeed * app.frameTime); } // Update the computer's paddle direction according to the ball position AITimer.stop(); if (AITimer.milliseconds > AITime) { AITimer.start(); if ((RightPaddleSpeed < 0) && (Ball.position.y + Ball.size.y > RightPaddle.position.y + RightPaddle.size.y)) RightPaddleSpeed = -RightPaddleSpeed; if ((RightPaddleSpeed > 0) && (Ball.position.y < RightPaddle.position.y)) RightPaddleSpeed = -RightPaddleSpeed; } // Move the ball float Factor = BallSpeed * app.frameTime; Ball.move(cos(BallAngle) * Factor, sin(BallAngle) * Factor); // Check collisions between the ball and the screen if (Ball.position.x < 0.f) { IsPlaying = false; End.text("You lost !\n(press escape to exit)"c); } if (Ball.position.x + Ball.size.x > app.view.getWidth()) { IsPlaying = false; End.text("You won !\n(press escape to exit)"c); } if (Ball.position.y < 0.f) { BallSound.play(); BallAngle = -BallAngle; Ball.y = 0.1f; } if (Ball.position.y + Ball.size.y > app.view.getHeight()) { BallSound.play(); BallAngle = -BallAngle; Ball.y = app.view.getHeight() - Ball.size.y - 0.1f; } // Check the collisions between the ball and the paddles // Left Paddle if (Ball.position.x < LeftPaddle.position.x + LeftPaddle.size.x && Ball.position.x > LeftPaddle.position.x + (LeftPaddle.size.x / 2.0f) && Ball.position.y + Ball.size.y >= LeftPaddle.position.y && Ball.position.y <= LeftPaddle.position.y + LeftPaddle.size.y) { BallSound.play(); BallAngle = PI - BallAngle; Ball.x = LeftPaddle.position.x + LeftPaddle.size.x + 0.1f; } // Right Paddle if (Ball.position.x + Ball.size.x > RightPaddle.position.x && Ball.position.x + Ball.size.x < RightPaddle.position.x + (RightPaddle.size.x / 2.0f) && Ball.position.y + Ball.size.y >= RightPaddle.position.y && Ball.position.y <= RightPaddle.position.y + RightPaddle.size.y) { BallSound.play(); BallAngle = PI - BallAngle; Ball.x = RightPaddle.position.x - Ball.size.x - 0.1f; } } // Draw the background, paddles and ball sprites app.draw(LeftPaddle); app.draw(RightPaddle); app.draw(Ball); fpsClock.stop(); if(fpsClock.seconds >= 1) { fps.text = std.string.format("%d fps", iFps); iFps = 0; fpsClock.start(); } ++iFps; app.draw(fps); // If the game is over, display the end message if (!IsPlaying) app.draw(End); // Display things on screen app.display(); } }