
-----------------------------------
TheOneTrueGod
Sat May 27, 2006 11:09 pm

Pong w/ classes
-----------------------------------
Since theres SO many pong programs out there, I decided to do something different to demonstrate the power of classes.  At first glance, the game doesn't look like much, it just looks like normal pong, but in this version, it would take like 5 lines to do something like, add 5 extra balls, give each player two paddles, etc...
class Ball
    export Create, Manage, Scored, ReverseXSpeed, X, Y
    var x, y, xs, ys : real

    procedure Create (x_, y_ : real)
        x := x_
        y := y_
        xs := Rand.Int (100, 200) / 100 * (Rand.Int (0, 1) * 2 - 1)
        ys := Rand.Int (100, 200) / 100 * (Rand.Int (0, 1) * 2 - 1)
    end Create

    function X : real
        result x
    end X
    function Y : real
        result y
    end Y

    procedure Manage
        if y + ys > maxy or y + ys < 0 then
            ys *= -1
        end if
        x += xs
        y += ys
        drawfilloval (round (x), round (y), 5, 5, black)
        drawoval (round (x), round (y), 5, 5, grey)

    end Manage
    function Scored : int
        if x < 0 then
            result 1
        elsif x > maxx then
            result 2
        end if
        result 0
    end Scored
    procedure ReverseXSpeed (newX : int)
        x := newX
        xs := xs * -1 * Rand.Int (130, 160) / 100
        ys := ys * Rand.Int (110, 120) / 100
    end ReverseXSpeed
end Ball

var pervasive keys : array char of boolean

class Paddle
    import Ball
    export Create, Manage, CheckForCollision
    var x, y : int
    var speed, ysize, xsize : int
    var UPKEY, DOWNKEY : int
    procedure Create (x_, y_ : int, UPKEY_, DOWNKEY_ : int, xsize_, ysize_ : int)
        x := x_
        y := y_
        UPKEY := UPKEY_
        DOWNKEY := DOWNKEY_
        speed := 3
        ysize := ysize_
        xsize := xsize_ div 2
    end Create
    procedure Manage
        if keys (chr (UPKEY)) and y + ysize < maxy then
            y += speed
        end if
        if keys (chr (DOWNKEY)) and y > 0 then
            y -= speed
        end if
        drawfillbox (x - xsize, y, x + xsize, y + ysize, grey)
        drawbox (x - xsize, y, x + xsize, y + ysize, black)
    end Manage
    procedure CheckForCollision (var b : ^Ball)
        if b -> Y > y and b -> Y < y + ysize and b -> X > x - xsize and b -> X < x + xsize then
            if b -> X < x then
                b -> ReverseXSpeed (x - xsize - 1)
            else
                b -> ReverseXSpeed (x + xsize + 1)
            end if

        end if
    end CheckForCollision
end Paddle

var b : array 1 .. 1 of ^Ball
var p : array 1 .. 2 of ^Paddle
var leftScore, rightScore : int := 0

new Paddle, p (1)
new Paddle, p (2)
new Ball, b (1)

p (1) -> Create (5, maxy div 2, ord ('w'), ord ('s'), 5, 50)
p (2) -> Create (maxx - 5, maxy div 2, ord ('w'), ord ('s'), 5, 50)
b (1) -> Create (maxx div 2, maxy div 2)

View.Set ('offscreenonly')

loop
    Input.KeyDown (keys)
    locate (1, maxcol div 2 - length (intstr (leftScore)))
    drawline (maxx div 2, maxy, maxx div 2, 0, black)
    put leftScore, ":", rightScore
    
    for i : 1 .. 2
        p (i) -> Manage
        for j : 1 .. upper (b)
            p (i) -> CheckForCollision (b (j))
        end for
    end for
    
    for i : 1 .. upper (b)
        b (i) -> Manage
        if b (i) -> Scored not= 0 then
            if b (i) -> Scored = 1 then
                leftScore += 1
            elsif b (i) -> Scored = 2 then
                rightScore += 1
            end if
            b (i) := b (upper (b))
            b (upper (b)) -> Create (maxx div 2, maxy div 2)
        end if
    end for
    View.Update
    Time.DelaySinceLast (25)
    cls
end loop

And heres a sample of what you can do with like 3 lines of change.
(Just replace everything after the end of the classes with this code)


var b : array 1 .. 5 of ^Ball
var p : array 1 .. 6 of ^Paddle
var leftScore, rightScore : int := 0

for i : 1 .. upper (p)
    new Paddle, p (i)
end for
for i : 1 .. upper (b)
    new Ball, b (i)
end for

%Left Player
p (1) -> Create (5, maxy div 2, ord ('w'), ord ('s'), 5, 50, 4)
p (3) -> Create (5, maxy div 2, ord ('s'), ord ('w'), 5, 50, 4)
p (5) -> Create (maxx div 4, maxy div 2, ord ('w'), ord ('s'), 15, 50, 4)

%Right Player
p (2) -> Create (maxx - 5, maxy div 2, ord (KEY_UP_ARROW), ord (KEY_DOWN_ARROW), 5, 50, 4)
p (4) -> Create (maxx - 5, maxy div 2, ord (KEY_DOWN_ARROW), ord (KEY_UP_ARROW), 5, 50, 4)
p (6) -> Create (maxx div 4 * 3, maxy div 2, ord (KEY_UP_ARROW), ord (KEY_DOWN_ARROW), 15, 50, 4)
for i : 1 .. upper (b)
    b (i) -> Create (maxx div 2, maxy div 2)
end for

View.Set ('offscreenonly')

loop
    Input.KeyDown (keys)
    locate (1, maxcol div 2 - length (intstr (leftScore)))
    drawline (maxx div 2, maxy, maxx div 2, 0, black)
    put leftScore, ":", rightScore

    for i : 1 .. upper (p)
        p (i) -> Manage
        for j : 1 .. upper (b)
            p (i) -> CheckForCollision (b (j))
        end for
    end for

    for i : 1 .. upper (b)
        b (i) -> Manage
        if b (i) -> Scored not= 0 then
            if b (i) -> Scored = 1 then
                leftScore += 1
            elsif b (i) -> Scored = 2 then
                rightScore += 1
            end if
            b (i) := b (upper (b))

            b (upper (b)) := nil
            new Ball, b (upper (b))
            b (upper (b)) -> Create (maxx div 2, maxy div 2)
        end if
    end for
    View.Update
    Time.DelaySinceLast (25)
    cls
end loop


-----------------------------------
Cervantes
Sun May 28, 2006 8:44 am


-----------------------------------
Good stuff. It really does my heart good to see more OOP code floating around the Turing forums than there was before. :)

One suggestion I have, however: Instead of making keys a pervasive variable, you could pass it in as a parameter to Paddle#Manage. Global variables are a pretty evil thing.

-----------------------------------
TheOneTrueGod
Sun May 28, 2006 9:59 am


-----------------------------------
I've heard that several times, but i've allways wondered why?  They detract from modularity, I believe, but somehow, I doubt that someone's going to be taking my paddle class and using it anyways  :wink:.
