int SCREENW = 900 int SCREENH = 600 int scoreOne = 0 int scoreTwo = 0 float ballSpeed = 400 float paddleMoveSpeed = 600 float lerpSpeed = 14 bool aiOn = false // Main is always run at the VERY BEGINNING. Start() is the start of GRAPHICS // so if you never call ZS.Grapgics.Init, then Start won't run func Main() { // Immediately creates the window, then Start(), then the game loop. The game loop calls Update() every frame ZS.Graphics.Init("This is a pong game", SCREENW, SCREENH) } func Start() { float centerX = SCREENW / 2 float centerY = SCREENH / 2 global Vec2 centerOfScreen = NVec2(centerX, centerY) Vec2 ballScale = NVec2(10, 10) Vec2 ballPos = centerOfScreen Vec2 paddleScale = NVec2(4, 70) float yPosPaddle = centerOfScreen.y Vec2 lPaddlePosition = NVec2(15, yPosPaddle) global Vec2 lPaddleTargetPosition = NVec2(15, yPosPaddle) float rOffset = SCREENW - 15 Vec2 rPaddlePosition = NVec2(rOffset, yPosPaddle) global Vec2 rPaddleTargetPosition = NVec2(rOffset, yPosPaddle) global Sprite ballSpr = ZS.Graphics.Sprite("./square.png", ballPos, ballScale, 0) global Sprite lPaddle = ZS.Graphics.Sprite("./square.png", lPaddlePosition, paddleScale, 0) global Sprite rPaddle = ZS.Graphics.Sprite("./square.png", rPaddlePosition, paddleScale, 0) Vec2 netScale = NVec2(1, SCREENH) global Sprite net = ZS.Graphics.Sprite("./net.png", centerOfScreen, netScale, 0) float leftOffset = SCREENW / 4 Vec2 scoreOnePos = NVec2(leftOffset, 30) global Text scoreTextOne = ZS.Graphics.Text("0", "./arial.ttf", scoreOnePos, 60, 0, 255, 255, 255) float rightOffset = SCREENW - (SCREENW / 4) Vec2 scoreTwoPos = NVec2(rightOffset, 30) global Text scoreTextTwo = ZS.Graphics.Text("0", "./arial.ttf", scoreTwoPos, 60, 0, 255, 255, 255) Vec2 instructionsPos = NVec2(centerOfScreen.x, SCREENH - 60) global Text instructionsText = ZS.Graphics.Text("Use 'W' and 'S' or 'UP' and 'DOWN' arrows to control or press 'ENTER' to toggle AI", "./arial.ttf", instructionsPos, 20, 0, 255, 255, 255) global Vec2 ballVelocity = NVec2(ballSpeed, ballSpeed) } func Update(deltaTime) { float FPS = 1 / deltaTime print "FPS: " + FPS // Handles Left Paddle Movement // if GetKey("W") == true { float newX = lPaddle.position.x // Subtract from Y to move up, because vertical coordinates are reversed float newY = lPaddleTargetPosition.y - paddleMoveSpeed * deltaTime newY = Clamp(newY, 0 + lPaddle.scale.y / 2, SCREENH - lPaddle.scale.y / 2) lPaddleTargetPosition = NVec2(newX, newY) } if GetKey("S") == true { float newX = lPaddle.position.x // Add to Y to move down, because vertical coordinates are reversed float newY = lPaddleTargetPosition.y + paddleMoveSpeed * deltaTime newY = Clamp(newY, 0 + lPaddle.scale.y / 2, SCREENH - lPaddle.scale.y / 2) lPaddleTargetPosition = NVec2(newX, newY) } // Lerps from old position to destination smoothly float oldY = lPaddle.position.y float stopSpeed = deltaTime * lerpSpeed float newY = lPaddleTargetPosition.y float lerpedY = Lerp(oldY, newY, stopSpeed) lPaddle.position = NVec2(newX, lerpedY) // Handles Right Paddle Movement // if GetKey("UP") == true { if aiOn == false { float newX = rPaddle.position.x // Subtract from Y to move up, because vertical coordinates are reversed float newY = rPaddleTargetPosition.y - paddleMoveSpeed * deltaTime newY = Clamp(newY, 0 + rPaddle.scale.y / 2, SCREENH - rPaddle.scale.y / 2) rPaddleTargetPosition = NVec2(newX, newY) } } if GetKey("DOWN") == true { if aiOn == false { float newX = rPaddle.position.x // Add to Y to move down, because vertical coordinates are reversed float newY = rPaddleTargetPosition.y + paddleMoveSpeed * deltaTime newY = Clamp(newY, 0 + rPaddle.scale.y / 2, SCREENH - rPaddle.scale.y / 2) rPaddleTargetPosition = NVec2(newX, newY) } } if aiOn == true { if rPaddle.position.y < ballSpr.position.y { float newX = rPaddle.position.x // Add to Y to move down, because vertical coordinates are reversed float newY = rPaddleTargetPosition.y + paddleMoveSpeed * deltaTime newY = Clamp(newY, 0 + rPaddle.scale.y / 2, SCREENH - rPaddle.scale.y / 2) rPaddleTargetPosition = NVec2(newX, newY) } if rPaddle.position.y > ballSpr.position.y { float newX = rPaddle.position.x // Subtract from Y to move up, because vertical coordinates are reversed float newY = rPaddleTargetPosition.y - paddleMoveSpeed * deltaTime newY = Clamp(newY, 0 + rPaddle.scale.y / 2, SCREENH - rPaddle.scale.y / 2) rPaddleTargetPosition = NVec2(newX, newY) } } // Lerps from old position to destination smoothly float oldY = rPaddle.position.y float stopSpeed = deltaTime * lerpSpeed float newY = rPaddleTargetPosition.y float lerpedY = Lerp(oldY, newY, stopSpeed) rPaddle.position = NVec2(newX, lerpedY) if GetKey("ENTER") == true { if aiOn == true { aiOn = false } if aiOn == false { aiOn = true } } Vec2 scaledVelocity = ballVelocity scaledVelocity *= deltaTime ballSpr.position += scaledVelocity // Finally draws all of the sprites ZS.Graphics.Draw(ballSpr) ZS.Graphics.Draw(lPaddle) ZS.Graphics.Draw(rPaddle) ZS.Graphics.Draw(net) ZS.Graphics.DrawText(scoreTextOne) ZS.Graphics.DrawText(scoreTextTwo) ZS.Graphics.DrawText(instructionsText) HandleBallBounce() } func HandleBallBounce() { float ballX = ballSpr.position.x float ballY = ballSpr.position.y float scaleY = ballSpr.scale.y float topEdge = ballY - scaleY/2 // Checks if the ball is touching the ceiling if topEdge <= 0 { float vX = ballVelocity.x float vY = ballVelocity.y vY *= -1 ballVelocity = NVec2(vX, vY) return 0 } float bottomEdge = ballY + scaleY/2 // Checks if the ball is touching the floor if bottomEdge >= SCREENH { float vX = ballVelocity.x float vY = ballVelocity.y vY *= -1 ballVelocity = NVec2(vX, vY) return 0 } // Checks if ball is in player 1 goal if ballX < 0 { Vec2 ballPos = centerOfScreen ballPos -= ballSpr.scale ballPos.x -= SCREENW / 3 scoreTwo += 1 ballSpr.position = ballPos ballVelocity = NVec2(ballSpeed, 0) scoreTextTwo.content = Round(scoreTwo) } // Checks if ball is in player 2 goal if ballX > SCREENW { Vec2 ballPos = centerOfScreen ballPos -= ballSpr.scale ballPos.x += SCREENW / 3 scoreOne += 1 ballSpr.position = ballPos ballVelocity = NVec2(-ballSpeed, 0) scoreTextOne.content = Round(scoreOne) } // Checks if colliding with left paddle bool coll = Colliding(ballSpr, lPaddle) if coll == true { float difference = lPaddle.position.y difference -= ballY float paddleHeight = lPaddle.scale.y float normalizedRelativeIntersectionY = difference / (paddleHeight / 2) float bounceAngle = normalizedRelativeIntersectionY * 0.523599 float ballVx = ballSpeed ballVx *= Cos(bounceAngle) float ballVy = ballSpeed ballVy *= Sin(bounceAngle) ballVy *= -1 ballVelocity = NVec2(ballVx, ballVy) } // Checks if colliding with right paddle bool coll = Colliding(ballSpr, rPaddle) if coll == true { float difference = rPaddle.position.y difference -= ballY float paddleHeight = rPaddle.scale.y float normalizedRelativeIntersectionY = difference / (paddleHeight / 2) float bounceAngle = normalizedRelativeIntersectionY * 0.523599 float ballVx = ballSpeed ballVx *= Cos(bounceAngle) ballVx *= -1 float ballVy = ballSpeed ballVy *= Sin(bounceAngle) ballVelocity = NVec2(ballVx, ballVy) } } func Colliding(a, b) { bool b = ZS.Physics.AxisAlignedCollision(a, b) return b }