Created
April 5, 2010 12:29
-
-
Save dbr/356294 to your computer and use it in GitHub Desktop.
Pong. In Nuke.
This file contains 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
"""Pong. | |
In Nuke. | |
""" | |
import nuke | |
import time | |
from random import random | |
import threading | |
class Player1Score(Exception): | |
pass | |
class Player2Score(Exception): | |
pass | |
class Ball(object): | |
def __init__(self, node): | |
self.node = node | |
self.vx = 4 | |
self.vy = 0 | |
# Number of nudge()'s since last collision. | |
# Used to prevent multiple collisions on the same object in | |
# quick sucession (which makes the ball get stuck in the object) | |
self.steps_since_collision = 0 | |
self.delay_between_collisions = 5 | |
# Getter/setter for ball location | |
def _setxy(self, v): | |
x, y = v | |
nuke.executeInMainThread(self.node.setXYpos, (x, y)) | |
time.sleep(0.001) | |
def _getxy(self): | |
x = self.node.xpos() | |
y = self.node.ypos() | |
return x, y | |
xy = property(_getxy, _setxy) | |
def nudge(self): | |
"""Moves ball with x/y velocity""" | |
x, y = self.xy | |
self.xy = (x + self.vx, y + self.vy) | |
self.steps_since_collision += 1 | |
def reset(self, gamebox): | |
"""Reset ball to centre. Reset velocity""" | |
x, y = gamebox.xpos(), gamebox.ypos() | |
w, h = gamebox.screenWidth(), gamebox.screenHeight() | |
cx = x + (w/2) | |
cy = y + (h/2) | |
r = 2 - (random() * 4) | |
if self.vx > 0: | |
self.vx, self.vy = 4, 0 | |
else: | |
self.vx, self.vy = -4, 0 | |
nuke.executeInMainThread(self.node.setXYpos, (cx, cy)) | |
def check_paddle(self, paddle): | |
"""Checks collision with paddles""" | |
if self.steps_since_collision < self.delay_between_collisions: | |
return | |
x, y = self.xy | |
cx, cy = paddle.xpos(), paddle.ypos() | |
cw, ch = paddle.screenWidth(), paddle.screenHeight() | |
if y > cy and y < (cy + ch): | |
# In correct y location | |
if (x > (cx)) and (x < (cx + cw)): | |
self.vx = -self.vx | |
# Add randomness to bounce | |
self.vy = self.vy + (1.0 - (random() * 2.0)) | |
self.nudge() | |
self.steps_since_collision = 0 | |
def check_gamebox(self, gamebox): | |
"""Checks for collisions with the edge of game box, and raises the | |
appropriate Player{n}Score exception""" | |
if self.steps_since_collision < self.delay_between_collisions: | |
return | |
sx, sy = gamebox.xpos(), gamebox.ypos() | |
w, h = gamebox.screenWidth(), gamebox.screenHeight() | |
maxx = sx + w | |
maxy = sy + h | |
x, y = self.xy | |
if x < sx: | |
self.vx = -self.vx | |
self.nudge() | |
self.steps_since_collision = 0 | |
raise Player1Score() | |
elif x > maxx: | |
self.vx = -self.vx | |
self.nudge() | |
self.steps_since_collision = 0 | |
raise Player2Score() | |
elif y < sy: | |
self.vy = -self.vy | |
self.nudge() | |
x, y = self.xy | |
self.xy = (x, sy) | |
self.steps_since_collision = 0 | |
elif y > maxy: | |
self.vy = -self.vy | |
self.nudge() | |
x, y = self.xy | |
self.xy = (x, maxy) | |
self.steps_since_collision = 0 | |
class Game(threading.Thread): | |
def __init__(self, gamebox, ball, player1, player2): | |
threading.Thread.__init__(self) | |
self.gamebox = gamebox | |
self.ball = ball | |
self.left = player1 | |
self.right = player2 | |
self.ball = Ball(self.ball) | |
self.stop = False | |
def deletenodes(self): | |
for x in [self.gamebox, self.left, self.right]: | |
nuke.delete(nuke.toNode(x.name())) | |
nuke.delete(self.ball.node) | |
def gameloop(self): | |
self.ball.reset(self.gamebox) | |
time.sleep(0.1) | |
while not self.stop: | |
self.ball.nudge() | |
toincrement = None | |
try: | |
self.ball.check_gamebox(self.gamebox) | |
except Player1Score: | |
print "Player 1 scored" | |
toincrement = self.gamebox['p1_score'] | |
except Player2Score: | |
print "Player 2 scored" | |
toincrement = self.gamebox['p2_score'] | |
if toincrement is not None: | |
cur = nuke.executeInMainThreadWithResult(toincrement.value) | |
if cur is None: | |
cur = 0 | |
new = cur + 1 | |
nuke.executeInMainThreadWithResult(toincrement.setValue, new) | |
self.ball.reset(self.gamebox) | |
self.ball.check_paddle(paddle = self.left) | |
self.ball.check_paddle(paddle = self.right) | |
time.sleep(0.01) | |
def run(self): | |
try: | |
self.gameloop() | |
except Exception, e: | |
# Exception in thread doesn't give a useful traceback | |
# to Nuke console, print one. | |
import traceback | |
traceback.print_exc() | |
raise | |
def _nudgeplayer(node, vertical): | |
y = node.ypos() | |
node.setYpos(y + vertical) | |
def nudge_up(left = False, right = False, large = False): | |
global pong | |
if left: | |
node = pong.left | |
elif right: | |
node = pong.right | |
else: | |
raise ValueError("left or right must be True") | |
_nudgeplayer(node, -40 if large else -20) | |
def nudge_down(left = False, right = False, large = False): | |
global pong | |
if left: | |
node = pong.left | |
elif right: | |
node = pong.right | |
else: | |
raise ValueError("left or right must be True") | |
_nudgeplayer(node, 40 if large else 20) | |
global pong | |
pong = None | |
def stop_pong(): | |
global pong | |
if pong is None: | |
return | |
else: | |
print "Stopping pong.." | |
pong.stop = True | |
pong.join() | |
pong.deletenodes() | |
pong = None | |
def start_pong(): | |
stop_pong() | |
# Make game box | |
gamebox = nuke.toNode("PONG") | |
if gamebox is None: | |
gamebox = nuke.nodes.BackdropNode(bdwidth = 1000, bdheight = 500) | |
p1s = nuke.Int_Knob('p1_score', 'player 1 score') | |
p2s = nuke.Int_Knob('p2_score', 'player 2 score') | |
gamebox.addKnob(p1s) | |
gamebox.addKnob(p2s) | |
gamebox['tile_color'].setValue(1) | |
ball = nuke.toNode("ball") | |
if ball is None: | |
ball = nuke.nodes.Dot() | |
# Make paddles | |
player1, player2 = nuke.toNode("player1"), nuke.toNode("player2") | |
if player1 is None: | |
player1 = nuke.nodes.BackdropNode(bdwidth = 40, bdheight = 100, name = "player1") | |
player1.setXpos(gamebox.xpos()) | |
if player2 is None: | |
player2 = nuke.nodes.BackdropNode(bdwidth = 40, bdheight = 100, name = "player2") | |
player2.setXpos( | |
(gamebox.xpos() + (gamebox.screenWidth() - 40))) | |
global pong | |
pong = Game( | |
gamebox = gamebox, | |
ball = ball, | |
player1 = player1, | |
player2 = player2) | |
pong.start() | |
def main(): | |
mn = nuke.menu("Nodes") | |
mp = mn.addMenu("Pong") | |
mp.addCommand( | |
"start pong", | |
lambda: start_pong(), | |
"alt+p") | |
mp.addCommand("stop pong", | |
lambda: stop_pong(), | |
"alt+q") | |
mp.addSeparator() | |
mp.addCommand("p1 - up", | |
lambda: nudge_up(left=True), | |
"Up") | |
mp.addCommand("p1 - up large", | |
lambda: nudge_up(left=True, large=True), | |
"Shift+Up") | |
mp.addCommand("p1 - down", | |
lambda: nudge_down(left=True), | |
"Down") | |
mp.addCommand("p1 - down large", | |
lambda: nudge_down(left=True, large=True), | |
"Shift+Down") | |
mp.addSeparator() | |
mp.addCommand("p2 - up", | |
lambda: nudge_up(right=True), | |
"w") | |
mp.addCommand("p2 - up large", | |
lambda: nudge_up(right=True, large=True), | |
"Shift+w") | |
mp.addCommand("p2 - down", | |
lambda: nudge_down(right=True), | |
"s") | |
mp.addCommand("p2 - down large", | |
lambda: nudge_down(right=True, large=True), | |
"Shift+s") | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment