Instead of traditional way of explaining, this guide will aim at teaching you through simple game examples.
In this first tutorial, we will go through some basics, and make a simple PONG game.
I wont explain you in detail how to make and run your Hollywood programs, I suppose you can figure that much out yourself.
Simply make program with text editor, and compile it with hollywood and run.
There are also text editors that support Hollywood in themselves, making programming much easier, as they will give you tips on the code syntaxes, as well as you can simply run the code by clicking "run" button, instead of first compiling the code into exe and then running it.
Couple of things about my explanations.
1. Sometimes I will use numbers at beginning of codelines to make it easier to explain the code. However, if you try out these example codes yourself, never use the line numbers, or code wont work.
2. If line starts with "->", it means this is what will be printed to the screen when program is executed.
Lets start:
Code: Select all
print("Hello World")
There is only one command in this code: "Print" Most Hollywood commands have "()" at end of them, ie. "Print()"
This "()" - part is the part, where the coder can and usually even needs to put stuff for that commands purpose, in this case the text "Hello World".
If you try out this code for yourself, you will notice there is a one problem. You probably wont see that text at all, since right after Hollywood prints that "Hello World"-text to the screen, program ends and hence closes itself.
If you want to see and experiment with this, try following:
Code: Select all
Print("Hello World")
REPEAT
FOREVER
I will at later point explain you the REPEAT - FOREVER part, although it is somewhat self explanatory.
As you might have noticed, I used '"'-commas on edges of the text that i wanted to print to screen. If you remove these '"'-commas, you will notice it stops working, but if you remove the space between these two words, you will notice something even stranger to happen:
Code: Select all
Print(HelloWorld)
This is, because now print() function is trying to print out variable instead of a text. But what exactly are variables?
You probably still remember from school those math questions in type of "2 + X = 3" determine the X.
That "X" is almost a variable.
If we rather change this math question to "2 + X = ?" then we have a variable.
Depending upon what the X is, will also decide, what the result will be, and X can be any number.
Idea with Variables is, that hey can store info. This info can be either numbers or letters.
For example, variable X could store number 4. Or variable X could store someones name ie. "Andreas Falkenhahn".
The practical use of Variables is many. But as simple example, lets suppose Company uses to send their letters with their CEOS full name in them:
"Greeting from Amiga Inc. This is Bill McEwen...", "Amiga Inc. CEO Bill McEwen is happy to..." and so on. There be multiple letters with CEOs name written on it. But what if the CEO Changes? It would mean, that into all different hundred letters, CEOs name would need to be changed.
And here comes variables. What if, instead of writing CEOs full name, it would be using a VARIABLE:
"Greetins from Amiga Inc. This is X...", "Amiga Inc. CEO X is happy to...".
Now when the program would be run, you would first tell it what is X, in this case "X = "Bill McEwen". When Program is now run, everytime it would encounter the X, it would change it into "Bill McEwen". And if it now happens that CEO changes, all you would need to do, would be to change the first line of code to "X = "Trevor Dickinson", and instead of doing hundred changes, you would do only one.
Lets see the usage of variables in practice:
Code: Select all
X = "Hello World"
print(X)
as you can see, this works exactly like the previous program did, but instead of telling print command to print "Hello World", we are now telling it to print out what ever variable X is containing.
Variable names can be anything, as long as some specific characters are not used, and it doesnt collide with another Hollywood command or reserved words.
Therefore, variables name could be for example: "hillbillybilly", "ceo", "agentx"... All of these are completely acceptable, and can have anything inside them:
Code: Select all
hillbillybilly = 1
ceo = "Bill McEwen"
agentx = "James Bond"
print(hillbillybilly)
print(ceo)
print(agentx)
-> Bill McEwen
-> James Bond
however, when using variables, you should aim at naming them soemthing descriptive, as example:
Code: Select all
text = "Hello World"
print(text)
using varibale name like "text" for storing the text to be printed out, makes it much easier to understand what is happening in your code.
Contents of variable can naturally be changed during the programs execution, otherwise these variables wouldnt be much use.
Code: Select all
text = "Hello World"
print(text)
text = "Anotehr text"
print(text)
text = 123
print(text)
-> Another Text
-> 123
Notice also, that although I have so far used to print only one variable at a time with Print command, i can as well print out several:
Code: Select all
text1 = "Hello"
text2 = "World"
print(text1..text2)
By simply using ".." two dots between two variables, I can add as many of them as I like. Notice however, that there is now one mistake in this code, for what I really wanted, was to get "Hello World", but now it was "HelloWorld", without the space. This is naturally, because I only told print command to dirst print contents of "text1" and right after, the contents of "text2", hence there is no space.
But this can be fixed, because I can also add letters myself without always using variables:
Code: Select all
1: text1 = "Hello"
2: text2 = "World"
3:
4: print(text1..text2)
5: print(text1.."I forgot to add space"..text2)
6: print(text1.." Now i remembered space "..text2)
7: print(text1.." "..text2)
->HelloI forgot to add spaceWorld
->Hello Now i remembered space World
->Hello World
As you can see, in line 5, I use my own writing to but between those two variables, but since i havent add any space, it writes it right after them.
in line 6 i however add those spaces, and in line 7, i put nothing but the space, and it finally comes out the way i intended it to come in the first place.
When variables have numbers inside them, they can be used to make mathematic calculations:
Code: Select all
mysalary = 2000
wifessalary = 1000
totalsalary = mysalary + wifessalary
print("Me and my wifes total income is "..totalsalary.." per month")
As you probably have already figured out, code is executed line by line basis, this means, that if you are referring to something, it must already exist before that line of code.
To take the previous example, you might think it would be nice to first make the actual action line, and then put all the variables to the end of the code so they would be easy to find:
Code: Select all
1: totalsalary = mysalary + wifessalary
2: print("Total Salary: "..totalsalary)
3:
4: mysalary = 2000
5: wifessalary = 1000
While this is clear for a human what should be happening in this small piece of code, computer doesnt get it. When computer executes line 1 to determine value for variable "totalsalary", it doesnt understand to go and look for the variables values from lines 4 and 5, but instead, simply makes the calculations based upon "mysalary" and "wifessalary"s current values.
As they havent been initialised with any value yet, their value is therefore 0. Hence, totalsalary = 0 + 0 which in total is 0.
This is also the reason why print(helloworld) resulted in 0, as after removing the commas around the "helloworld", print command thought it was suppsoed to print what is inside variable called "helloworld" and as that variable hadnt been initialized, the value was 0.
You can think code execution to be like following driving instructions. If instructions are:
1. Turn left, 2. Turn Right, 3. Drive straight forward - you cant expect to get to the right place, if you instead of first turning to left, decide that you rather start by turning right and only after that to the left.
This is same with coding. If you havent already earlier told some value to the variable, you cant expect computer to figure out that it is supposed to get that value from later point of the code, especially when considered that same variable might have different values at different points of code.
So far our program flow have been pretty straight forward. Execute line 1, then 2, then 3... after all the lines are executed, then end the program.
But that isnt very useful and the real use of variables isnt just to be some copy-paste stores, but for them to store different states of different things which will be used to dynamically create things to happen.
If you wonder what is difference between dynamic and static. The static is something that always stays the same. As example, our first
Print("Hello World")
This will always result in exactly same result.
However, dynamic version would be the:
Code: Select all
text="Hello World"
Print(text)
Similarly any game code for example is always dynamic by nature, since depending upon players actions would for example depend where the player is drawn to screen.
The basic, most common way to affect things, is by using "IF" statement.
At simplest, "IF" is followed by "THEN" statement.
as example:
Code: Select all
1: A=1
2: IF A=1 THEN text="Hello World"
3: IF A=2 THEN text="Bye World"
4: print(text)
In this program, we in first line decide that variable A contains number value of 1.
second line check if A equals 1 (which it is) and if it is, then makes content of variable "text" have "Hello World" inside it.
third line does similar check to second lines, but checks if A equals 2 (which is doesnt), and if it does, it would make content of variable "text" have "Bye World" inside it.
fourth line is simply printing out what ever is inside the variable "text", which in this case is "Hello World".
However, if you change first lines A=1 instead to A=2, you will get:
-> Bye World
And if you would change A into any other number, it would result in:
-> 0
since when "text" is not initialized its value is 0, and "text" contains data only if line 2 or line 3 is true (A equals 1 or 2), in other cases, lines 2 and 3 are ignored, in which case "text" stays uninitialized. and hence results in "0".
IF - THEN is the simplest form of IF statement, but many times it becomes necessary to execute multiple commands instead of just one, in which case you would need to write:
Code: Select all
IF A=1 THEN text = "Hello World"
IF A=1 THEN B=3
IF A=1 THEN print(text)
Code: Select all
IF A=1
text="Hello World"
B=3
print(text)
ENDIF
This works so, that when you state the "IF A=1" then if A equals 1, then all the lines after this line will be executed, until comes the line that says "ENDIF"
Since in the first "IF" example, there were two different IF - THEN statements, and they both had to do with variable "A"s statement, there is another way to do it:
IF - ELSEIF - ELSE statement.
This works the following way:
Code: Select all
1: A=2
2:
3: IF A=1
4: text="Hello World"
5: ELSEIF A=2
6: text="Bye World"
7: ELSEIF A=3
8: text="Still World"
9: ELSE
10: text="A:s value should be between 1 and 3"
11: ENDIF
12:
13: print(text)
By changing value of A, you can get all the 4 different texts printed out.
This system works following:
in line 3 it is first checking the first statement, wether it is true or not. If it is true, then it goes to line 4 and does the stuff, in this case, assign "Hello World" to variable "text". After this it would go to line 5, and see there is another elseif statment.
since IF statement already was true, it would in this case work same as "ENDIF" and instead of executing further, jump directly to line 11, which is ENDIF, and continue executing from that point on to line 12 (empty) and 13 (print).
If line 3s statement is not true, then it next checks statamenent at line 5, if that is true, execute line 6 and from line 7 jump to ENDIF again.
If line 5s statement is not true either, then jump to line 7.
If line 7s statement is not true either, then finally jump to line 9, and since it tells "ELSE", that means that in case none of the previous IF - ELSEIF statements were true, then execute the lines between ELSE and ENDIF.
First of all, I want to point out, that unlike IF - THEN statement, this IF - ELSEIF - ELSE doesnt limit the number of lines to execute, there can be several lines executed:
Code: Select all
IF A=1
text = "Hello World"
B=2
ELSEIF A=2
text = "Bye World"
ELSE
text = "Error - A is not in range"
ENDIF
Second, you can choose wether to use ELSE and ELSEIF. You can use both or only one of them, or actually not even either of them (IF - END - execution of multiple lines):
Code: Select all
IF A=1
text = "Hello World"
ELSE
text = "Error"
ENDIF
Code: Select all
IF A=1
text = "Hello World"
ELSEIF A=2
text = "Bye World"
ENDIF
You can also have multiple "IF" statements, inside "IF" statements:
Code: Select all
A=1
B=1
IF A=1
IF B=1
text="Hello World"
ELSEIF B=2
text="Bye World"
ENDIF
ENDIF
print(text)
If you change "B" to 2, you will get "Bye World", if you change "A" into something else, you will get 0, since this A=1 block, which inside itself had B=something block will then never be executed.
Notice that sometimes there might be a reason, that instead of using IF - ELSEIF - ELSE statment, you want to use multiple IF statements, or perhaps absolutely dont want to use:
Code: Select all
A=1
IF A=1
text="Hello World"
A=2
ELSEIF A=2
text="Bye World"
A=3
ELSEIF A=3
Text="Another World"
A=1
ENDIF
Using previous examples way, this can be achieved. Each time code comes here, it checks what number A equals. If A equals 1, it makes content of "text" - variable to be "Hello World" and also changes variable A to become 2, so that when code next time comes to this same place, it would instead pick the "A=2" statement place to be executed.
What is important to notice is, that each time code gets here, only one of these statement places is going to be executed. Therefore when A=1 is already executed (making A=2 become true) it jumps directly to ENDIF and continues executing code.
Many times, this is the preferred way, since if it would execute each IF - ELSEIF statment as long as they are real, then in this previous example, it would always execute them all, and instead of ending up printing different text each time, it would always be printing the "Another World" out since first A would equal 1, then because of that, it would change to 2, after that it would check if A equals 2, and once again change to 3 and then finally check if A = 3 and get text as "Another World". However, this is not how IF - ELSEIF - ELSE works, it will always only execute one of those conditions, the first one that is true.
But sometimes it might be favored that all be executed one after another, in this case you will just have to use multiple "IF"s:
Code: Select all
IF A=1
text="Hello World"
A=2
ENDIF
IF A=2
text="Bye World"
A=3
IF A=3
text="Another World"
A=1
ENDIF
This code of course makes no sense, but just to get the idea, since sometimes this is how you wish it to work out.
Notice also, that when using IF - ELSEIF - ELSE statements, only the first one to be true is executed:
Code: Select all
A=1
B=1
IF A=1
text="Hello World"
ELSEIF B=1
text="Bye World"
ENDIF
In previous examples i was always using same variable (A) on IF and ELSEIF statments, but sometimes it might be that you have multiple "IF" conditions, which are not necessarily excluding each other out, in these kind of cases you have to be careful not to make a mistake where both A=1 and B=1 lines were supposed to be executed, but in this case, only A=1 is executed, since it is the first true statement the program sees, and after executing that statements lines, it jumps directly to ENDIF which ends the whole IF - ELSEIF - ELSE block.
Up to this point, our code have always went directly from beginning to end, line by line, perhaps jumping some lines thanks to "IF", statements, but regardless, they have always been doomed to sooner or later, end.
And the example about text that would be changing between three different texts is useless, if code ie executed only once.
While there are programs in which code is suppsoed to be executed just once, most of the programs, for example games, are supposed to keep executing the code again and again forever, until user himself decides to quit the program.
To achieve this, we could for example use REPEAT - UNTIL/FOREVER statement.
as example:
Code: Select all
A=1
REPEAT
IF A=1
text="Hello World"
A=2
ELSEIF A=2
text="Bye World"
A=3
ELSEIF A=3
Text="Another World"
A=1
ENDIF
Print(text)
FOREVER
-> Bye World
-> Another World
-> Hello World
-> Bye World
->...
When program sees "REPEAT", it will mark that spot.
When program comes to the point of "FOREVER", it will jump to the REPEAT and continue executing code from there, effectively repeating the IF - ELSEIF - ELSE statement again and again, and hence changing the contents of the text, as well as the number stored inside variable "A". And during each REPEAT - FOREVER cycle, also print the current value of "text" at PRINT(text).
Only way to stop this, is by quitting the program using "CTRL" + "C" combination.
However, instead of using FOREVER to make it last forever, we can use UNTIL, which tells the condition at when to continue past that UNTIL point.
example:
Code: Select all
1: A=1
2:
3: REPEAT
4: A = A + 1
5: print("Hello World")
6: UNTIL A=5
7:
8: Print("End of Code")
->Hello World
->Hello World
->Hello World
->End of Code
in line 1 This program first assigns value 1 to variable "A"
At line 3 comes the REPEAT command, which makes it so that lines 4 and 5 are being continuously executed, until the line 6s UNTIL statement of "A equals 5" is true, at which point it will continue executing the code forward.
What happens at lines 4 and 5 is following:
line 4 says that A = A + 1, this means, that if A is for example 2, then A is same as 2 + 1, which is 3. This is good way to get A to increase its value by 1 each cycle.
At line 5 it simply prints out text "Hello World" using print() command.
Notice one thing here. When you look at the code, you first look, and programmer have probably so also intended, that "Hello World" would be written 5 times before exiting the REPEAT - UNTIL CYCLE, but if you look it cycle by cycle you notice the error.
A starts from 1, and before "Hello World" is wrote even for first time, A is already increased to 2. Therefore Print command is only executed when A is 2, 3, 4 or 5. Since when it is 5, it is already going to continue the code forward.
This kind of bug is very easy to miss on codes.
Just like "IF"s, so can REPEAT - UNTIL commands be multiple inside themselves, and you can have even multiple "IF"s inside REPEAT - UNTILs as well as multiple REPEAT - UNTILs inside "IF"s.
Code: Select all
1: A=0
2: B=0
3:
4: REPEAT
5: A=A+1
6: B=0
7: REPEAT
8: Print(A..B)
9: B=B+1
10: UNTIL B=10
11: UNTIL A=10
->02
->03
...
->10
->11
->12
... all the way until 99
What happens in this is that at beginning, lines 1 and 2 A and B is assigned with value 0.
Then comes the first REPEAT at line 4, which keeps cycling through lines 5 and 6. Each time this cycle happens, A will increase its value by 1, and B will get back to 0 (actually, line 2s initialization of B is not even necessary since same happens here anyway)
But before this lines 4 and 5 cycle is repeated, there will first be execute another REPEAT - UNTIL, which cycles through line 8 and 9.
Line 8 prints out current values of A and B, effectively making it 00, 01, 02... (A being 0 for the duration of the whole REPEAT - UNTIL, B being the number changing)
When B reaches 10, it will end the REPEAT - UNTIL, and continue the previous REPEAT - UNTIL. However, part of previous parts cycle, was this second REPEAT - UNTIL, and it will be executed again and again, until A reaches 10 as well.
By other words, first cycle is executed only 10 times, while second cycle is executed 100 times in total (10 times the 10 cycles).
There could be even more REPEAT - UNTILs inside these, as well as IF statements and any other Hollywood program flow control commands.
In examples before, I have been using variable equals something, but there is also other options instead of direct comparison of value. You could also use statements like "Greater than" or "Less than" for example. There are some obvious uses for these kind of statements, for example on untils.
Example:
Code: Select all
REPEAT
A=A+2
UNTIL A=10
Surely idea is that when A reaches 10, it would continue forward, but now it would never reach exact 10, since it would first become 9, then 11, 13, 15... making the UNTIL statement unintentionally never true. Or what if A is already bigger than 10 when it reaches that point? Same problem again.
Instead of comparing exactly, we can use Relative comparing.
Code: Select all
REPEAT
A = A + 2
UNTIL A > 10
Now cycle works fine, regardless if A is 1 or above 10 when it enters the cycle.
With these basic commands, we are already able to make a simple PONG game.
Naturally, I wouldnt really make a Pong game this way, but would use different technics to achieve the same, but I by purpose kept it simple and with minimal amount of commands.
There are commands that I havent gone through yet, but they are much simpler from their nature than these basic programming commands I have went through now.
I will keep explaining place by place what I am doing and why, as well as explain the commands that havent been explained yet:
Code: Select all
@SCREEN {Mode = "FakeFullScreen"}
@DISPLAY {Width = 1920, Height = 1080, Borderless = True, ScaleMode = #SCALEMODE_AUTO, FitScale=True}
stickwidth = 40
stickheight = 200
playerx = 1800
playery = 500
computerx = 110
computery = 500
computerspeed = 3
ballx = 930
bally = 500
ballsize = 30
ballstartspeed = 1
ballspeed = ballstartspeed
ballspeedincrease = 1.10
ballxdirection = "right"
ballydirection = "up"
top = 0
bottom = 1050
leftedge = 50
rightedge = 1900
playerscore = 0
computerscore = 0
quit = 0
BeginDoubleBuffer()
Repeat
Cls(#BLACK)
If ballxdirection = "right"
ballx = ballx + ballspeed
If ballx > rightedge
ballx = 1000
bally = 500
ballspeed = ballstartspeed
computerscore = computerscore + 1
EndIf
ElseIf ballxdirection = "left"
ballx = ballx - ballspeed
If ballx < leftedge
ballx = 1000
bally = 500
ballspeed = ballstartspeed
playerscore = playerscore + 1
EndIf
EndIf
If ballydirection = "down"
bally = bally + ballspeed
If bally > bottom
ballydirection = "up"
EndIf
Else
bally = bally - ballspeed
If bally < top
ballydirection = "down"
EndIf
EndIf
If computery < bally
computery = computery + computerspeed
ElseIf computery > bally
computery = computery - computerspeed
Else
/*nothing*/
EndIf
playery = MouseY()
Box(ballx, bally, ballsize, ballsize, #WHITE)
Box(computerx, computery, stickwidth, stickheight, #WHITE)
Box(playerx, playery, stickwidth, stickheight, #WHITE)
TextOut(300, 30, computerscore)
TextOut(1630, 30, playerscore)
col = Collision(#BOX, ballx, bally, ballsize, ballsize, computerx, computery, stickwidth, stickheight)
If col = 1
ballxdirection = "right"
ballspeed = ballspeed * ballspeedincrease
EndIf
col = Collision(#BOX, ballx, bally, ballsize, ballsize, playerx, playery, stickwidth, stickheight)
If col = 1
ballxdirection = "left"
ballspeed = ballspeed * ballspeedincrease
EndIf
Flip()
If IsRightMouse()=1 Then quit = 1
Until quit=1
Two first lines are
Code: Select all
@SCREEN {Mode = "FakeFullScreen"}
@DISPLAY {Width = 1920, Height = 1080, Borderless = True, ScaleMode = #SCALEMODE_AUTO, FitScale=True}
These are both commands that tell us what kind of screen to open. FakeFullScreen means that it is opening a window of size that occupies your whole screen, and while it is actually a window (you can even drag it around), it looks like a screen. (There is difference between screen and window, which I am not going into at this)
@DISPLAY on the other hand tells other stuff about your display, like that the resolution is HD resolution (1920x1080), borderless means that there are no visible borders seeable, SCALEMODE_AUTO tells that regardless of the size of your display, it will always autoamtically stretch it to right size. So if you have screensize of 640x256, it will shrink the picture to right size to fit your screen, and similarly, if your resolution is bigger, it will stretch the images to fit it right.
You dont really need to understand those two lines at this point yet. But they are necessary to put in some way, just copy paste from here.
After these, there are many Variables I am initializing for the program. I am putting all the variables to beginning, so it is easiest to see what bariables are being used, as well as change them. For example, you could try changing the value of ballspeed or computerspeed and see what happens. Notice that some variables are shared. What I mean by this is that for example size of the pongstick is same for both computers and players pongstick, hence I have only decided to use one stickwidth variable, which i use to put both players as well as computers stick. Therefore, if you change this value, size of both players as well as computers pongstick changes.
Notice the Quit = 0 part.
This is how I have put QUIT option for player. Following lines are important for it:
Code: Select all
QUIT = 0
REPEAT
if isrightmouse() = 1 then QUIT = 1
UNTIL QUIT=1
What happens is, that first it is told that value that variable "QUIT" holds, is 0.
Then comes the REPEAT - UNTIL. Lines between these make the actual game, and these lines are repeatedly being executed to make the game move.
UNTIL condition is that if QUIT equals 1, then it will continue forward (and end the program, since there isnt anything else there beyond that point left to execute)
Only way to make QUIT become 1, is by clicking Right Mouse Button.
isrightmouse() tells the state of the right mouse button. It works in states 0 and 1. 0 means that it is not pressed, 1 means, it is being pressed.
What that line is effectively doing, is checking if Right Mouse button is being pressed (IsLeftMouse() = 1) and if that happens, then it changes the value of QUIT to 1, which means that when REPEAT - UNTIL cycle reaches UNTIL part, it will continue out of the cycle and effectively ends the program.
Next I am explaining the movement. Movement is very simple in this. Ball moves only to 4 different directions. Upleft, upright, downleft, downright.
I am using variables balldirectionx and balldirectiony to tell which direction ball should be moving to.
Code: Select all
If ballxdirection = "right"
ballx = ballx + ballspeed
For example, if display is FULL HD display with 1920 x 1080 resolution, it means that there are 1920 different spots where something can be drawn on vertical (x) line.
Displays work so, that location 1 is to the left edge, and location 1920 is to the right edge of the screen. Therefore, if i want to move something towards right, I need to draw it bigger numbered location. Therefore ballx = ballx + 1 moves ball, one pixel towards right.
Similarly Horizontally (y) numbers work 1 being on top of the screen, and bigger numbers being at bottom of screen. location 1,1 is therefore at topleft corner, while location 1920,1080 is at bottom right corner.
You may also notice, that I didnt use ballx = ballx + 1, but isntead used, ballx = ballx + BALLSPEED.
This is so I can have better control at what is the speed of the ball, as well as have possiblity to increase balls movement speed during play. At beginning Ballspeed is 1, hence at beginning of game, saying ballx = ballx + 1, is true, although at later point it isnt anymore.
After I have moved the ball, there comes another thing I have to check, did it reach the right edge yet?
Code: Select all
If ballx > rightedge
ballx = 1000
bally = 500
ballspeed = ballstartspeed
computerscore = computerscore + 1
EndIf
If this happens, then we first decide that ballx = 1000 and bally = 500, effectively making ball go to about middle of screen.
ballspeed = ballstartspeed. Reason for ballstartspeed is, that during the game, ballspeed keeps getting higher. By using this variable "ballstartspeed" we can simply change this number at beginning variables place, and everytime score happens, get the balls speed go back to the starting speed.
finally, I am using variable computerscore = computerscore + 1. This is simply the amount of points the computer has. Since we know this happens only when right edge is reached, it is clearly a point for computer.
In balldirectiony case things work slightly different:
Code: Select all
If ballydirection = "down"
bally = bally + ballspeed
If bally > bottom
ballydirection = "up"
EndIf
if this is the case, then move the ball similarly as with x we did.
After that once again check if y have reached the edge of screen (or in this case - bottom)
If y indeed have reached bottom, then in this case change the "balldirectiony" to "up", so the ball would next time go upwards. Similarly in Hitting top code is similarly chaging balldirectiony to become "down" again. Effectively making ball go from top to bottom and back forever and ever more, making it look like that if it hits the edge of screen, it bounces from it.
Then comes the simple AI that this game has:
Code: Select all
If computery < bally
computery = computery + computerspeed
ElseIf computery > bally
computery = computery - computerspeed
Else
/*nothing*/
EndIf
In practice this means that computer simply follows the ball, and when speed of ball becomes higher than computers speed, then computer will fail to hit the ball anymore.
notice the ELSE statement. There are two things to learn here.
First is the "/*" and "*/", this is so called comment tag. "/*" starts the commenting, which means that we can write anything we like after that one without affecting the code in any way, and then the "*/" ends it and after that point all that is written, will be executed as normal code again.
But more importantly, there are now cases of computer y and ball y are bigger or smaller, but what if it is the same? This ELSE is there to handle that, although there isnt really anything to handle since idea is taht coputer stays still, in which case no values of any variables are changed.
Basically there isnt even any need for that ELSE, but I put it there just for educational purposes.
Now that programs logic is eplained, lets go to graphics part:
Code: Select all
Box(ballx, bally, ballsize, ballsize, #WHITE)
Box(computerx, computery, stickwidth, stickheight, #WHITE)
Box(playerx, playery, stickwidth, stickheight, #WHITE)
TextOut(300, 30, computerscore)
TextOut(1630, 30, playerscore)
TextOut works simple. you tell x and Y spot where you want to display the text, in this case 300, 30 and 1630, 30, and then you tell what text to print there, which in this case is number variable holding computers and players current score.
BOX commands arent really any more difficult. First you simply tell where in screen you want to place them by giving X and Y co-ordinates. Two next numbers tell the width and height of the box you wish to draw. Last detail is the color of the box, which i in this case used #WHITE.
Since ball is simply a rectangle, I am using for both its width as well as height variable "ballsize". You change that, and it becomes smaller or bigger rectangle.
Since pong sticks size is same for player as well as computer, I have simply used stickwidth and stickheight which i use for both computer as well as player.
Notice that playerx and computerx are actually static. During the program execution, they never change. Sticks only move in Y.
Similarly the line
Code: Select all
playery = MouseY()
practically whole movement of players pong stick is handled in:
Code: Select all
repeat
cls(#BLACK)
playery = MouseY()
Box(playerx, playery, stickwidth, stickheight, #WHITE)
until quit=1
After all the graphics are drawn, we are going to Collision testing to see if one of the pong sticks have touched the ball:
Code: Select all
col = Collision(#BOX, ballx, bally, ballsize, ballsize, computerx, computery, stickwidth, stickheight)
If col = 1
ballxdirection = "right"
ballspeed = ballspeed * ballspeedincrease
EndIf
col is simply a variable to handle the result of collision test (which is either 0 - no collision, or 1 - collision)
Collision command works so, that first we are telling what kind of collision we are checking for, in this case we are looking wether two rectangular areas are colliding with each other (we wouldnt actually even need to draw anything to check this, since this doesnt check if any two images are colliding, just if two defined areas are touching).
Then we first tell the x and y of the first rectangle areas, and then the width and height of it. Then similarly second boxes x and y and width and height. After this Hollywood calculates if these would collide or not.
If collision did happen, then it goes inside the if statements execution. Since this is very simple game, we know that for example in this case, if ball touches computers pongstick, then we already know the ball was travelling from right to left, and hence we can simply tell it to change its direction to go towards right from now on.
In addition I am also increasing balls moving speed. This is handled by using ballspeedincrease variable, which works with simple mathematics.
I am using 10 percent increase on each hit in this program. I could do it some other way, but easiest way to get 10 percent increase mathematically, is by multiplying the number by 1.10.
For example 100 X 1.10 = 110 (which is 10 percent more), 110 x 1.10 = 121 x 1.10 = 133 x 1.10 = 146 x 1.10 = 160...
As a last thing, our graphics explanation is not complete. There are still:
Code: Select all
Cls(#BLACK)
BeginDoubleBuffer()
and Flip()
Cls is same as Clear Screen, and it does exactly that. It will make the whole screen become of the defined color (in this case Black), making it look like screen is cleared.
This is necessary, since each time we draw a box, it would simply be drawn on top of the previous ones, but by clearing the screen between these drawing, it makes it look like these boxes are moving.
You can try remove CLS line and see for yourself what happens.
However, this is not so simple a thing as simply putting CLS command, since without Doublebuffer and Flip, it would work so, that you would see each thing happening. First screen being cleaned, then each rectangle being drawn. This would most likely cause annoying flickering (depending upon your hardware etc.)
Therefore there is this BeginDoubleBuffer() and Flip()
You first start with BeginDoubleBugger() (and remember to do it before the graphics REPEAT - UNTIL loop starts, since you are supposed to do it only once), and after that instead of drawing stuff visibly, Hollywood will draw everything on background, unseeable to player.
When Flip() is used, it will update the screen to the current one. You could think it as if someone would keep drawing boxes on paper, that you can either have it so that he takes clean paper and starts showing whole drawing process to you, or then he instead shows you the paper only after he have already finished drawing everything there.
This is practically same that is happening with DOuble Buffering.
This was the simple PONG, experiment with the numbers and see what happens.
I however, at this end still want to put one more thing that i by purpose left out of this example, but which fixes one problem.
Now all the movement is based upon ball and computer moving some fixed amount each cycle. However, How long it takes for one cycle depends upon your machine. Vrey slow machine, and it is deadbeat slow, and very fast machine, and you will lose before you even notice it.
You can see this same problem with old Sierra games. They had slow, normal, fast, fastest speed as options, if you chose the fastest, they were going as fast as they could, and with modern machines, thats real fast. fast enough that you wont even see the screen when its already changed to next one (since your character moved to the edge already).
There is a fix for this. Instead of tweaking with numbers on each different machine trying to find suitable speed, we can use Clock to speed everything so, that regardless how fast or slow your machine is, it will always work the same speed for everyone.
First of all, add following line right before REPEAT
Code: Select all
StartTimer(1)
Next, as last thing before UNTIL you put following:
Code: Select all
Repeat
timepassed = GetTimer(1)
Until timepassed > 3
ResetTimer(1)
timepassed = timepassed / 1000
REPEAT - UNTIL loop is there constantly looping, until at least 4 time units have passed. "timepassed" variable saves the current amoutn of time passed since clock was started/reseted, and if it isnt at least 4, it keeps continuing to do so, until clock shows at least 4.
After UNTIL condition is met, there comes the ResetTimer(1), which tells HOllywood to put clock number 1, back to 0 and start calculating from beginning. This way we will each time get a new time that have passed since the last time the cycle was completed.
Notice that it is very important that right after GetTimer, as soon as possible, ResetTimer is executed.
one thing that tempts programmingwise would be to first have the timepassed = timepassed / 1000, but if these two would be upside down, then that would mean, that if for some reason machine would get stuck for this line, it wouldnt affect the clock in anyway, making the game move at wrong speed.
Reason for this timepassed = timepassed / 1000 is, that first of all, 1000 time units, is same as 1 second of time passed.
This line is for mathematical reasons to make things later simpler. This has similar idea as the 1.10 multiplier to get the 10 percent increase.
In this case, lets say time have passed 100 units, that is 1/10th of a second. By dividing this number by 1 000, we will get 0.1 as a result.
If some character is supposed to move at speed of 200 pixels per second, we can use following calculation: characterx = characterx + (characterspeed * timepassed), which would be characterx = characterx + (200 * 0.10), which means, in 1/10th of a second, this character would move 20 pixels - exactly the amount it should move.
Now that the timer is done, we still need to apply the system to all the movements (except players which speed is based upon the speed player moves the mouse):, you have to change couple of lines:
Code: Select all
ballx = ballx + ballspeed ---> change into ---> ballx = ballx + (ballspeed * timepassed)
Code: Select all
ballx = ballx - (ballspeed * timepassed)
bally = bally + (ballspeed * timepassed)
bally = bally - (ballspeed * timepassed)
computery = computery + (computerspeed * timepassed)
computery = computery - (computerspeed * timepassed)
notice now that speeds are also now very different. For example, ballspeed = 1 defined at beginning, will now mean that it moves 1 pixel each second, making the trip from one edge to other take about half an hour. Personally I think that is bit too slow, and I would recommend rather changing it into something like 300. Similarly Computer speed of 3, is deadbeat slow as well, perhaps 1000 for that now.