Showing posts with label how to. Show all posts
Showing posts with label how to. Show all posts

Monday, September 24, 2012

Petit Computer Journal #8


Petit Computer Journal #8





The Apple Picker Game? We're going to finish it up proper! Actually, we're not going to really make it professional quality. But we'll put on some fancy dressing on it to make it really enjoyable!

Adding color:
It was later in the development cycle (fancy words for repeatedly finding and fixing numerous bugs) that I find myself squinting at the screen looking for that last apple among the many snakes. Adding colors solves this problem. I colored the apples pink because I find red is too strong among the snake green.

Adding music:
It makes a great game. Looking at the help menu, I see a list of ready made music. Use BGMPLAY N, where N is a number. BGMSTOP to stop the music. Remember that N is a number. If you do this: BGMPLAY FANCY. That means you're playing music as defined by variable FANCY, which would be zero if you haven't set it to anything.

I purposely did not add music for level playing. I found it to be too noisy. But if you want it, add this to @NEWLEVEL
BGMPLAY LEVEL+ADJ
This will launch a new background music with every new level, with ADJ as offset.

Adding Sound Effect:
Oh, this is a good one! I added scream, hit, and coin sounds immediately. Easy sound effects! It took me awhile to add steps sound, but once I did, I never want to go back! This is how you know what you did is good!

Adding walls:
This was a doozy! The program kept hanging up (a polite way to say unintended infinite loop) and I didn't know why! Obviously, I needed to work out the math on paper, and then do exhaustive analysis upon it. I did neither. I did hack-and-slash programming, so even now, I'm not sure the solution is correct.

I did test out this form:
FOR I=0 TO 0:T=RND(5)+5):I=ABS(MY-T)-1:NEXT:WX[0]=T
You probably wonder why I bothered to put the FOR loop in there. I use it as REPEAT loop, just so you know. Notice that I set the value of I everytime. When MY==T, the loop will repeat. That is, T of any value EXCEPT WY.

The walls will erase snakes. That's fine. I also have to make sure that the walls will never form an enclosed space where the player cannot enter/exit. The easy way is to create some levels with array or DATA statements. I decided to create it dynamically, which isn't the easiest in the world, but I hate putting in DATA too much and results in repeat levels, making them boring.

Adding Lives:
I added this as I realize that the later levels may feature apples surrounded by snakes. I don't want the game to end immediately. Like any good design decision, once I put it in, I don't want to take it out.

Adding Time:
This comes in last. After a while, I started to add challenges. Can I finish 10 levels in 5 minutes? 20 levels in 10 minutes? Yes, I can! You can, too. Look at the levels and time completed. Major bragging rights, there!

Adding Alternative control:
It's not hard to do button controls. I simply extended the button readouts, and that's it! Noteworthy to mention is that I didn't put fast button where pushing L or R button results in faster movement. It's not hard to do, but I can pull the feature out after I put it in. Not a good design decision.

Adding moving snake:
I decided not to. It's not that kind of game. The game evolves from taking apples (Path Finding/Travelling Salesman) problem, to maze game, to Least Cost finding. Along the way, you have to be able to control the person very well to avoid running into snakes.

Adding customized graphic:
I decided not to. The game benefits from seeing the whole level all at once. If I use same size sprites, the size of the game would have expanded radically, for little returns. If I use double size sprites, the game will look great, but play suffers. If I use smaller playfield, the game becomes boring really quickly. If I use big sprite on top screen, and normal size for bottom screen as map, then the player will constantly look at the bottom screen. In which case, why bother?

How to CHEAT:
Yes, you can cheat! You have the source code in front of you! Whenever you feel like you want some extra lives, hit BREAK, then type this:
LIVE=20:CONT
You'll continue no problem. Your live is now 20! You have to be careful to do it so the screen does not scroll, and no apple is overwritten. I recommend waiting until the last apple is on upper right corner.

You can also add more apples, by typing this:
SCORE=9:CONT
Since the level advances every 10 points, this will cause new apples to appear at the next apple taken.

Level select is no problem either. Can you guess how?
LEVEL=15:CONT
Yup. It's that easy!

Finally, you may want a puzzle game, instead of an action game. Not a problem! Do this at @GAMELOOP

From this: VSYNC 15:GOSUB @SETB2
To this: VSYNC 1:GOSUB @SETB3

And you got yourself a puzzle game!

Professional Quality?

This game is a good Hobbyist effort, but I wouldn't call it a professional quality. There are different things that I can do as a professional, but choose not to. I already mentioned the exhaustive testing of walls. Here are some other things that I need to do in order to be professionals:

1. Limit the number of lives to 30, as to not mess up the display.
2. Add option to set background music to the levels
3. Add faster speed button
4. Save/Load High scores
5. Refresh whole screen to prevent display corruption
6. Add variety of enemies. Maybe some will add apples, others fling you randomly to another part of the screen.
7. Add time limit, allowing for levels of difficulty.
8. Also adjust player speed according to level of difficulty.
9. Add Puzzle mode from Option
10. Add replay option, play as demo on splash screen.
11. Tune up the presentation, not necessarily fancy graphics, but I would experiment with different placements of elements.
12. Make sure adding apples, snakes will not hang the game.

If I want to put this out for sale, I will add these:
13. Multiplayer option. 2 players. One is using Dpad. The other, buttons. Photo Dojo style
14. Computer player, single, double. With good path finding algorithm.
15. Selectable number of player
16. Sound/Music selection. Volume adjustable individually.
17. Optional level editor. It's not that hard.
18. Optional sprite editor. It's not that hard.
19. Optional music editor. It's not that hard.
20. Optional 3D graphic. This one is hard, and not at all useful. It's great marketing tool, though.


Wednesday, September 5, 2012

The Art of Review


I do read game reviews on the Web. Sometimes, I even buy the games based on reviews. Sometimes, though, there is a clearly biased review, when the reviewer is applying his prejudices to a product. Almost without exception, the reviewer provides excuses as to how his review can stand without change. I hope that by writing this essay, I can persuade them otherwise. Not hopeful, as biased reviewers don't really care what other people think, but perhaps there are those future writers who do care about their readers. This will give you a change to see the other side.

A Bad Hammer

There was a salesman who provided a craftsman a tool for review. The craftsman stated "This is a terrible hammer! The handle is too short. The metal is too slender. The weight is unbalanced. It is too light to hammer effectively. You will get tired too easily. I just can't see how anybody can be stupid enough to buy this hammer!"

Having thus voiced his professional opinion, the craftsman gave the tool back to the salesman.

The salesman said, "It's a screwdriver."


We can all laugh at the story. Who in the world cannot tell a screwdriver from a hammer? Nobody, that's who. However, in the world of computer programs, that is not so easy. In fact, it happened with rather alarming regularity.

The spectrum of Racing: Mario Kart - Forza Motorsport

Let's take a very successful game: Mario Kart. I don't need to tell you that this driving game is extremely fun and energetic. It's very popular with a lot of people, and rightly so. Very easy to pick up, and caters to a wide variety of people.

Here's another game that is just as well done, but without too much fan base: Forza Motorsport. It's the ultimate driving game. The simulation is highly detailed, and I was impressed by the accuracy of it. But it's not as exciting, and the courses are rather plain. Coming from Mario Kart, the feel is rather boring. Does that mean Forza Motorsport is a bad product?

Of course not! They are two different products. How can that be? Aren't they both driving games? Well, yes. How can they be different? Isn't Mario Kart with its hugely successful sales numbers clearly a "better" product? Of course not, and here's why:

It's a question of a driving GAME, and a DRIVING game. That is where the emphasis lies. Is it about a GAME? Or is it about DRIVING? Mario Kart is a great GAME, but bad driving. Forza Motorsport is a great DRIVING, but a bad game. Neither is "better" than the other. They are both great examples at what they want to achieve.

2 Different Games

It is a great mistake to treat them as the same game. Let me put it this way. Mario Kart is a game where you go from one place to another, in a frentic manner, fending off all kind of obstacles and enemies. Forza Motorsport, OTOH, is about finding that ideal line in which to make the turns, speeding up and slowing down as required, making the turn JUST RIGHT as to preserve as much speed as possible.

Read the descriptions again. Now tell me, am I wrong to say that those descriptions describe Super Monkey Ball(1) and Downhill Snow Racing? Will you claim that Super Monkey Ball and Downhill Snow Racing both represent the same game? Of course not, don't be silly! Likewise, Mario Kart and Forza Motorsport aren't the same game. They're the same GENRE, but they're not the same game!

(1) I actually haven't played Super Monkey Ball, so if it isn't accurate, substitute it with something else. Follow the reasoning anyway. Or how about this? Take Doom/Quake Deathmatch levels where you go from start spawn point to end level. The fastest player get shot in the back! That sums up my feeling about Mario Kart. If that's your game, then you'll like Mario Kart.


The Shifting Expectation

So, now there's another racing game. Let's take Ridge Racer. We can see that although the game isn't a hyper realistic driving simulation, it still leans toward the DRIVING aspect of it. Take another game, such as OutRun. It clearly leans toward the GAME aspect of it.

It is folly to review Ridge Racer while applying the standards of Mario Kart: No bombs. No holes. No beach. No underwater course. No missiles. Gosh, how boring!

It is folly to review OutRun while applying the standards of Forza Motorsport. Roads don't look like that. Speed of cars are off. How about some reasonable damage behavior here?

And yet, game reviewers would review the games per their preferences. If they like games, then they will think Ridge Racer is a bad game, citing that Mario Kart is "better". If a game review like RPG, they will rate Mario Kart as insignificant toys. In either cases, the game gets low marks for "not living up to the expectation."

I argue that as a good, impartial game reviewer, you need to be able to handle different expectations. You can't just say that you don't like the game, therefore the game is bad. Having an opinion is fine, but back it up with facts, and details about the game so that the reader can make their own mind about the game.

What Should We Do?

It's not easy to write enough details to satisfy everybody. It's even harder in print format where space is at premium and that there's only room for so many words. I tend to discount reviewers who would use their alloted words to bring unrelated scenes just to make a point. It may read better, but if it's done at the expense of missing details, then I get upset.

There's not so much excuse when it comes to On-line review, though. A whole new page is only a couple of kilo bytes. 15 minutes if you type fast. There's just no excuse of not doing your homework when it comes to the web.

There's opinion and there's fact. I do not want to catch you saying that a particular game does not feature "drifting" when I drift in that particular game in mid level! That just smacks of either stupidity (and nobody is THAT stupid) or laziness (he didn't bothered playing other than easy level? If the reviewer complained that the AI is so easy to beat, then yeah, I'd say so!)

Then it becomes his reputation that is tarnished, because I find in 5 minutes that he was wrong! I'm not saying that he only spent 5 minutes reviewing the game, but it sure looks like it! This has happened many times over the years, with many games, by many reviewers.

One of the victim was Chris Crawford (Yes, THAT Chris Crawford) who detailed the incident in his book (on Game Design), about how a review is riddled with so many factual errors that Chris Crawford wasn't sure that the reviewer got past the title screen. I am sorry to say, that the tradition of lazy reviewer continues to this day.


Is There a Bad Review?

I'm not saying reviewing a game properly is easy. It's not. It's hard. I would have said that Tetris game is boring. Then, again, I would have been very, very wrong. But at least I would describe the game properly and tried to find a demographic for it. The game may be niche, but if it's well done, and it's great for that niche, then I will give a favorable review, EVEN IF I PERSONALLY DON'T LIKE IT. I'd say something like, "Not for me, but for these [demographic] people, it's a great product." I clearly state my opinion, and yet, I give a fair review so that people other than me can still enjoy the products. I think that's important.

It's very hard to critize something after "walking a mile in their shoes." Yet it must be done that way. It's very easy to critize something you are ignorant about. Yet, it is clearly wrong. So, walk a mile in their shoes. Try to find a positive thing or two, and always give detailed factual reviews, while keeping your opinions to a minimum.

I am not saying you can never roast a product. If the designer of the game is clearly ignorant, such as putting the levels in reverse order of difficulty (Yes, it happened!), then by all means, say so. If the program is so buggy as to be unplayable, it is a disservice to your reader for you to hold out that information. But do research the issue, spending time with it, and make sure to show that you did.

This message is intended for all reviewers out there, but especially the pros. You do not want to see your scathing reviews compared to runaway sales figure, ever. By keeping your opinion to yourself, you give yourself an excuse for not being enthusiastic about it. And you really, really do not want to do a cursory review ever, only to see an amateur did it a lot better, while claiming to spend no more than one hour. And if you are the rare reviewer who lashed out to every criticism, then don't be surprised if you stay in the niche market because, really, you don't learn nor improve, and there is no hope for you.

Monday, September 3, 2012

Petit Computer Journal #5


Petit Computer Journal #5 - Buttons and Touchscreen

Let's take a little detour for now. We should be doing strings and graphics, but I want to do something else real quick: Buttons, Touchscreen, and Keyboard. In other words: INPUT.

We have done buttons, touchscreen, and keyboard inputs before. However, I'm interested in doing them all at once. And the trick is to do it without stopping the other input methods. That's not too easy.

Regarding keyboard input method that doesn't stop other process, we have INKEY$. We also have touchscreen variables TCHX,TCHY and all those. How about buttons? We have BUTTON(0), and that is sufficient. So, at the surface, we have all that we need.

The thing is, I don't want to have to structure the program into multi-threading format at this point in time. So, we will have to make some sacrifices. The INKEY$ is well enough. How about buttons and touchscreen?

In Touchscreen, it is convenient to have a drag-and-drop process. That means X1,Y1,X2,Y2,TouchStatus. Let's build that capability.

@SETT
IF TCHST==0 THEN TS1=TCHST:RETURN
IF TS1==0 THEN TX1=TCHX:TY1=TCHY:TS1=1
IF TS1==1 THEN TX2=TCHX:TY2=TCHY
TS1=TCHST
RETURN

That looks simple enough. Basically, we want to update the variables if TCHST==1. The first line takes care of that by returning from subroutine if TCHST==0. Next, we want to see which pair we want to update X1,Y1 or X2,Y2? And that's all there is to it!


The buttons isn't so simple, though. There are 4 possible arrangements that I can see:
1. No Wait+Multiple: BUTTON(0)
2. No wait+Single: @SETB1
3. Wait+Multiple: @SETB2
4. Wait+Single: @SETB3

Of these, we want no wait version. If the no wait version is equivalent to INKEY$, then the wait version is equivalent to INPUT. The whole process involve trying out different versions of the commands. You see the finished product as clean, but I assure you that the process involves repeatedly trying and failing to come up with that clean method. You do not see the hard work that is done. At least, if you ever wonder why my progress is at glacial pace, you know the reason: Lacking tutorial such as this, I do a lot of experiments, not all of them successful.

There are 4 cases and only 3 subroutines. The first case can be easily met via BUTTON(0). The rest is done with simple subroutines. It only works on the first 8 bits, corresponding to UDLRABXY. This is because the method I use requires string characters, and those only goes to 255. I typed in the character in the actual program, but for the purpose of tutorial there are two index variables used by INSTR()

1. IST1$=CHR$(128)+CHR$(64)+CHR$(32)+CHR$(16)+CHR$(8)+CHR$(4)+CHR$(2)+CHR$(1)
2. IST2$=CHR$(129)+CHR$(65)+CHR$(33)+CHR$(17)+CHR$(9)+CHR$(5)+CHR$(3)+CHR$(2)

I use this technique a lot as it simplifies things greatly. It's not the fastest running code, and so only amateur hobbyist would use it. Certainly not a professional quality code. If need be, I may changed the code later to a more efficient one. But I like doing rapid prototyping in the beginning.

One more thing, the no wait version is tricky. If you check out the clock, you will see that no-wait @SETB1 does cause the program to stop when you press the button for a long time. A way to fix this would be to use a variable, but I would rather just do it directly with BUTTON(0) or @SETB2.

@SETB1 :'SINGLE FIRE
INBUTTON$="":Z=BUTTON(0):IF!Z THEN RETURN
FOR Z=0 TO 1:Z=BUTTON(3):NEXT:Z=Z AND 255
Z=INSTR(IST2$,CHR$(Z)):IF Z< 0 THEN RETURN
INBUTTON$=MID$("YXBARLDU",Z,1)
RETURN

@SETB2 :'CONTINUOUS
INBUTTON$="":Z=BUTTON(0):IF!Z THEN RETURN
Z=Z AND 255:Z=INSTR(IST1$,CHR$(Z)):IF Z< 0 THEN RETURN
INBUTTON$=MID$("YXBARLDU",Z,1)
RETURN

@SETB3 :'WAIT
INBUTTON$=""
FOR Z=0 TO 1:VSYNC 1:Z=BUTTON(1):NEXT:Z=Z AND 255
Z=INSTR(IST2$,CHR$(Z)):IF Z< 0 THEN RETURN
INBUTTON$=MID$("YXBARLDU",Z,1)
RETURN

And those are the functions. Next, let's write a quick demo program to demonstrate the different functions. It may be best that you write a program and save it because you will be using this at all times. I know I do!

'BUTTON/TOUCHSCREEN TEST EXAMPLE
CLS:CLEAR:P1=0:P2=1
@MAINLOOP
LOCATE 0,0:?TIME$
VSYNC 1:A$=INKEY$():?A$
GOSUB @SETB1:'?INBUTTON$;
GOSUB @SETT

IF INBUTTON$!="" OR TS1 THEN GOSUB @DT
GOTO @MAINLOOP

@DT :'DRAW TEXT
IF INBUTTON$!="" THEN L1=(L1+1)%32:LOCATE L1,1:?INBUTTON$;

'DRAW BOX
IF INBUTTON$=="L" THEN P1=P1+15
IF INBUTTON$=="R" THEN P1=P1+1
IF INBUTTON$=="U" THEN P2=P2+15
IF INBUTTON$=="D" THEN P2=P2+1
P1=P1%16:P2=P2%16
SX1=FLOOR(TX1/8):SY1=FLOOR(TY1/8)
SX2=FLOOR(TX2/8):SY2=FLOOR(TY2/8)
FOR X=SX1 TO SX2:FOR Y=SY1 TO SY2:
C$=CHR$(151):COLOR P2:'0=BIG BLOCK CHARACTER IN PETIT COMPUTER
IF X==SX1 OR X==SX2 THEN C$=CHR$(150):COLOR P1:'1=VERT LINE
IF Y==SY1 OR Y==SY2 THEN C$=CHR$(149):COLOR P1:'2=HORZ LINE
IF X==SX1 AND Y==SY1 THEN C$=CHR$(152):COLOR P1:'3=UPPERLEFT
IF X==SX2 AND Y==SY1 THEN C$=CHR$(153):COLOR P1:'4=UPPERRIGHT
IF X==SX1 AND Y==SY2 THEN C$=CHR$(154):COLOR P1:'5=LOWERLEFT
IF X==SX2 AND Y==SY2 THEN C$=CHR$(155):COLOR P1:'6=UPPERRIGHT
LOCATE X,Y:?C$;
NEXT:NEXT

RETURN

For some reason, my computer does not read my memory card. That's a setback. I have to have those special characters, and so, I'm forced to do it the hard way, which is very annoying. However, either I overcome that setback, or I don't do this at all. I can work on the DSi no problem, but if I want to share it, I have to do this thankless work of translating those characters into their numeric equivalent. I wrote a simple program just for that:

'ASCII TABLE
S=0
@MAINLOOP
CLS
FOR I=S TO S+15
R=I%16
LOCATE 0,R:?I;:LOCATE 5,R:?CHR$(I)
NEXT

GOSUB @SETB3

IF INBUTTON$=="U" THEN S=S+16
IF INBUTTON$=="D" THEN S=S+256-16
S=S%256
?:?"S=";S;"   ";INBUTTON$:WAIT 60:'OPTIONAL FOR DEBUGGING
GOTO @MAINLOOP

And that's it. Not even 10 minutes. You need to provide Subroutine @SETB3, but that's trivial. Just copy the one above.



Problems and How to Ask Questions

You know how people say there's no such thing as stupid questions? I know I'm bucking the convention here, but I'd say there are! Here's a sample, quoted in its entirety:

"Help! SAVE doesn't work."

I'm not saying that SAVE command is so easy that it cannot fail. I am saying that the question doesn't even begin to show the framework in which the problem occurs. We need more data! You know how PRINT statement works, right? What if there's somebody who ask help like this: "How do you use PRINT?", following your answer with "It doesn't work."

You know it works, and you know how it works. The problem is, how does it doesn't work? You have no clue as to what problem this person encounter. So, here is how you handle a problem that you cannot solve, because the unwritten rule is, if you ask a question that you later answer without any prompting whatsoever, YOU JUST ASKED A STUPID QUESTION THAT YOU KNOW THE ANSWER TO!

Problem solving technique:
1. Ran into problem, WRITE IT DOWN!
2. Write down all the relevant elements.
3. Read the Manual/Help file
4. WRITE ALL THE POTENTIAL SOLUTIONS DOWN.
5. Implement them all.

That's step-by-step. You are not allowed to skip steps. Half of your problems can be solved this way. As for the rest, well, that's when it gets tricky.

Hard Problem Solving:
1. You are tired. STOP AND GO TO SLEEP!
2. Wake up. Eat something solid
3. Repeat problem solving steps above.

By this time, if you followed this advice, a lot of you would do a lot of face palming "Of course! Why didn't I think of that?" sequence. That happens to me, too.

Stubborn Problem Solving:
1. You are sadly misunderstanding the problem. YOU are at fault!
2. Find 3 different interpretations to the problem.
3. Also, find 3 different OTHER places where it may cause the problem.
4. Consult the manual for help.

It may help to pretend that you're a newbie who doesn't understand everything. Don't laugh. It works! I used that technique myself occasionally. For the next level you must first admit that you are stupid. No, really. You are! You may humbly ask other people for help. Ever seen somebody arrogantly ask for solution to their problem? That never gets resolved, does it? Bingo.

Impossible Problem Solving:
1. Explain What the Problem is
2. Tell what you think are the relevant elements
3. Show what you did to solve the problem
4. WRITE THE SIMPLEST, SHORTEST CODE to explain the problem.

That last element is vital. No one wants to read 200 lines of code just to debug your program. So, there. Problem solving explained. Either that or you explain your problem to a duck.

Haha, joking aside, the ability to properly explain your problem is crucial in getting it solved. You don't want to ask a question like a grade schooler if you can ask your questions like a professor!

My PRINT doesn't work!

1. Did you type it in RUN(direct) mode or EDIT (deferred) mode?
2. Did it give you Syntax Error?
3. Did it print 0?
4. Did you set VISIBILITY?

What if PRINT doesn't work because it was set to XOR Mode? How will you respond to that? You can't set Console to XOR mode, right? How does that work? This is where giving out sample code is crucial.

CLS
COLOR SET XOR ! DOIT
PRINT "HELLO WORLD"

SET and DOIT ARE not keywordS. Why is there an exclamation mark preceding it? Because when I put it after the word (DOIT!), the computer complained, DUH!

You see how sample source code clarifies the issue quickly and easily? Don't act like a grade schooler. Ask questions like a professor! When I see the words "I don't understand ..." it'd better be followed by "These are the things I tried in order to understand it."