Created
December 4, 2022 00:21
-
-
Save AaronO/11ca97312bb830649e15e0a062958fd4 to your computer and use it in GitHub Desktop.
GPT-Pong's code, created by ChatGPT, fixed by AaronO
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SpriteKit | |
import AVFoundation | |
class GameScene: SKScene { | |
// Create a ball node | |
let ball = SKShapeNode(circleOfRadius: 10) | |
// Create player paddles | |
let player1 = SKShapeNode(rectOf: CGSize(width: 10, height: 50)) | |
let player2 = SKShapeNode(rectOf: CGSize(width: 10, height: 50)) | |
// Create score labels | |
let player1ScoreLabel = SKLabelNode(text: "0") | |
let player2ScoreLabel = SKLabelNode(text: "0") | |
// Create a game state to track the score and ball velocity | |
var gameState = GameState() | |
// Track the touch positions for each player's paddle | |
var player1Touch: UITouch? | |
var player2Touch: UITouch? | |
// Create an emitter node for the confetti animation | |
let confettiEmitter = SKEmitterNode() | |
let EASY_DIFFICULTY: CGFloat = 99 | |
let MEDIUM_DIFFICULTY: CGFloat = 50 | |
let HARD_DIFFICULTY: CGFloat = 10 | |
override func didMove(to view: SKView) { | |
// Set the background color to black | |
self.backgroundColor = SKColor.black | |
// Set the ball properties | |
ball.position = CGPoint(x: frame.midX, y: frame.midY) | |
ball.fillColor = SKColor.white | |
ball.strokeColor = SKColor.white | |
addChild(ball) | |
// Set the player paddles' positions and colors | |
player1.position = CGPoint(x: frame.minX + 25, y: frame.midY) | |
player1.fillColor = SKColor.white | |
player1.strokeColor = SKColor.white | |
addChild(player1) | |
player2.position = CGPoint(x: frame.maxX - 25, y: frame.midY) | |
player2.fillColor = SKColor.white | |
player2.strokeColor = SKColor.white | |
addChild(player2) | |
// Set the score labels' positions and colors | |
player1ScoreLabel.position = CGPoint(x: frame.midX - 50, y: frame.maxY - 40) | |
player1ScoreLabel.fontColor = SKColor.white | |
addChild(player1ScoreLabel) | |
player2ScoreLabel.position = CGPoint(x: frame.midX + 50, y: frame.maxY - 40) | |
player2ScoreLabel.fontColor = SKColor.white | |
addChild(player2ScoreLabel) | |
// Set the ball's initial velocity | |
gameState.ballVelocity = CGVector(dx: 200, dy: 200) | |
// Create a circle shape node for the confetti texture | |
let confettiShape = SKShapeNode(circleOfRadius: 5) | |
confettiShape.fillColor = SKColor.white | |
confettiShape.strokeColor = SKColor.white | |
// Create an SKTexture object from the circle shape node | |
let confettiTexture = self.view!.texture(from: confettiShape) | |
// Configure the confetti emitter node | |
// confettiEmitter.particleTexture = SKTexture(imageNamed: "confetti") | |
confettiEmitter.particleTexture = confettiTexture | |
confettiEmitter.particleBirthRate = 300 | |
confettiEmitter.particleLifetime = 5 | |
confettiEmitter.particleColor = SKColor.green | |
confettiEmitter.particleColorBlendFactor = 1 | |
confettiEmitter.particleBlendMode = SKBlendMode.add | |
confettiEmitter.position = CGPoint(x: frame.midX, y: frame.minY) | |
confettiEmitter.particlePositionRange = CGVector(dx: frame.size.width/8, dy: frame.size.height/8) | |
confettiEmitter.particleSpeed = 100 | |
confettiEmitter.particleSpeedRange = 50 | |
confettiEmitter.emissionAngle = 3.14 | |
confettiEmitter.emissionAngleRange = 3.14 | |
confettiEmitter.particleAlpha = 1 | |
confettiEmitter.particleAlphaRange = 0.5 | |
confettiEmitter.particleAlphaSpeed = -1 | |
confettiEmitter.particleScale = 0.5 | |
confettiEmitter.particleScaleRange = 0.25 | |
confettiEmitter.particleScaleSpeed = -0.5 | |
confettiEmitter.particleRotation = 3.14 | |
confettiEmitter.particleRotationRange = 3.14 | |
confettiEmitter.particleRotationSpeed = -3 | |
confettiEmitter.particleLifetimeRange = 3 | |
} | |
override func update(_ interval: TimeInterval) { | |
// fixedby(Aaron): compute delta | |
let t = CGFloat(interval) | |
let delta = t - gameState.prevT | |
gameState.prevT = t | |
// Move the ball based on its velocity | |
ball.position.x += gameState.ballVelocity.dx * delta | |
ball.position.y += gameState.ballVelocity.dy * delta | |
// Check if the ball has collided with a paddle | |
if ball.frame.intersects(player1.frame) { | |
gameState.ballVelocity.dx = abs(gameState.ballVelocity.dx) | |
} else if ball.frame.intersects(player2.frame) { | |
gameState.ballVelocity.dx = -abs(gameState.ballVelocity.dx) | |
} | |
// Check if the ball has gone off the top or bottom of the screen | |
if ball.position.y > frame.maxY || ball.position.y < frame.minY { | |
gameState.ballVelocity.dy = -gameState.ballVelocity.dy | |
} | |
// Check if the ball has gone off the left or right side of the screen | |
if ball.position.x < frame.minX { | |
player2Scored() | |
didScore() | |
} else if ball.position.x > frame.maxX { | |
player1Scored() | |
didScore() | |
} | |
// Move the player paddles based on the touch positions | |
if let touch = player1Touch { | |
player1.position.y = touch.location(in: self).y | |
} | |
if let touch = player2Touch { | |
player2.position.y = touch.location(in: self).y | |
} | |
// AI control inactive players | |
if player1Touch == nil { | |
// Calculate the AI's next move based on the ball's position and velocity | |
let nextMove = calculateAIMove(player: player1, ball: ball, ballVelocity: gameState.ballVelocity, difficulty: HARD_DIFFICULTY) | |
// Update player 1's paddle position based on the AI's next move | |
player1.position.y += nextMove | |
} | |
if player2Touch == nil { | |
// Calculate the AI's next move based on the ball's position and velocity | |
let nextMove = calculateAIMove(player: player2, ball: ball, ballVelocity: gameState.ballVelocity, difficulty: EASY_DIFFICULTY) | |
// Update player 2's paddle position based on the AI's next move | |
player2.position.y += nextMove | |
} | |
} | |
// Calculate the AI's next move based on the ball's position and velocity | |
func calculateAIMove(player: SKShapeNode, ball: SKShapeNode, ballVelocity: CGVector, difficulty: CGFloat) -> CGFloat { | |
// Calculate the ball's projected position after a small time interval | |
let ballProjectedPosition = CGPoint( | |
x: ball.position.x + (ballVelocity.dx * 0.05), | |
y: ball.position.y + (ballVelocity.dy * 0.05) | |
) | |
// Calculate the AI's next move based on the ball's projected position | |
let nextMove = ballProjectedPosition.y - player.position.y | |
// Slow down the AI's movement based on the difficulty level | |
let movementSpeed = max(1 - difficulty / 100, 0) | |
let adjustedMove = nextMove * movementSpeed | |
// Limit the AI's next move to the screen's bounds | |
let minY = self.frame.minY + player.frame.height / 2; | |
let maxY = self.frame.maxY - player.frame.height / 2; | |
return max(min(adjustedMove, maxY), minY) | |
} | |
func player1Scored() { | |
// Increment player 1's score | |
gameState.player1Score += 1 | |
// Update the score label | |
player1ScoreLabel.text = "\(gameState.player1Score)" | |
// Reset the ball's position and velocity | |
ball.position = CGPoint(x: frame.midX, y: frame.midY) | |
gameState.ballVelocity = CGVector(dx: 200, dy: 200) | |
} | |
func player2Scored() { | |
// Increment player 2's score | |
gameState.player2Score += 1 | |
// Update the score label | |
player2ScoreLabel.text = "\(gameState.player2Score)" | |
// Reset the ball's position and velocity | |
ball.position = CGPoint(x: frame.midX, y: frame.midY) | |
gameState.ballVelocity = CGVector(dx: -200, dy: -200) | |
} | |
// Start the confetti animation when a player scores | |
func didScore() { | |
// Add the confetti emitter node to the scene | |
addChild(confettiEmitter) | |
confettiEmitter.resetSimulation() | |
confettiEmitter.run(SKAction.sequence([ | |
SKAction.wait(forDuration: 1), | |
SKAction.removeFromParent() | |
])) | |
// Victory sound | |
playVictorySound() | |
} | |
func playVictorySound() { | |
AudioServicesPlaySystemSound(1057) | |
} | |
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { | |
// Get the touch position | |
guard let touch = touches.first else { | |
return | |
} | |
let touchPosition = touch.location(in: self) | |
// Check which player's paddle the touch corresponds to | |
if touchPosition.x < frame.midX { | |
player1Touch = touch | |
} else { | |
player2Touch = touch | |
} | |
} | |
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { | |
// Get the touch position | |
guard let touch = touches.first else { | |
return | |
} | |
let touchPosition = touch.location(in: self) | |
// Check which player's paddle the touch corresponds to | |
if touchPosition.x < frame.midX { | |
player1Touch = touch | |
} else { | |
player2Touch = touch | |
} | |
} | |
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { | |
// Check which player's paddle the touch corresponds to | |
for touch in touches { | |
if touch == player1Touch { | |
player1Touch = nil | |
} else if touch == player2Touch { | |
player2Touch = nil | |
} | |
} | |
} | |
} | |
struct GameState { | |
var prevT = CGFloat(0) | |
var player1Score = 0 | |
var player2Score = 0 | |
var ballVelocity = CGVector.zero | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment