6
$\begingroup$

This is the code we have created so far for a Pacman type game:

`DynamicModule[{diskPosition = {250, 450}, diskRadius = 15, 
  pacman = {9, 4}}, 
 EventHandler[
  Graphics[Dynamic[{Yellow, Disk[diskPosition, diskRadius, pacman]}],

   PlotRange -> {{0, 460}, {0, 590}}, Background -> Black],

  {
   "LeftArrowKeyDown" :> {(pacman = {9, 4}), (diskPosition[[
        1]] += -10)},

   "RightArrowKeyDown" :> {(pacman = {1, 6}), (diskPosition[[1]] += 
       10)},

   "UpArrowKeyDown" :> {(pacman = {2, 7}), (diskPosition[[2]] += 10)},

   "DownArrowKeyDown" :> {(pacman = {-2, -7}), (diskPosition[[
        2]] += -10)}

   }]]`

We want to create a grid which the pacman cannot pass through the barriers, creating a maze it must go through.

$\endgroup$
  • 1
    $\begingroup$ It might be easier to build a path along which the pacman can move (rather than a wall that it cannot cross). $\endgroup$ – bill s Nov 29 '16 at 18:46
  • $\begingroup$ Welcome to Mathematica.SE! 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Take the tour and check the faqs! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$ – user9660 Nov 29 '16 at 19:29
  • $\begingroup$ How would would I build a path that the pacman can only move on? $\endgroup$ – pacman Nov 29 '16 at 20:59
7
$\begingroup$

Here's a maze for the pacman to operate in (which is taken from here)

style = {Background -> GrayLevel[0], 
   BaseStyle -> {Directive[White, EdgeForm[], Opacity[1]]}, 
   VertexShapeFunction -> (Rectangle[#1 + .16, #1 - .16] &), 
   EdgeShapeFunction -> (Rectangle[#1[[1]] + .16, #1[[2]] - .16] &)};
embedding = GraphEmbedding[GridGraph[{20, 30}]]; 
g = GridGraph[{20, 30}, EdgeWeight -> RandomReal[10, 1150]];
tree = FindSpanningTree[{g, 1}]; 
maze = Binarize[Image[Rasterize[Graph[tree, VertexCoordinates->embedding, style], 
       RasterSize -> 1000], ImageSize -> 1000]];
m = 5;

Now the pac man in-the-maze, constrained with the If[] statements to the white portions of the maze.

DynamicModule[{diskPosition = {250, 450}, diskRadius = 15, pacman = {9, 4}}, 
 EventHandler[
  Show[maze, Graphics[Dynamic[{Yellow, Disk[diskPosition, diskRadius, pacman]}],
     PlotRange -> {{0, 200}, {0, 300}}]], 
{"RightArrowKeyDown" :> 
    If[PixelValue[maze, {diskPosition[[1]] + m, diskPosition[[2]]}] == 1, 
                  pacman = {1, 6}; diskPosition[[1]] += m],
 "LeftArrowKeyDown" :> 
    If[PixelValue[maze, {diskPosition[[1]] - m, diskPosition[[2]]}] == 1, 
                  pacman = {9, 4}; diskPosition[[1]] += -m],
 "UpArrowKeyDown" :> 
    If[PixelValue[maze, {diskPosition[[1]], diskPosition[[2]] + m}] == 1, 
                  pacman = {2, 7}; diskPosition[[2]] += m],
 "DownArrowKeyDown" :> 
    If[PixelValue[maze, {diskPosition[[1]], diskPosition[[2]] - m}] == 1, 
                  pacman = {-2, -7}; diskPosition[[2]] += -m]}]]

enter image description here

| improve this answer | |
$\endgroup$
7
$\begingroup$

Before making a move, test if the new position is a valid position. A valid position is one where Pac-Man does not touch the walls. Mathematica has convenient functions that deal with regions, so we might consider creating a region and then using those functions. Regions can be built using Graphics primitives and then converted into regions with DiscretizeGraphics, therefore we will first create a graphics object of the map. I decided to start from this image:

I used some image processing functions to turn the map into a region, but note that you can create your map by hand using Rectangle, Line, Polygon or whatever you may want.

img = ImageCrop@Binarize@Import["http://wallpapercave.com/wp/6SKGas2.png"];
components = MorphologicalComponents[Thinning[img]];
indices = DeleteCases[DeleteDuplicates@Flatten[components], 0];
curvePathPlots = ListCurvePathPlot[Position[components, #]] & /@ indices;
lines = Cases[Show[curvePathPlots, PlotRange -> All], _Line, Infinity];

lines now contains Line objects corresponding to all the lines. We now create the map, for displaying as a background, and the region, for collision checking.

map = Graphics[{Thickness[0.004], White, lines}, Background -> Black];
region = DiscretizeGraphics[map];

Evaluate map to see what it looks like, put a white disk of radius 20 in as well for scale:

Show[
 map,
 Graphics[{White, Disk[{420, 425}, 20]}]
 ]

Mathematica graphics

Because of a change of coordinate system we've rotated the image, but it doesn't matter. The one who cares about it, may fix it.

Now we need a function that will tell us if a Pac-Man, represented as a disk of radius 20, collides with the walls, if it is positioned at a certain position. Since it is a disk it is equivalent to checking whether the distance to the wall is larger than 20:

freeQ[{x_, y_}] := RegionDistance[region, {x, y}] > 20

Now, an event in the EventHandler may look like this:

"LeftArrowKeyDown" :> If[freeQ[diskPosition - {10, 0}],
  pacman = {9, 4};
  diskPosition[[1]] += -10
  ]

This says "if the new position will not cause Pac-Man to collide with any wall, make the move." Here is your updated code:

DynamicModule[
 {
  diskPosition = {510, 470},
  diskRadius = 20,
  pacman = {9, 4}
  },
 EventHandler[Show[
   map,
   Graphics[
    Dynamic[{Yellow, Disk[diskPosition, diskRadius, pacman]}],
    PlotRange -> {{0, 460}, {0, 590}}
    ]
   ],
  {
   "LeftArrowKeyDown" :> If[freeQ[diskPosition - {10, 0}],
     pacman = {9, 4};
     diskPosition[[1]] += -10
     ],
   "RightArrowKeyDown" :> If[freeQ[diskPosition + {10, 0}],
     pacman = {1, 6};
     diskPosition[[1]] += 10;
     ],
   "UpArrowKeyDown" :> If[freeQ[diskPosition + {0, 10}],
     pacman = {2, 7};
     diskPosition[[2]] += 10
     ],
   "DownArrowKeyDown" :> If[freeQ[diskPosition - {0, 10}],
     pacman = {-2, -7};
     diskPosition[[2]] += -10
     ]
   }]]

Pac-Man test run

| improve this answer | |
$\endgroup$
  • $\begingroup$ This code is great except our pacman will only move along the center box. Any idea why our pacman can't move around the entire map? $\endgroup$ – pacman Dec 1 '16 at 16:24
  • $\begingroup$ @pacman I think I demonstrate in my animation that the Pac-Man can in fact move around the entire map? $\endgroup$ – C. E. Dec 1 '16 at 20:38
  • $\begingroup$ I tried it out but for some reason it only goes around the center box. $\endgroup$ – pacman Dec 1 '16 at 21:01
  • $\begingroup$ @pacman I just tried it too. There was a slight change of image size when I uploaded the image, so I had to adjust the starting position (I've now incorporated this into answer), but other than that it runs fine... I'm using version 11, but I expect it to work in Mathematica 10 as well. $\endgroup$ – C. E. Dec 1 '16 at 21:17
4
$\begingroup$

here is an idea..crude but may show how to proceed.

box = {{50, 200}, {300, 200}, {300, 400}, {50, 400}, {50, 200}};
up[p_] := 
 Module[ {t = p + {0, 10}}, 
  If[ 200 - 15 < t[[2]] < 400 + 15 && 50 < t[[1]] < 300 , 0, 10]]
left[p_] := 
 Module[ {t = p - {10, 0}}, 
  If[ 200 < t[[2]] < 400 && 50 - 15 < t[[1]] < 300 + 15, 0, -10]]
right[p_] := 
 Module[ {t = p + {10, 0}}, 
  If[ 200 < t[[2]] < 400 && 50 - 15 < t[[1]] < 300 + 15, 0, 10]]
down[p_] := 
 Module[ {t = p - {0, 10}}, 
  If[ 200 - 15 < t[[2]] < 400 + 15 && 50 < t[[1]] < 300 , 0, -10]]
DynamicModule[
 {diskPosition = {250, 450}, diskRadius = 15, pacman = {9, 4}}, 
 EventHandler[
  Graphics[{Dynamic[{Yellow, Disk[diskPosition, diskRadius, pacman]}],
     Thick, White, Line[box]}, PlotRange -> {{0, 460}, {0, 590}}, 
   Background -> Black], {
   "LeftArrowKeyDown" :> {(pacman = {9, 4}), (diskPosition[[1]] += 
       left[diskPosition])},
   "RightArrowKeyDown" :> {(pacman = {1, 6}), (diskPosition[[1]] += 
       right[diskPosition])},
   "UpArrowKeyDown" :> {(pacman = {2, 7}), (diskPosition[[2]] += 
       up[diskPosition])}, 
   "DownArrowKeyDown" :> {(pacman = {-2, -7}), (diskPosition[[2]] += 
       down[diskPosition])}}]]

as noted in comment it may be better to define a permissible path, which would amount to a list of permissible positions on a 10x10 grid. Then as you do each update you check if the updated position is in the permissible list ( MemberQ maybe. )

grid = Table[ {i, 450}, {i, 100, 400, 10}]~Join~
   Table[ {100, j}, {j, 100, 500, 10}];
up[p_] := Module[ {t = p + {0, 10}}, If[ MemberQ[grid, t] , 10, 0]]
left[p_] := Module[ {t = p - {10, 0}}, If[ MemberQ[grid, t] , -10, 0]]
right[p_] := Module[ {t = p + {10, 0}}, If[ MemberQ[grid, t] , 10, 0]]
down[p_] := Module[ {t = p - {0, 10}}, If[ MemberQ[grid, t] , -10, 0]]
DynamicModule[
 {diskPosition = {250, 450}, diskRadius = 15, pacman = {9, 4}}, 
 EventHandler[
  Graphics[{Dynamic[{Yellow, Disk[diskPosition, diskRadius, pacman]}],
     White, Point[grid]}, PlotRange -> {{0, 460}, {0, 590}}, 
   Background -> Black], {
   "LeftArrowKeyDown" :> {(pacman = {9, 4}), (diskPosition[[1]] += 
       left[diskPosition])},
   "RightArrowKeyDown" :> {(pacman = {1, 6}), (diskPosition[[1]] += 
       right[diskPosition])},
   "UpArrowKeyDown" :> {(pacman = {2, 7}), (diskPosition[[2]] += 
       up[diskPosition])}, 
   "DownArrowKeyDown" :> {(pacman = {-2, -7}), (diskPosition[[2]] += 
       down[diskPosition])}}]]

enter image description here

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.