Skip to content

Commit f64849c

Browse files
committed
Add pacman_march design with animated Pac-Man, ghosts and dots
1 parent 8fb2a72 commit f64849c

4 files changed

Lines changed: 247 additions & 1 deletion

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ Self-playing Space Invaders. Use `-C` for colored mode.
9595
### alien_march
9696
Animated Space Invader aliens scrolling across the screen like a marquee. Use `-C` for colored mode, `-R` to reverse direction, `-S <ticks>` to control scroll speed (default: 4), `-N <ticks>` to control animation speed (default: 1).
9797

98+
### pacman_march
99+
Pac-Man chased by ghosts scrolling across the screen with dots. Use `-C` for colored mode, `-R` to reverse direction, `-S <ticks>` for scroll speed (default: 4), `-N <ticks>` for animation speed (default: 1).
100+
98101
### Examples
99102

100103
```bash
@@ -106,6 +109,7 @@ Animated Space Invader aliens scrolling across the screen like a marquee. Use `-
106109
./pixelwall -d alien_march -C # Animated aliens scrolling with colors
107110
./pixelwall -d alien_march -R -S 6 # Slower scroll to the right
108111
./pixelwall -d alien_march -S 2 -N 4 # Fast scroll, slow animation
112+
./pixelwall -d pacman_march -C # Pac-Man with classic colors
109113
./pixelwall -T 30 # Cycle through all designs every 30s
110114
```
111115

pixelwall/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ OBJECTS = \
2929
design_tetris.o \
3030
design_starfield.o \
3131
design_invaders.o \
32-
design_alien_march.o
32+
design_alien_march.o \
33+
design_pacman_march.o
3334

3435
.PHONY: all
3536
all: $(PROGRAM)

pixelwall/design_pacman_march.c

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/*
2+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3+
Version 2, December 2004
4+
5+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
6+
7+
Everyone is permitted to copy and distribute verbatim or modified
8+
copies of this license document, and changing it is allowed as long
9+
as the name is changed.
10+
11+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
12+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
13+
14+
0. You just DO WHAT THE FUCK YOU WANT TO.
15+
*/
16+
17+
#include "pixelwall.h"
18+
#include <stdbool.h>
19+
20+
#define SPRITE_W 7
21+
#define SPRITE_H 7
22+
#define NUM_FRAMES 2
23+
#define DEFAULT_SPEED 4
24+
#define DEFAULT_ANIM_SPEED 1
25+
26+
// Pac-Man: 2 frames (mouth open / mouth closed)
27+
static const uint8_t pacman[NUM_FRAMES][SPRITE_H] = {
28+
// Frame 0 - mouth open
29+
{
30+
0x1C, // ..###..
31+
0x3E, // .#####.
32+
0x7C, // #####..
33+
0x70, // ###....
34+
0x7C, // #####..
35+
0x3E, // .#####.
36+
0x1C, // ..###..
37+
},
38+
// Frame 1 - mouth closing
39+
{
40+
0x1C, // ..###..
41+
0x3E, // .#####.
42+
0x7E, // ######.
43+
0x7F, // #######
44+
0x7E, // ######.
45+
0x3E, // .#####.
46+
0x1C, // ..###..
47+
},
48+
};
49+
50+
// Ghost: 2 frames (legs alternate)
51+
static const uint8_t ghost[NUM_FRAMES][SPRITE_H] = {
52+
// Frame 0
53+
{
54+
0x1C, // ..###..
55+
0x3E, // .#####.
56+
0x6B, // ##.##.#
57+
0x7F, // #######
58+
0x7F, // #######
59+
0x7F, // #######
60+
0x55, // #.#.#.#
61+
},
62+
// Frame 1
63+
{
64+
0x1C, // ..###..
65+
0x3E, // .#####.
66+
0x6B, // ##.##.#
67+
0x7F, // #######
68+
0x7F, // #######
69+
0x7F, // #######
70+
0x2A, // .#.#.#.
71+
},
72+
};
73+
74+
// Dot: small pellet centered in a 3-wide space (only middle row has a pixel)
75+
#define DOT_W 3
76+
#define DOT_H 7
77+
78+
// Pattern layout:
79+
// [pacman 7] [gap 2] [dot 3] [dot 3] [dot 3] [ghost 7] [gap 2] [ghost 7] [gap 2]
80+
// Total: 7 + 2 + 3 + 3 + 3 + 7 + 2 + 7 + 2 = 36
81+
82+
#define NUM_ELEMENTS 9
83+
static const int element_widths[NUM_ELEMENTS] = { 7, 2, 3, 3, 3, 7, 2, 7, 2 };
84+
// Element types: 0=pacman, 1=gap, 2=dot, 3=ghost
85+
static const int element_types[NUM_ELEMENTS] = { 0, 1, 2, 2, 2, 3, 1, 3, 1 };
86+
#define TOTAL_PATTERN_W 36
87+
88+
typedef struct {
89+
int offset;
90+
int dir;
91+
int tick;
92+
int speed;
93+
int anim_tick;
94+
int anim_speed;
95+
int frame;
96+
bool colorful;
97+
Color color;
98+
Color pacman_color;
99+
Color ghost_colors[2];
100+
Color dot_color;
101+
} PacmanMarchData;
102+
103+
static void PrintHelp() {
104+
printf(" -C Enable colored mode\n");
105+
printf(" -R Reverse direction (scroll right)\n");
106+
printf(" -S <ticks> Scroll speed, higher = slower (default: %d)\n", DEFAULT_SPEED);
107+
printf(" -N <ticks> Animation speed, higher = slower (default: %d)\n", DEFAULT_ANIM_SPEED);
108+
printf(" -P <color> Pac-Man color (R,G,B, default: 255,255,85)\n");
109+
printf(" -G <color> Ghost 1 color (R,G,B, default: 255,85,85)\n");
110+
printf(" -K <color> Ghost 2 color (R,G,B, default: 85,255,255)\n");
111+
printf(" -E <color> Dot color (R,G,B, default: 255,185,80)\n");
112+
}
113+
114+
static void *Create(Grid *grid, int argc, char *argv[]) {
115+
(void)grid;
116+
PacmanMarchData *pd = calloc(1, sizeof(PacmanMarchData));
117+
if (!pd) return NULL;
118+
119+
pd->color = GREEN;
120+
pd->dir = 1;
121+
pd->speed = DEFAULT_SPEED;
122+
pd->anim_speed = DEFAULT_ANIM_SPEED;
123+
pd->colorful = false;
124+
pd->pacman_color = (Color){255, 255, 85, 255};
125+
pd->ghost_colors[0] = (Color){255, 85, 85, 255};
126+
pd->ghost_colors[1] = (Color){85, 255, 255, 255};
127+
pd->dot_color = (Color){255, 185, 80, 255};
128+
129+
int opt;
130+
optind = 1;
131+
while ((opt = getopt(argc, argv, ":d:CRS:N:P:G:K:E:")) != -1) {
132+
switch (opt) {
133+
case 'C': pd->colorful = true; break;
134+
case 'R': pd->dir = -1; break;
135+
case 'S':
136+
pd->speed = atoi(optarg);
137+
if (pd->speed < 1) pd->speed = 1;
138+
break;
139+
case 'N':
140+
pd->anim_speed = atoi(optarg);
141+
if (pd->anim_speed < 1) pd->anim_speed = 1;
142+
break;
143+
case 'P': pd->pacman_color = ParseColor(optarg); break;
144+
case 'G': pd->ghost_colors[0] = ParseColor(optarg); break;
145+
case 'K': pd->ghost_colors[1] = ParseColor(optarg); break;
146+
case 'E': pd->dot_color = ParseColor(optarg); break;
147+
}
148+
}
149+
150+
return pd;
151+
}
152+
153+
static void DrawColumn(PacmanMarchData *pd, Grid *grid, int screen_x, int pattern_col,
154+
int start_row, int frame) {
155+
// Find which element this column belongs to
156+
int col = pattern_col;
157+
int elem = 0;
158+
while (elem < NUM_ELEMENTS && col >= element_widths[elem]) {
159+
col -= element_widths[elem];
160+
elem++;
161+
}
162+
if (elem >= NUM_ELEMENTS) return;
163+
164+
int type = element_types[elem];
165+
166+
if (type == 1) return; // gap
167+
168+
if (type == 2) {
169+
// Dot: single pixel in the center (col 1, row 3)
170+
if (col == 1) {
171+
int gy = start_row + SPRITE_H / 2;
172+
if (gy >= 0 && gy < grid->rows) {
173+
Color c = pd->colorful ? pd->dot_color : pd->color;
174+
GridSetColor(grid, (Pos){screen_x, gy}, c);
175+
}
176+
}
177+
return;
178+
}
179+
180+
const uint8_t *sprite;
181+
Color c;
182+
183+
if (type == 0) {
184+
// Pac-Man
185+
sprite = pacman[frame];
186+
c = pd->colorful ? pd->pacman_color : pd->color;
187+
} else {
188+
// Ghost - figure out which one (first or second ghost in pattern)
189+
int ghost_idx = (elem == 5) ? 0 : 1;
190+
sprite = ghost[frame];
191+
c = pd->colorful ? pd->ghost_colors[ghost_idx] : pd->color;
192+
}
193+
194+
for (int r = 0; r < SPRITE_H; r++) {
195+
int gy = start_row + r;
196+
if (gy < 0 || gy >= grid->rows) continue;
197+
if ((sprite[r] >> (SPRITE_W - 1 - col)) & 1) {
198+
GridSetColor(grid, (Pos){screen_x, gy}, c);
199+
}
200+
}
201+
}
202+
203+
static void UpdateFrame(Grid *grid, void *data) {
204+
PacmanMarchData *pd = (PacmanMarchData *)data;
205+
Color bg = grid->conf.backgroundColor;
206+
207+
GridFillColor(grid, bg);
208+
209+
int start_row = (grid->rows - SPRITE_H) / 2;
210+
211+
for (int x = 0; x < grid->cols; x++) {
212+
int pcol = ((x + pd->offset) % TOTAL_PATTERN_W + TOTAL_PATTERN_W) % TOTAL_PATTERN_W;
213+
DrawColumn(pd, grid, x, pcol, start_row, pd->frame);
214+
}
215+
216+
pd->tick++;
217+
if (pd->tick >= pd->speed) {
218+
pd->tick = 0;
219+
pd->offset += pd->dir;
220+
}
221+
222+
pd->anim_tick++;
223+
if (pd->anim_tick >= pd->anim_speed) {
224+
pd->anim_tick = 0;
225+
pd->frame = (pd->frame + 1) % NUM_FRAMES;
226+
}
227+
}
228+
229+
static void Destroy(void *data) {
230+
free(data);
231+
}
232+
233+
Design pacmanMarchDesign = {
234+
.name = "pacman_march",
235+
.PrintHelp = PrintHelp,
236+
.Create = Create,
237+
.UpdateFrame = UpdateFrame,
238+
.Destroy = Destroy,
239+
};

pixelwall/designs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extern Design tetrisDesign;
3131
extern Design starfieldDesign;
3232
extern Design invadersDesign;
3333
extern Design alienMarchDesign;
34+
extern Design pacmanMarchDesign;
3435

3536
Design *designs[] = {
3637
&snakeDesign,
@@ -46,4 +47,5 @@ Design *designs[] = {
4647
&starfieldDesign,
4748
&invadersDesign,
4849
&alienMarchDesign,
50+
&pacmanMarchDesign,
4951
};

0 commit comments

Comments
 (0)