source: trunk/third/xscreensaver/hacks/pong.c @ 20148

Revision 20148, 11.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* pong, Copyright (c) 2003 Jeremy English <jenglish@myself.com>
2 * A pong screen saver
3 *
4 * Modified by Trevor Blackwell <tlb@tlb.org> to use analogtv.[ch] display.
5 * Also added gradual acceleration of the ball, shrinking of paddles, and
6 * scorekeeping.
7 *
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that
11 * copyright notice and this permission notice appear in supporting
12 * documentation.  No representations are made about the suitability of this
13 * software for any purpose.  It is provided "as is" without express or
14 * implied warranty.
15 */
16
17/*
18 * TLB sez: I haven't actually seen a pong game since I was about 9. Can
19 * someone who has one make this look more realistic? Issues:
20 *
21 *  - the font for scores is wrong. For example '0' was square.
22 *  - was there some kind of screen display when someone won?
23 *  - did the ball move smoothly, or was the X or Y position quantized?
24 *
25 * It could also use better player logic: moving the paddle even when the ball
26 * is going away, and making mistakes instead of just not keeping up with the
27 * speeding ball.
28 *
29 * There is some info at http://www.mameworld.net/discrete/Atari/Atari.htm#Pong
30 *
31 * It says that the original Pong game did not have a microprocessor, or even a
32 * custom integrated circuit. It was all discrete logic.
33 *
34 */
35
36#include "screenhack.h"
37#include "analogtv.h"
38/* #define OUTPUT_POS */
39
40typedef struct _paddle {
41  int x;
42  int y;
43  int w;
44  int h;
45  int wait;
46  int lock;
47  int score;
48} Paddle;
49
50typedef struct _ball {
51  int x;
52  int y;
53  int w;
54  int h;
55} Ball;
56
57static int delay;
58Paddle l_paddle;
59Paddle r_paddle;
60Ball ball;
61static int bx,by;
62static int m_unit;
63static int paddle_rate;
64
65static analogtv *tv;
66static analogtv_input *inp;
67static analogtv_reception reception;
68
69static int paddle_ntsc[4];
70static int field_ntsc[4];
71static int ball_ntsc[4];
72static int score_ntsc[4];
73static int net_ntsc[4];
74
75analogtv_font score_font;
76
77enum {
78  PONG_W = ANALOGTV_VIS_LEN,
79  PONG_H = ANALOGTV_VISLINES,
80  PONG_TMARG = 10
81};
82
83static void
84hit_top_bottom(void)
85{
86  if ( (ball.y <= PONG_TMARG) ||
87       (ball.y+ball.h >= PONG_H) )
88    by=-by;
89}
90
91void
92start_game(void)
93{
94  /*Init the ball*/
95  ball.x = PONG_W/2;
96  ball.y = PONG_H/2;
97  bx = m_unit;
98  by = m_unit;
99
100  l_paddle.wait = 1;
101  l_paddle.lock = 0;
102  r_paddle.wait = 0;
103  r_paddle.lock = 0;
104  paddle_rate = m_unit-1;
105
106  if (l_paddle.h > 10) l_paddle.h= l_paddle.h*19/20;
107  if (r_paddle.h > 10) r_paddle.h= r_paddle.h*19/20;
108}
109
110static void
111hit_paddle(void)
112{
113  if ( ball.x + ball.w >= r_paddle.x &&
114       bx > 0 ) /*we are traveling to the right*/
115    {
116      if ((ball.y + ball.h > r_paddle.y) &&
117          (ball.y < r_paddle.y + r_paddle.h))
118        {
119          bx=-bx;
120          l_paddle.wait = 0;
121          r_paddle.wait = 1;
122          r_paddle.lock = 0;
123          l_paddle.lock = 0;
124        }
125      else
126        {
127          r_paddle.score++;
128          start_game();
129        }
130    }
131
132  if (ball.x <= l_paddle.x + l_paddle.w &&
133      bx < 0 ) /*we are traveling to the left*/
134    {
135      if ( ball.y + ball.h > l_paddle.y &&
136           ball.y < l_paddle.y + l_paddle.h)
137        {
138          bx=-bx;
139          l_paddle.wait = 1;
140          r_paddle.wait = 0;
141          r_paddle.lock = 0;
142          l_paddle.lock = 0;
143        }
144      else
145        {
146          l_paddle.score++;
147          start_game();
148        }
149    }
150}
151
152static void
153init_pong (Display *dpy, Window window)
154{
155  tv=analogtv_allocate(dpy, window);
156  analogtv_set_defaults(tv, "");
157  tv->event_handler = screenhack_handle_event;
158
159  analogtv_make_font(dpy, window, &score_font,
160                     4, 6, NULL );
161
162  /* If you think we haven't learned anything since the early 70s,
163     look at this font for a while */
164  analogtv_font_set_char(&score_font, '0',
165                        "****"
166                        "*  *"
167                        "*  *"
168                        "*  *"
169                        "*  *"
170                        "****");
171  analogtv_font_set_char(&score_font, '1',
172                        "   *"
173                        "   *"
174                        "   *"
175                        "   *"
176                        "   *"
177                        "   *");
178  analogtv_font_set_char(&score_font, '2',
179                        "****"
180                        "   *"
181                        "****"
182                        "*   "
183                        "*   "
184                        "****");
185  analogtv_font_set_char(&score_font, '3',
186                        "****"
187                        "   *"
188                        "****"
189                        "   *"
190                        "   *"
191                        "****");
192  analogtv_font_set_char(&score_font, '4',
193                        "*  *"
194                        "*  *"
195                        "****"
196                        "   *"
197                        "   *"
198                        "   *");
199  analogtv_font_set_char(&score_font, '5',
200                        "****"
201                        "*   "
202                        "****"
203                        "   *"
204                        "   *"
205                        "****");
206  analogtv_font_set_char(&score_font, '6',
207                        "****"
208                        "*   "
209                        "****"
210                        "*  *"
211                        "*  *"
212                        "****");
213  analogtv_font_set_char(&score_font, '7',
214                        "****"
215                        "   *"
216                        "   *"
217                        "   *"
218                        "   *"
219                        "   *");
220  analogtv_font_set_char(&score_font, '8',
221                        "****"
222                        "*  *"
223                        "****"
224                        "*  *"
225                        "*  *"
226                        "****");
227  analogtv_font_set_char(&score_font, '9',
228                        "****"
229                        "*  *"
230                        "****"
231                        "   *"
232                        "   *"
233                        "   *");
234
235  score_font.y_mult *= 2;
236  score_font.x_mult *= 2;
237
238#ifdef OUTPUT_POS
239  printf("screen(%d,%d,%d,%d)\n",0,0,PONG_W,PONG_H);
240#endif
241
242  inp=analogtv_input_allocate();
243  analogtv_setup_sync(inp, 0, 0);
244
245  reception.input = inp;
246  reception.level = 2.0;
247  reception.ofs=0;
248#if 0
249  if (random()) {
250    reception.multipath = frand(1.0);
251  } else {
252#endif
253    reception.multipath=0.0;
254#if 0
255  }
256#endif
257
258  delay = get_integer_resource ("delay", "Integer");
259  if (delay < 0) delay = 0;
260
261  /*Init the paddles*/
262  l_paddle.x = 8;
263  l_paddle.y = 100;
264  l_paddle.w = 16;
265  l_paddle.h = PONG_H/4;
266  l_paddle.wait = 1;
267  l_paddle.lock = 0;
268  r_paddle = l_paddle;
269  r_paddle.x = PONG_W - 8 - r_paddle.w;
270  r_paddle.wait = 0;
271  /*Init the ball*/
272  ball.x = PONG_W/2;
273  ball.y = PONG_H/2;
274  ball.w = 16;
275  ball.h = 8;
276
277  m_unit = get_integer_resource ("speed", "Integer");
278
279  start_game();
280
281  analogtv_lcp_to_ntsc(ANALOGTV_BLACK_LEVEL, 0.0, 0.0, field_ntsc);
282  analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, ball_ntsc);
283  analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, paddle_ntsc);
284  analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, score_ntsc);
285  analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, net_ntsc);
286
287  analogtv_draw_solid(inp,
288                      ANALOGTV_VIS_START, ANALOGTV_VIS_END,
289                      ANALOGTV_TOP, ANALOGTV_BOT,
290                      field_ntsc);
291}
292
293static void
294p_logic(Paddle *p)
295{
296  int targ;
297  if (bx > 0) {
298    targ = ball.y + by * (r_paddle.x-ball.x) / bx;
299  }
300  else if (bx < 0) {
301    targ = ball.y - by * (ball.x - l_paddle.x - l_paddle.w) / bx;
302  }
303  else {
304    targ = ball.y;
305  }
306  if (targ > PONG_H) targ=PONG_H;
307  if (targ < 0) targ=0;
308
309  if (targ < p->y && !p->lock)
310  {
311    p->y -= paddle_rate;
312  }
313  else if (targ > (p->y + p->h) && !p->lock)
314  {
315    p->y += paddle_rate;
316  }
317  else
318  {
319    int move=targ - (p->y + p->h/2);
320    if (move>paddle_rate) move=paddle_rate;
321    if (move<-paddle_rate) move=-paddle_rate;
322    p->y += move;
323    p->lock = 1;
324  }
325}
326
327static void
328p_hit_top_bottom(Paddle *p)
329{
330  if(p->y <= PONG_TMARG)
331  {
332    p->y = PONG_TMARG;
333  }
334  if((p->y + p->h) >= PONG_H)
335  {
336    p->y = PONG_H - p->h;
337  }
338}
339
340/*
341  XFillRectangle (dpy, window, gc, p->x, p->y, p->w, p->h);
342  if (old_v > p->y)
343  {
344    XClearArea(dpy,window, p->x, p->y + p->h,
345      p->w, (old_v + p->h) - (p->y + p->h), 0);
346  }
347  else if (old_v < p->y)
348  {
349    XClearArea(dpy,window, p->x, old_v, p->w, p->y - old_v, 0);
350  }
351*/
352static void
353paint_paddle(analogtv_input *inp, Paddle *p)
354{
355  analogtv_draw_solid(inp,
356                      ANALOGTV_VIS_START + p->x, ANALOGTV_VIS_START + p->x + p->w,
357                      ANALOGTV_TOP, ANALOGTV_BOT,
358                      field_ntsc);
359
360  analogtv_draw_solid(inp,
361                      ANALOGTV_VIS_START + p->x, ANALOGTV_VIS_START + p->x + p->w,
362                      ANALOGTV_TOP + p->y, ANALOGTV_TOP + p->y + p->h,
363                      paddle_ntsc);
364}
365
366/*
367  XClearArea(dpy,window, old_ballx, old_bally, ball.d, ball.d, 0);
368  XFillRectangle (dpy, window, gc, ball.x, ball.y, ball.d, ball.d);
369  XFillRectangle (dpy, window, gc, xgwa.width / 2, 0, ball.d, xgwa.height);
370*/
371
372static void
373erase_ball(analogtv_input *inp)
374{
375  analogtv_draw_solid(inp,
376                      ANALOGTV_VIS_START + ball.x, ANALOGTV_VIS_START + ball.x + ball.w,
377                      ANALOGTV_TOP + ball.y, ANALOGTV_TOP + ball.y + ball.h,
378                      field_ntsc);
379}
380
381static void
382paint_ball(analogtv_input *inp)
383{
384  analogtv_draw_solid(inp,
385                      ANALOGTV_VIS_START + ball.x, ANALOGTV_VIS_START + ball.x + ball.w,
386                      ANALOGTV_TOP + ball.y, ANALOGTV_TOP + ball.y + ball.h,
387                      ball_ntsc);
388}
389
390static void
391paint_score(analogtv_input *inp)
392{
393  char buf[256];
394
395  analogtv_draw_solid(inp,
396                      ANALOGTV_VIS_START, ANALOGTV_VIS_END,
397                      ANALOGTV_TOP, ANALOGTV_TOP + 10+ score_font.char_h * score_font.y_mult,
398                      field_ntsc);
399
400  sprintf(buf, "%d",r_paddle.score%256);
401  analogtv_draw_string(inp, &score_font, buf,
402                       ANALOGTV_VIS_START + 130, ANALOGTV_TOP + 8,
403                       score_ntsc);
404
405  sprintf(buf, "%d",l_paddle.score%256);
406  analogtv_draw_string(inp, &score_font, buf,
407                       ANALOGTV_VIS_END - 200, ANALOGTV_TOP + 8,
408                       score_ntsc);
409
410}
411
412static void
413paint_net(analogtv_input *inp)
414{
415  int x,y;
416
417  x=(ANALOGTV_VIS_START + ANALOGTV_VIS_END)/2;
418
419  for (y=ANALOGTV_TOP; y<ANALOGTV_BOT; y+=6) {
420    analogtv_draw_solid(inp, x-2, x+2, y, y+3,
421                        net_ntsc);
422    analogtv_draw_solid(inp, x-2, x+2, y+3, y+6,
423                        field_ntsc);
424
425  }
426}
427
428static void
429play_pong (void)
430{
431  erase_ball(inp);
432
433  ball.x += bx;
434  ball.y += by;
435
436  if ((random()%40)==0) {
437    if (bx>0) bx++; else bx--;
438  }
439
440  if (!r_paddle.wait)
441  {
442    p_logic(&r_paddle);
443  }
444  if (!l_paddle.wait)
445  {
446    p_logic(&l_paddle);
447  }
448
449  p_hit_top_bottom(&r_paddle);
450  p_hit_top_bottom(&l_paddle);
451
452  hit_top_bottom();
453  hit_paddle();
454
455  #ifdef OUTPUT_POS
456  printf("(%d,%d,%d,%d)\n",ball.x,ball.y,ball.w,ball.h);
457  #endif
458
459  paint_score(inp);
460
461  paint_net(inp);
462
463  if (1) {
464    paint_paddle(inp, &r_paddle);
465    paint_paddle(inp, &l_paddle);
466  }
467  if (1) paint_ball(inp);
468
469  analogtv_handle_events(tv);
470
471  analogtv_init_signal(tv, 0.04);
472  analogtv_reception_update(&reception);
473  analogtv_add_signal(tv, &reception);
474  analogtv_draw(tv);
475}
476
477
478char *progclass = "pong";
479
480char *defaults [] = {
481  "*delay:      10000",
482  "*speed:      6",
483  ANALOGTV_DEFAULTS
484  "*TVContrast:      150",
485  0
486};
487
488XrmOptionDescRec options [] = {
489  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
490  { "-percent",         ".percent",     XrmoptionSepArg, 0 },
491  { "-speed",           ".speed",     XrmoptionSepArg, 0 },
492  ANALOGTV_OPTIONS
493  { 0, 0, 0, 0 }
494};
495
496void
497screenhack (Display *dpy, Window window)
498{
499  init_pong (dpy, window);
500  while (1)
501    {
502      play_pong ();
503    }
504}
505
Note: See TracBrowser for help on using the repository browser.