Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1665 pj 1
//////////////////////////////////////////////////////////////////
2
// Pong
3
// Written for CS 324, UIUC
4
// Spencer Hoke
5
// James Kim
6
// Tao Luo
7
//
8
// Last Modified: April 29, 2004
9
 
10
#include "pong.h"
11
 
12
///////////////////////////////////////
13
// sets initial values of global variables
14
void setglobals() {
15
    P_MASS = 100;
16
    kp = 30;
17
    kd = 20;                 // > sqrt(4*(XMAX - XMIN)* kp)
18
    AI_VIEWING_RANGE = 250;  // window = YMAX - this
19
 
20
    balllist = NULL;
21
 
22
    num_balls = 0;           // number of balls currently in system
23
    min_balls = 0;           // minimum number of balls in the system
24
    locked = 0;              // 1 if #balls kept constant
25
    ball_spd = 5;            // ballspeed (default = 5)
26
 
27
    p_speed = 10;            // # pixels to move each keypress
28
    p1_length = 150;         // size of the paddles
29
    p2_length = 75;          // size of the paddles
30
 
31
    p1_pos = (XMAX + XMIN - p1_length)/2;  // initialize starting paddle positions
32
    p2_pos = (XMAX + XMIN - p2_length)/2;
33
    p2_target_pos = p2_pos;  // initially no movement
34
 
35
    points1 = 0;             // scores for each side
36
    points2 = 0;
37
}
38
 
39
///////////////////////////////////////
40
// center at (x,y) with radius RAD and color c
41
void draw_ball(int x, int y, int c) {
42
    mutex_lock(&draw_mutex);
43
    grx_disc(x, y, RAD, c);
44
    mutex_unlock(&draw_mutex);
45
}
46
 
47
///////////////////////////////////////
48
// top left corner is (x,y), length is l,
49
// thickness is P_THICKNESS, and color is c
50
void draw_paddle(int x, int y, int l, int c) {
51
    mutex_lock(&draw_mutex);
52
    grx_box(x, y, x + l, y + P_THICKNESS, c);
53
    mutex_unlock(&draw_mutex);
54
}
55
 
56
///////////////////////////////////////
57
// draws a line where the computer's viewing window starts
58
void draw_viewwin(int col) {
59
    mutex_lock(&draw_mutex);
60
    grx_line(XMIN-RAD, AI_VIEWING_RANGE+YMIN, XMAX+RAD, AI_VIEWING_RANGE+YMIN, col);
61
    mutex_unlock(&draw_mutex);
62
}
63
 
64
///////////////////////////////////////
65
void print_scores() {
66
    char st1[15], st2[15];
67
 
68
    sprintf(st1, "Player 1:%6d", points1);
69
    sprintf(st2, "Player 2:%6d", points2);
70
    mutex_lock(&draw_mutex);
71
    grx_text(st1, XMIN-RAD-1, 20, blue, black);
72
    grx_text(st2, XMIN-RAD-1, 30, red, black);
73
    mutex_unlock(&draw_mutex);
74
}
75
 
76
///////////////////////////////////////
77
void print_numballs() {
78
    char st[15];
79
 
80
    sprintf(st, "Num balls:%3d", num_balls);
81
    mutex_lock(&draw_mutex);
82
    grx_text(st, XMAX-100, 20, magenta, black);
83
    mutex_unlock(&draw_mutex);
84
}
85
 
86
///////////////////////////////////////
87
void print_constants() {
88
    char st[15];
89
 
90
    sprintf(st, "kp:%3d, kd:%3d, mass:%4d", kp, kd, P_MASS);
91
    mutex_lock(&draw_mutex);
92
    grx_text(st, XMIN-RAD-1, YMAX+20, magenta, black);
93
    mutex_unlock(&draw_mutex);
94
}
95
 
96
///////////////////////////////////////
97
TASK ball(void *arg) {
98
    int     x, y;             // current position
99
    int     oldx, oldy;       // last position
100
    int     dx, dy;           // delta x, y
101
    int     theta, col;
102
    double  r;                // theta in radians
103
    int     p1len, p2len, p1pos, p2pos;   // temp storage of length and position
104
    int     outx;
105
    int     hitp1, hitp2;        // 1 if ball has hit paddle
106
    int     in1, in2;            // 1 if ball is currently inside paddle (error)
107
    struct  ballinfo myinfo;     // shared x/y/theta
108
 
109
    myinfo.x = x = oldx = XMIN;             // start in middle of the left
110
    myinfo.y = y = oldy = (YMIN+YMAX)/2;
111
    col = rand()%14 + 2;         // color ball
112
 
113
    // insert myinfo into global list
114
    mutex_lock(&list_mutex);
115
    if(balllist != NULL)   // update old first entry in list
116
        balllist->prev = &myinfo;
117
    myinfo.next = balllist;
118
    myinfo.prev = NULL;
119
    balllist = &myinfo;
120
    mutex_unlock(&list_mutex);
121
 
122
    //  starting angle = [ANGMIN,ANGMAX]
123
    theta = rand()%(ANGMAX - ANGMIN) + ANGMIN;
124
    if (rand()%2 == 1) // random starting direction
125
        theta *= -1;
126
    if (theta > 360) theta -= 360;
127
    if (theta < 0) theta += 360;
128
    myinfo.theta = theta;
129
    r = (double)theta * PI / 180.;
130
 
131
    while (1) {
132
        dx = (float)(ball_spd * cos(r));
133
        dy = (float)(ball_spd * sin(r));
134
        x += dx;
135
        y += dy;
136
 
137
        // check boundary conditions
138
        if (y >= YMAX) {  // end task and score point for player 2
139
            points1++;
140
            break;
141
        }
142
        if (y <= YMIN) {  // end task and score point for player 1
143
            points2++;
144
            break;
145
        }
146
 
147
        p1len = p1_length;  // copy globals
148
        p1pos = p1_pos;
149
        p2len = p2_length;
150
        p2pos = p2_pos;
151
 
152
        outx = (x >= XMAX) || (x <= XMIN);
153
        hitp1 = (y <= (YMIN + 2*RAD + P_THICKNESS)) // y is within range of paddle
154
                && (x >= (p1pos - RAD)) && (x <= (p1pos + p1len + RAD)); // x is within range of paddle
155
        hitp2 = (y >= (YMAX - 2*RAD - P_THICKNESS)) // y is within range of paddle
156
                && (x >= (p2pos - RAD)) && (x <= (p2pos + p2len + RAD)); // x is within range of paddle
157
 
158
        // need these in case ball goes in the side of the paddle
159
        in1 = (oldy <= (YMIN + 2*RAD + P_THICKNESS)) // oldy is within range of paddle
160
                && (oldx >= (p1pos - RAD)) && (oldx <= (p1pos + p1len + RAD)); // oldx is within range of paddle
161
        in2 = (oldy >= (YMAX - 2*RAD - P_THICKNESS)) // oldy is within range of paddle
162
                && (oldx >= (p2pos - RAD)) && (oldx <= (p2pos + p2len + RAD)); // oldx is within range of paddle
163
 
164
        if (outx || ((hitp1 || hitp2) && !in1 && !in2)) { // ball needs to bounce
165
            x -= dx;
166
            y -= dy;
167
            if (outx) theta = 180 - theta;                        // bounce off wall
168
            if ((hitp1 || hitp2) && !in1 && !in2) theta = -theta; // bounce off paddle
169
 
170
            if (theta > 360) theta -= 360;
171
            else if (theta < 0) theta += 360;
172
 
173
            r = (double)theta * PI / 180.;
174
            x += (float)(ball_spd * cos(r));
175
            y += (float)(ball_spd * sin(r));
176
        }
177
 
178
        draw_ball(oldx, oldy, black);       // clear old position
179
        draw_ball(x, y, col);               // draw new ball
180
        oldx = x; oldy = y;
181
 
182
        mutex_lock(&list_mutex);      // updates values in list
183
        myinfo.x = x;
184
        myinfo.y = y;
185
        myinfo.theta = theta;
186
        mutex_unlock(&list_mutex);
187
 
188
        task_endcycle();
189
    }
190
 
191
    // remove myinfo from list
192
    mutex_lock(&list_mutex);
193
    if(myinfo.next != NULL)
194
        (myinfo.next)->prev = myinfo.prev;
195
 
196
    if(myinfo.prev != NULL)
197
        (myinfo.prev)->next = myinfo.next;
198
    else
199
        balllist = myinfo.next;
200
    mutex_unlock(&list_mutex);
201
 
202
    draw_ball(oldx, oldy, 0); // clear ball
203
    print_scores();           // update score
204
    num_balls--;              // remove ball from system
205
    if(!locked)
206
        print_numballs();     // update count of balls
207
    return NULL;
208
}
209
 
210
///////////////////////////////////////
211
void addball() {
212
    HARD_TASK_MODEL m;
213
    PID pid;
214
 
215
    hard_task_default_model(m);
216
    hard_task_def_ctrl_jet (m);
217
    hard_task_def_wcet     (m, BALL_WCET);
218
    hard_task_def_mit      (m, BALL_PER);
219
    hard_task_def_group    (m, BALLGROUP);
220
    hard_task_def_usemath  (m);
221
    pid = task_create("ball", ball, &m, NULL);
222
    if (pid == NIL) {
223
        grx_close();
224
        sys_shutdown_message("Could not create task <ball> errno=%d", errno);
225
        sys_abort(errno);
226
    }
227
    task_activate(pid);
228
    num_balls++;
229
    print_numballs();
230
}
231
 
232
///////////////////////////////////////
233
// paddle 1 controller
234
TASK paddle1(void *arg) {
235
    int oldpos, newpos;
236
    int move, oldlength, length;
237
 
238
    oldpos = newpos = p1_pos;
239
    oldlength = -1;            // force draw initially
240
 
241
    while (1) {
242
        length = p1_length;    // need to copy in case they change
243
        move = p1_move;
244
        p1_move -= move;       // update global variable
245
 
246
        // get new position of ball
247
        newpos += move * p_speed;
248
        if(newpos < XMIN) // tried to move too far right
249
            newpos = XMIN;
250
        else if(newpos > (XMAX - length)) // tried to move too far left
251
            newpos = XMAX - length;
252
 
253
        if ((newpos != oldpos) || (length != oldlength)) { // need to redraw the paddle
254
            p1_pos = newpos;  // update global position
255
            draw_paddle(oldpos, YMIN + RAD, oldlength, black);  // clear old paddle
256
            draw_paddle(newpos, YMIN + RAD, length, blue);  // draw new one
257
            oldpos = newpos;
258
            oldlength = length;
259
        }
260
        else
261
            draw_paddle(newpos, YMIN + RAD, length, blue);  // refresh paddle
262
 
263
        task_endcycle();
264
    }
265
}
266
 
267
///////////////////////////////////////
268
// determines target position of paddle 2
269
TASK p2ai(void *arg) {
270
    int     proj;    // projected length to y-value of paddle
271
    int     closestBallY_Location = 0;
272
    int     closestBallX_Location = 0;
273
    int         closestBallY_Angle = 0;
274
    int     closestToPaddle;
275
    int         projectedX_Location = 0;
276
    int     foundBall;
277
    double  r;                  // angle in radians
278
    struct ballinfo *cur;
279
    char st[20];
280
 
281
     while(1) {
282
        if (num_balls != 0) { // if there are balls
283
            //finds the closest ball and its position and angle
284
            closestBallY_Location = AI_VIEWING_RANGE + YMIN;
285
            closestToPaddle = 1000000;       // large default number
286
            foundBall = 0;
287
 
288
            mutex_lock(&list_mutex);
289
            for (cur = balllist; cur != NULL; cur = cur->next) {
290
                if (cur->y > closestBallY_Location         // within window
291
                    && cur->y < (YMAX - RAD - P_THICKNESS) // not past paddle already
292
                    && cur->theta < 180)                   // going toward paddle
293
                {
294
                    r = (double)(cur->theta) * PI / 180.;
295
                    proj = (float)( (YMAX - RAD - P_THICKNESS - cur->y) / sin(r) );  // geometry
296
                    if(proj < closestToPaddle) { // this is the closest one
297
                        foundBall = 1;
298
                        closestBallY_Location = cur->y;
299
                        closestBallX_Location = cur->x;
300
                        closestBallY_Angle = cur->theta;
301
                        closestToPaddle = proj;
302
                    }
303
                }
304
            }
305
            mutex_unlock(&list_mutex);
306
 
307
            //finds where it needs to move to
308
            if (foundBall == 1) {
309
                r = (double)closestBallY_Angle * PI / 180.;
310
                projectedX_Location = (float)( (YMAX - RAD - P_THICKNESS - closestBallY_Location) / tan(r) );  // geometry
311
                projectedX_Location += closestBallX_Location;
312
 
313
                while(projectedX_Location < XMIN || projectedX_Location > XMAX) { // adjust for ball bounces
314
                    if(projectedX_Location < XMIN)
315
                        projectedX_Location = 2*XMIN - projectedX_Location;  // bounce off left side
316
                    if(projectedX_Location > XMAX)
317
                        projectedX_Location = 2*XMAX - projectedX_Location;  // bounce off right side
318
                }
319
 
320
                sprintf(st, "Proj X: %3d", projectedX_Location);
321
                mutex_lock(&draw_mutex);
322
                grx_text(st, XMAX-85, YMAX+20, magenta, black);
323
                mutex_unlock(&draw_mutex);
324
 
325
                p2_target_pos = projectedX_Location - p2_length/2;   // copy into target for p2
326
            }
327
        }
328
 
329
        task_endcycle();
330
    }
331
}
332
 
333
///////////////////////////////////////
334
// paddle 2 controller - applies forces and draws paddle
335
TASK paddle2(void *arg) {
336
    int     oldpos, newpos;
337
    int     positionErrorX, oldlength, length;
338
    int     force = 0, acceleration = 0, velocity = 0;    // paddle movement
339
 
340
    oldpos = newpos = p2_pos;
341
    oldlength = -1;            // force draw initially
342
 
343
    while (1) {
344
        length = p2_length;    // need to copy in case they change
345
        positionErrorX = p2_target_pos - oldpos;
346
 
347
        //Applying force
348
        force = kp * positionErrorX - kd * velocity;
349
        acceleration = force / P_MASS;
350
 
351
        velocity += acceleration;      // new velocity
352
        newpos = oldpos + velocity;    // using new velocity, so incorporates acceleration
353
 
354
        if(newpos < XMIN) // tried to move too far right
355
            newpos = XMIN;
356
        else if(newpos > (XMAX - length)) // tried to move too far left
357
            newpos = XMAX - length;
358
 
359
        if ((newpos != oldpos) || (length != oldlength)) { // need to redraw the paddle
360
            p2_pos = newpos;  // update global position
361
            draw_paddle(oldpos, YMAX - P_THICKNESS - RAD, oldlength, black);  // clear old paddle
362
            draw_paddle(newpos, YMAX - P_THICKNESS - RAD, length, red);  // draw new one
363
            oldpos = newpos;
364
            oldlength = length;
365
        }
366
        else
367
            draw_paddle(newpos, YMAX - P_THICKNESS - RAD, length, red);  // refresh paddle
368
 
369
        task_endcycle();
370
    }
371
}
372
 
373
///////////////////////////////////////
374
TASK countmon(void *arg) {
375
    while(1) {
376
        while(num_balls < min_balls)
377
            addball();
378
        task_endcycle();
379
    }
380
}
381
 
382
///////////////////////////////////////
383
// called when the system exits
384
void byebye(void *arg) {
385
    grx_close();
386
    cprintf("Thanks for playing!\n");
387
}
388
 
389
///////////////////////////////////////
390
int main(int argc, char **argv) {
391
    HARD_TASK_MODEL m;
392
    PID pid;
393
 
394
    char c;
395
    TIME seme;          // used to init the random seed
396
    PI_mutexattr_t a;   // for PI mutex init
397
 
398
    // Set the closing function
399
    sys_atrunlevel(byebye, NULL, RUNLEVEL_BEFORE_EXIT);
400
 
401
    // initialize global variables
402
    setglobals();
403
 
404
    // initialize PI mutexes
405
    PI_mutexattr_default(a);
406
    mutex_init(&draw_mutex, &a);
407
    mutex_init(&list_mutex, &a);
408
 
409
    // graphic card Initialization
410
    if (grx_init() < 1) {
411
        sys_abort(errno);
412
    }
413
    if (grx_open(640, 480, 8) < 0) {
414
        cprintf("GRX Error\n");
415
        sys_abort(errno);
416
    }
417
 
418
    // Draw initial screen layout and menu
419
    grx_rect(XMIN-RAD-1, YMIN-RAD-1, XMAX+RAD+1, YMAX+RAD+1, yellow);
420
    grx_text("Scores:",             XMIN-RAD-1, 10, magenta, black);
421
 
422
    grx_text("PONG",                       XMENU, YMENU, magenta, black);
423
    grx_text("Create a ball:       SPACE", XMENU, YMENU+15, redorange, black);
424
    grx_text("Quit program:        ESC",   XMENU, YMENU+25, redorange, black);
425
    grx_text("Move top paddle:     z x",   XMENU, YMENU+35, redorange, black);
426
    grx_text("Change top size:     a s",   XMENU, YMENU+45, redorange, black);
427
    grx_text("Change bottom size:  q w",   XMENU, YMENU+55, redorange, black);
428
    grx_text("Keep # Balls Const:  l",     XMENU, YMENU+65, redorange, black);
429
    grx_text("Change ball speed:   1 2",   XMENU, YMENU+75, redorange, black);
430
    grx_text("Change kp:           3 4",   XMENU, YMENU+85, redorange, black);
431
    grx_text("Change kd:           5 6",   XMENU, YMENU+95, redorange, black);
432
    grx_text("Change mass:         7 8",   XMENU, YMENU+105, redorange, black);
433
    grx_text("Change AI window:    9 0",   XMENU, YMENU+115, redorange, black);
434
 
435
    print_scores();
436
    print_numballs();
437
    print_constants();
438
    draw_viewwin(gray);
439
 
440
    // randomize for ball starting angle
441
    seme = sys_gettime(NULL);
442
    srand(seme);
443
 
444
    // set up the paddle tasks
445
    hard_task_default_model(m);
446
    hard_task_def_ctrl_jet (m);
447
    hard_task_def_wcet     (m, P_WCET);
448
    hard_task_def_mit      (m, P_PER);
449
    hard_task_def_group    (m, PGROUP);
450
    hard_task_def_usemath  (m);
451
    pid = task_create("paddle1", paddle1, &m, NULL);
452
    if (pid == NIL) {
453
        grx_close();
454
        sys_shutdown_message("Could not create task <paddle1> errno=%d", errno);
455
        sys_abort(errno);
456
    }
457
 
458
    hard_task_default_model(m);
459
    hard_task_def_ctrl_jet (m);
460
    hard_task_def_wcet     (m, P_WCET);
461
    hard_task_def_mit      (m, P_PER);
462
    hard_task_def_group    (m, PGROUP);
463
    hard_task_def_usemath  (m);
464
    pid = task_create("p2ai", p2ai, &m, NULL);
465
    if (pid == NIL) {
466
        grx_close();
467
        sys_shutdown_message("Could not create task <p2ai> errno=%d", errno);
468
        sys_abort(errno);
469
    }
470
 
471
    hard_task_default_model(m);
472
    hard_task_def_ctrl_jet (m);
473
    hard_task_def_wcet     (m, P_WCET);
474
    hard_task_def_mit      (m, P_PER);
475
    hard_task_def_group    (m, PGROUP);
476
    hard_task_def_usemath  (m);
477
    pid = task_create("paddle2", paddle2, &m, NULL);
478
    if (pid == NIL) {
479
        grx_close();
480
        sys_shutdown_message("Could not create task <paddle2> errno=%d", errno);
481
        sys_abort(errno);
482
    }
483
    group_activate(PGROUP);
484
 
485
    #ifdef JET_ON
486
        scenario_jetcontrol();
487
        init_jetcontrol();
488
        group_activate(JET_GROUP);
489
    #endif
490
 
491
    hard_task_default_model(m);
492
    hard_task_def_ctrl_jet (m);
493
    hard_task_def_wcet     (m, BALL_WCET);
494
    hard_task_def_mit      (m, BALL_PER);
495
    hard_task_def_group    (m, BALLGROUP);
496
    hard_task_def_usemath  (m);
497
    pid = task_create("countmon", countmon, &m, NULL);
498
    if (pid == NIL) {
499
        grx_close();
500
        sys_shutdown_message("Could not create task <countmonitor> errno=%d", errno);
501
        sys_abort(errno);
502
    }
503
    task_activate(pid);
504
 
505
    while(1) { // read in commands ( exit handled in handle_key() )
506
        c = keyb_getch(BLOCK);
507
        switch (c) {
508
            case ESC: // quit program
509
                sys_abort(0);
510
                break;
511
            case ' ': // create a new ball
512
                addball();
513
                if(locked == 1)    // update min # balls if locked
514
                    min_balls++;
515
                break;
516
            case 'z': // move paddle1 left
517
                p1_move--;
518
                break;
519
            case 'x': // move paddle1 right
520
                p1_move++;
521
                break;
522
            case 's': // increase paddle1 length
523
                if (p1_length < (XMAX - XMIN - P_DLENGTH))
524
                    p1_length += P_DLENGTH;
525
                break;
526
            case 'a': // decrease paddle1 length
527
                if (p1_length > (1 + P_DLENGTH))
528
                     p1_length -= P_DLENGTH;
529
                break;
530
            case 'w': // increase paddle2 length
531
                if (p2_length < (XMAX - XMIN - P_DLENGTH))
532
                    p2_length += P_DLENGTH;
533
                break;
534
            case 'q': // decrease paddle2 length
535
                if (p2_length > (1 + P_DLENGTH))
536
                    p2_length -= P_DLENGTH;
537
                break;
538
            case 'l': // lock number of balls
539
                if((locked = !locked)) {
540
                    min_balls = num_balls;
541
                    mutex_lock(&draw_mutex);
542
                    grx_text("   Locked", XMAX-100, 30, redorange, black);
543
                    mutex_unlock(&draw_mutex);
544
                }
545
                else {
546
                    min_balls = 0;
547
                    mutex_lock(&draw_mutex);
548
                    grx_text("         ", XMAX-100, 30, redorange, black);
549
                    mutex_unlock(&draw_mutex);
550
                }
551
                break;
552
            case '1': // decrease ball speed
553
                ball_spd--;
554
                break;
555
            case '2': // increase ball speed
556
                ball_spd++;
557
                break;
558
            case '3': // decrease kp
559
                if(kp > 0)
560
                    kp--;
561
                print_constants();
562
                break;
563
            case '4': // increase kp
564
                kp++;
565
                print_constants();
566
                break;
567
            case '5': // decrease kd
568
                if(kd > 0)
569
                    kd--;
570
                print_constants();
571
                break;
572
            case '6': // increase kd
573
                kd++;
574
                print_constants();
575
                break;
576
            case '7': // decrease mass
577
                if(P_MASS > 5)
578
                    P_MASS -= 5;
579
                print_constants();
580
                break;
581
            case '8': // increase mass
582
                P_MASS += 5;
583
                print_constants();
584
                break;
585
            case '9': // decrease AI window
586
                draw_viewwin(black);    // clear old line
587
                AI_VIEWING_RANGE += 5;
588
                draw_viewwin(gray);     // draw new one
589
                break;
590
            case '0': // increase AI window
591
                draw_viewwin(black);    // clear old line
592
                AI_VIEWING_RANGE -= 5;
593
                draw_viewwin(gray);     // draw new one
594
                break;
595
            default:
596
                break;
597
        }
598
    }
599
 
600
    return 0;
601
}
602