Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Snake Games

Module[
{dir = {-1, 0}, x = -1., y = 0., snake = Table[{i, 0}, {i, 0, 4}],
gameover = False,
target = {RandomInteger[17] - 9, RandomInteger[17] - 9},
timecount = 0,
score = 0},
Manipulate[
If[
 Mod[timecount, 5] == 0 && u != {-1, -1} && gameover == False,
x = u[[1]];
y = u[[2]];
dir = If[
 y >= x,
 If[y >= -x, {0, 1}, {-1, 0}],
 If[y >= -x, {1, 0}, {0, -1}]
 ];
 If[
  MemberQ[snake, 
    snake[[1]] + dir] || (snake[[1]] + dir)[[
     1]] < -10 || (snake[[1]] + dir)[[1]] > 
    9 || (snake[[1]] + dir)[[2]] < -10 || (snake[[1]] + dir)[[2]] > 
    9,
  gameover = True;
  score = Length[snake] - 5
  ];
 If[
  (snake[[1]] + dir) == target,
  target = {RandomInteger[17] - 9, RandomInteger[17] - 9},
  snake = Most[snake]
  ];
 PrependTo[snake, snake[[1]] + dir]
 ];
timecount++;
Framed[
 Graphics[
 If[
  False == gameover,
  Append[
   Table[Rectangle[i, i + {1, 1}], {i, snake}],
   Rectangle[target, target + {1, 1}]
   ],
  {Rectangle[{-10, -10}, {10, 10}], 
   Text[Style[" Game over! ", FontSize -> 36], {0, 3}, 
    Background -> White], 
   Text[Style[" Score: ", FontSize -> 24], {0, 0}, 
    Background -> White], 
   Text[Style[score, FontSize -> 24], {0, -2}, Background -> White]}
   ],
   Axes -> False, PlotRange -> {{-10, 10}, {-10, 10}}, 
   ImagePadding -> 0
   ],
  FrameMargins -> 0
 ],
{u, {-1, -1}, {1, 1}}, ControlPlacement -> Right
]
]

It is not convenient for the user to play this game in the above form. So how can I rewrite it without using Manipulate, but using other functions that can provide a better user interface?

share|improve this question
    
@Nasser,It is not convenient for manipulate function to operate the snake game.You could copy the codes to run it.At that time ,you can understand my qusetion. –  tangtaotao Jul 30 '13 at 14:55
    
I would suggest reading the documentation for Dynamic and EventHandler‌​. Then start out trying smaller constructions, then try to build this game again, and come back when you know more about what you are trying to accomplish. –  jVincent Jul 30 '13 at 14:58
    
Some useful ideas for keyboard control in the amazing Minecraft Q&A –  cormullion Jul 30 '13 at 15:04
    
@Nasser.Sorry,I can't translate it clearly.Anyway,Thank you! –  tangtaotao Jul 30 '13 at 15:06
    
A generic answer: Use DynamicModule for your variables, perhaps Panel, Grid, etc for layout, place your controls or write your own with EventHandler, etc. -- these links are guides to the functions that can help you do what you want. But you'll have to decide what you want (or ask an expert). –  Michael E2 Jul 30 '13 at 17:34
show 2 more comments

2 Answers 2

up vote 7 down vote accepted

I think you've actually done a good job considering you are only using Manipulate. Here's a simplified snake game using Dynamic:

snake = {{0, 0}, {0, 1}, {0, 2}};
dir = {0, -1};

directions = {
   "UpArrowKeyDown" :> (dir = {0, 1}),
   "DownArrowKeyDown" :> (dir = {0, -1}),
   "LeftArrowKeyDown" :> (dir = {-1, 0}),
   "RightArrowKeyDown" :> (dir = {1, 0})};

EventHandler[
 Graphics[
  Dynamic[Rectangle /@ snake],
  PlotRange -> 5],
 directions]

While[True, Pause[.5];
 snake = Most[snake]~Prepend~(snake[[1]] + dir);]

Here I put the Dynamic inside the Graphics expression, rather than wrapping the whole Graphics with a Dynamic. This works because Graphics is designed to let it work, and it does make a difference (in general) if you need performance.

I recommend you read the documentation for Dynamic (especially the "Details") and the Advanced Dynamic Functionality tutorial. It's kinda boring but it's useful.

Another thing I should point out, that wasn't obvious to me at first, is that Dynamic uses Set, quite explicitly. What this means in practice is that Dynamic works, for example, with array locations:

array = {1, 2, 3};
Dynamic[array]
Slider[Dynamic[array[[2]]]]
While[True, Pause[.5]; array[[2]] = RandomReal[]]

As well as for function downvalues such as f[2]. This makes the programming easier for larger controls, such as matrix controls and the like.

share|improve this answer
    
,Thanks very much.I will use your method to rewrite my game. –  tangtaotao Jul 31 '13 at 4:11
add comment

Writing games using dynamic interactivity in mathematica is an amusing subject! I will vote up your post for this. But I agree with others that it is hard to answer your question, you should work out minimal example for us first.

Below I am giving my code for tetris. I recognize, it is a nonminimal answer, but it is working and can be useful for you. Controls are with arrow keys. To make controls working, make the focus on the panel, e.g. click "MatTetris!". Enjoy.

numFigures=6;speed=6;
gLen=16;gWidth=10;bckgColor=Black;bckgColor2=Gray;figColor=Red;patColor=Blue;
fig[1]={{1,-1},{1,0},{0,0},{0,1}};
fig[2]={{-1,-1},{-1,0},{0,0},{0,1}};
fig[3]={{-1,0},{0,0},{1,0},{0,1}};
fig[4]={{-1,0},{0,0},{1,0},{2,0}};fig[5]={{-1,1},{0,1},{0,0},{0,-1}};
fig[6]={{1,1},{0,1},{0,0},{0,-1}};
mRight={{0,1},{-1,0}};
mLeft={{0,-1},{1,0}};

MovementPossible[where_]:=Block[{altData=Which[
 where=="down",{figData[[1]]+{0,-1},figData[[2]]},
where=="left",{figData[[1]]+{-1,0},figData[[2]]},
where=="right",{figData[[1]]+{1,0},figData[[2]]},
where=="rotleft",{figData[[1]],(mLeft.#)&/@figData[[2]]},
where=="rotright",{figData[[1]],(mRight.#)&/@figData[[2]]}
]}
,(Count[patData,Alternatives@@((altData[[1]]+#)&/@figData[[2]])]==0)&&(Count[altData[[1,2]]+altData[[2,All,2]],x_/;x<1]==0)&&(Count[altData[[1,1]]+altData[[2,All,1]],x_/;((x<1)||(x>gWidth))]==0)];
Move[where_]:=(figData=Which[
 where=="down",{figData[[1]]+{0,-1},figData[[2]]},
where=="left",{figData[[1]]+{-1,0},figData[[2]]},
where=="right",{figData[[1]]+{1,0},figData[[2]]},
where=="rotleft",{figData[[1]],(mLeft.#)&/@figData[[2]]},
where=="rotright",{figData[[1]],(mRight.#)&/@figData[[2]]}
]);
AddFigureToPattern:=(patData=Union[patData,(figData[[1]]+#)&/@figData[[2]]];figData={{0,0},{}});
AddingFigurePossible:=(Count[patData,Alternatives@@(({Round[gWidth/2],gLen-1}+#)&/@prefigData)]==0);
AddFigure:=(figData={{Round[gWidth/2],gLen-1},prefigData};prefigData=fig[RandomInteger[{1,numFigures}]]);
DeleteLines:=Block[{lineCount=0,ic=1},
        While[ic<=gLen,
                If[Count[patData,{_,ic}]==gWidth,
                patData=DeleteCases[patData,{_,ic}];patData=((#/.{xx_,yy_/;yy>ic}:>{xx,yy-1})&/@patData);++lineCount;--ic,
                ++ic];
                ]
            Score[lineCount]];
Score[lC_]:=Which[lC==1,totScore+=1,
                lC==2,totScore+=3,
                lC==3,totScore+=6,
                lC==4,totScore+=10];
GameOver:=(CreateDialog[{Column[{Style["Game Over!",FontColor->Red,FontSize->18],
Row[{Style["Your score is: ",FontColor->Blue,FontSize->18],Style[totScore,FontColor->Blue,FontSize->18]}]
}],DefaultButton[ResetGame;DialogReturn[]]}];)
ResetGame:=(patData={};prefigData=fig[RandomInteger[{1,numFigures}]];FigureActive=False;totScore=0;notGamingOver=True)
MainCycle:=If[FigureActive,
    If[MovementPossible["down"],
    Move["down"];,
    FigureActive=False;AddFigureToPattern;DeleteLines;],
    If[AddingFigurePossible,
    AddFigure;FigureActive=True;,
    If[notGamingOver,notGamingOver=False;GameOver];]
];
gameBoard:=EventHandler[
Panel[Row[
{Dynamic@Graphics[{{bckgColor,Rectangle[{0,0},{gWidth,gLen}]},{figColor,Rectangle[#-{1,1},#]&/@((figData[[1]]+#)&/@figData[[2]])},{patColor,Rectangle[#-{1,1},#]&/@patData}},ImageSize->300],
Column[{
Style["MatTetris!",FontColor->Blue,FontSize->18],,Row[{Style["Score:  ",FontColor->Red,FontSize->18],Dynamic@Style[totScore,FontColor->Red,FontSize->18]}],,,Dynamic@Graphics[{{bckgColor2,Rectangle[{-2,-2},{2,1}]},{figColor,Rectangle[#-{1,1},#]&/@prefigData}}],,,,,,,,,,,,,,,,""
},Center]
}]],
{"LeftArrowKeyDown":>If[MovementPossible["left"],Move["left"]],"RightArrowKeyDown":>If[MovementPossible["right"],Move["right"]],"DownArrowKeyDown":>If[MovementPossible["down"],Move["down"]],"UpArrowKeyDown":>If[MovementPossible["rotleft"],Move["rotleft"]]}];

LaunchGame:=(ResetGame;MainCycle;gameBoard);

LaunchGame
While[True, MainCycle; Pause[1 - speed/10]]
share|improve this answer
    
,Thanks very much! –  tangtaotao Jul 31 '13 at 4:53
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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