当前位置:网站首页>Teach you to write a classic dodge game
Teach you to write a classic dodge game
2022-06-24 16:27:00 【HZFEStudio】
to examine :nightcat
Preface
Because the author is just an ordinary page boy , Not subordinate to the game industry . I usually write some small games because of my interest , Some small ideas often pop up in my mind . So a lot of knowledge is just made up by yourself .
Therefore, this article is only to throw a brick to attract jade , Tell you how I went from zero to one , Step by step to complete a page game that can be played . If you are a developer in the game industry or a developer planning to enter the game industry , It is recommended to read more professional books and learn professional game framework and game knowledge .
Thank you in advance .
Reading threshold
- How much is it Typescript
- How much do you know Canvas
- I have seen a little of teacher Ruan Yifeng's ES6 course
- I still remember a little high school math
Finished drawings
qq There is something wrong with the recording screen , It accelerates and the colors flash around , There is an online experience link at the end of the article , Those who are interested can experience it .
Foreplay
Initialize the development environment
Environment doesn't really matter , We only need one canvas Tags and a support typescript The environment is good . What I choose here is the simplest and fastest packaging tool Parcel. No additional configuration is required , Use it out of the box .
Then we can start to introduce our game subject objects
Not directly used here index.ts To write the game content is to facilitate the subsequent increase UI Interface . By passing canvas Component and configuration width and height new A game object , Subsequent management of the game process 、 The rendering of the canvas will be implemented here .
A light gray background is added here , Test whether it can render normally
WOW, There is ! So our first step , The development environment is arranged .( No technical content = =
Introduction to canvas
The canvas is actually <Canvas> Elements , We can use it to create a context , That is, the code in the above figure ctx, By calling ctx Upper api, We can draw the content we want to show on the canvas .
Solve the problem of blurring under the high-definition screen
One point to consider when creating a canvas is DPR problem , That is, the device pixel ratio . For example, the code in the above figure , We will 600x600 The canvas is rendered in a 600px x 600px Elements on , In the high-definition screen (DPR >= 2) In the scene of , There will be a vague phenomenon . Specifically, I'm interested in why fuzzy people can search by themselves . All in all , To solve the problem of blurring in the high-definition screen , We have to enlarge the canvas to an equal scale .
In this way DPR = 2 In the scene of ,Canvas There will be no ambiguity .
Let the canvas move
Game , It's still a game if you can't move . So we have to move the canvas next , The main one used here api window.requestAnimationFrame To tell the browser to run as smoothly as possible ( Per second 60 frame ) Run our game . An additional point to note is that the canvas needs to be emptied before each redrawing .
In this way, our canvas will be displayed in seconds 60 The frame speed is refreshing ( Although there is only a gray background now, there is no difference .
performance optimization
One 、 Multi canvas rendering
If your background is complex enough , Consider using a canvas to render the background . So you don't have to redraw every second 60 Secondary background . Because the game we play this time has a solid background , So the rendering of a single canvas is finished .
Two 、 Off screen rendering
If your game screen is very fancy , The game screen is jammed with insufficient frames . Consider off screen rendering , The principle of off screen rendering is to create an off screen Canvas When the cache , Cache the contents that need to be drawn repeatedly in advance , Thereby reducing API Loss of calls , Improve rendering efficiency . If you are specifically interested, you can go to search , I didn't use it either .
🧚*️ spirit Sprite
A sprite is actually an object , Each individual element on the canvas can be regarded as a sprite . Sprites can contain locations 、 shape 、 Behavior and other attributes . No amount of code is intuitive .
In this way, a basic wizard abstract class is implemented , It contains the most basic location information of an element , It also provides two methods for canvas rendering and updating sprite information . Our later wizard implementations will inherit the abstract class development .
Positive
Realize the bullet wizard
First of all, we need to confirm the attributes that a bullet wizard should have , In addition to the location , It also requires the radius and color of the bullet, as well as the direction and speed of movement .
Because the bullets are random , So the position radius of the bullet should be randomly generated within a range . I set the specific game design like this :
- Bullets are generated off screen , And move to a certain range near the target
- The larger the bullet radius , The slower you move
- Remove when bullets fly off screen , Keep the number of bullets on the screen constant
After confirming the game settings, you can start typing the code , First of all, we must determine the functional scope of the bullet wizard , We just need to give the bullet Genie a place , A size , There is another goal . The bullet wizard needs to generate the corresponding moving direction and speed according to the target .
The moving direction and speed of the bullet shall be reserved for the time being TODO, First, we got the location radius and other attributes of the bullet . also , In order to make the subsequent games easier to maintain , We put all the game configuration related values , Put it all together config Inside management .
Next, you can implement it step by step according to the design :
First of all, sir, into a random bullet radius
Then randomly generate the position of the bullet , Here we are on the outside edge of the screen in four directions , Random position generates a bullet
Because we haven't been a player spirit yet , So for the time being mock One goal . And make an array to add bullets , Later, we have to control the length of this array to control the screen density , This is the final method :
At this point, the position and radius of the bullet are , Next, the moving direction and speed are realized , Back to our bullet Genie . First we have to calculate our moving speed according to the radius , Because the larger the radius, the slower the speed , So use the maximum velocity to reduce the proportion of the radius within the radius by multiplying the velocity range :
Speed has improved , Now we have to divide our velocity into horizontal velocity and vertical velocity .
First of all, let's popularize the methods that people usually don't use Math.atan2 , This method can get the angle of two points . Stick the mdn Overview :
Math.atan2() Back from the origin (0,0) To (x,y) The line segment of a point is related to x The plane angle between the positive directions of the axes ( Radian value ), That is to say Math.atan2(y,x)
So suppose our goal is to stay where we are (0, 0) The coordinates of the bullet are ( The bullet x - The goal is x, The bullet y - The goal is y).
So we can get the angle ( By the way, the target is also randomly shifted , Otherwise, it would be very stiff to go straight to the target )
With an angle , Simple use of high school trigonometric function knowledge , We can easily divide our speed into horizontal speed and vertical speed .
Finally, write down the methods of drawing bullets and updating bullets
Remember to update the game after each rendering , Then add the bullet rendering and bullet update to .
Finally, let's modify the update logic , The screen density must be controlled at a fixed value . After adding the bullet essence, we're done !
wuhu ! One success , The barrage came out !
Implement player sprites
Player sprites are relatively simple in attributes , The old rules go directly to the game settings :
- Player shape is triangle ▲, The direction is always in the direction of movement
- You can use the keyboard wsad and ↑↓←→ Manipulation
First step , At the beginning of the game , Initialize player sprite
Then the second step begins to draw triangles ,x and y Is the center of gravity of the triangle , Then set a distance from the center of gravity to the three corners d , Then we can calculate the coordinates of the three points
A: (x, y - d)
B: (x - Math.cos(30deg) * d, y + Math.sin(30deg) * d)
C: (x + Math.cos(30deg) * d, y + Math.sin(30deg) * d)
Then add the code according to the formula , Save and see ~
With , A small triangle comes out .
Because the triangle needs to face the moving direction , So we have to add the rotation angle , because rotate Default is based on (0, 0) Point rotated , And we need to rotate based on the center of gravity of the triangle , So let's use it first translate Offset , Shift to the center of gravity and then move back , Finally, don't forget to reset the rotation .
Then you can handle the player control movement . First of all, we have to support oblique movement , For example, top left, top right, etc , A total of eight directions , So we add a field to indicate which direction the player is currently moving .
Here we use the binary method , use 0001 On behalf of ,0010 On behalf of ,0100 For left ,1000 For right . And direction and direction can be combined ( for example 0101 It stands for the upper left ), So we can use a number to represent eight directions .
We just need to press the button or ( | ) Check the corresponding digits , When you release the key again, you can contact ( & ) Reverse the corresponding digits (~). You can easily record the current direction of progress .
When updating later , Then update the position and rotation angle according to the direction, and you are done .
Don't forget edge detection , Avoid players running out of the area .
Save code , Let's test it out !
With ! Look at this flexible little arrow , But now nothing happens when you hit a bullet , It's the last step away from completion !
collision detection
Judge whether the triangle collides with the circle , We need to judge two situations , One is that the center of the circle is in the triangle , There's a collision . The other is to judge whether the distance from the center of the circle to the three sides is less than the radius , If so, a collision occurs .
The first is easier to judge : Whether the center of the circle is in the path of the triangle . So we have to extract the code that drew the triangle path before , And then we'll use a few corners , Therefore, the acquisition of several corners is also extracted into a single method :
And then we need to use isPointInPath Just judge whether the center of the circle is in this path :
The second judgment is more complicated : Judge the distance from the center of the circle to the three sides , Here we need to use the knowledge of vectors :
Let the sides of the triangle AB The vector is v1, Angle to center AO The vector is v2, We need to get AO stay AB A projection on a vector AC The length is u.
According to the dot multiplication formula of the vector :
Then we will v1 unitalize ( normalization ), Both
Then according to trigonometric function knowledge , It is known that |v2|cosθ Is the projection we need u, Hurry to implement it with code :
Here projection u There are also three situations ( Corresponding to the figure below 123):
- The first is in A Click on the left u It's a negative number , The nearest point is A spot
- The second is in B The length of the projection beyond the edge when the point is on the right , The nearest point is B spot
- The third is that the circle is just above the edge , The nearest point is C spot
Get the point whose center is closest to the edge , Calculate the distance by using the formula of the distance between two points , Then judge whether the distance is less than the center of the circle to detect whether there is a collision :
Then when updating the bullets , To determine whether the player has been shot ( Remember to render again after the game , Otherwise, the picture will stay at the moment before the collision , Look like BUG)
After the test , Find something wrong , Because the player sprite rotation used canvas Self contained API rotate Spinning , After that, collision detection uses triangles that are not rotated to judge , Therefore, the collision will be triggered even if there is no contact .
The solution is to rotate The rotation is changed to the three corners of a solid triangle , Here we need to use the shaft formula :
Get it done , Hurry up and try
" ! You can play normally , But it's not fun to play like this , Next, let's make a final improvement , Add the fraction count .
Count
Because this is a game of persistence , So we use the seconds as the result . This is not difficult , I won't go into details , One thing to note is that you can't simply take a timestamp when recording time , Because switching browsers tab When the game is rAF It will pause automatically , Then the score will continue to count .
️ Mobile compatible
This paragraph is added after the writing of this article , Considering that many people now use their mobile phones to brush articles , So I decided to add mobile support . There are two implementations
- Move to where the player touches
- Add virtual rocker
Because if scheme 1 is used , The player's fingers will block the view , The game experience is poor , So we decided to adopt scheme II , Add a virtual rocker .
Related configuration items of rocker :
In fact, the implementation is very simple , Is to add more parameters to the player spirit , Control mode can be selected , If using touch control , Then add the rocker , By default, the center of the rocker is set at the lower left corner
Then judge if it is touch control , Then monitor the touch event
Then add a field to record the place where the finger is pressed
It is worth noting that , When we touch the position in the center of the rocker , Players don't move , In this way, the operability of the game is much higher . So let's add getter Facilitate subsequent judgment :
Then when updating the player's location , And then distinguish and handle according to different control methods , Calculate the angle between the finger touch position and the center of the joystick, which is the player's moving angle :
Finally, we will draw the joystick on the screen , The implementation is also very simple , Just draw two circles , One is a large background circle , One is the rocker circle of the player's current moving direction .
Be accomplished ! It took less than half an hour to complete the compatible mobile terminal , So a perfect code structure and clear code logic are very important , It can make the subsequent maintenance and function iteration easy .
Ending summary
In general, the implementation is very simple , Not counting the writing time, you can finish this little game in almost one day . At present, there is still much room for code quality optimization , To facilitate reading comprehension , How many repeated logical calculations have not been extracted .
Thinking expansion
At present, only the most basic functions have been realized , If you want to expand , There are many directions to do .
For example, you can add level design , Because bullet speed and bullet density can be dynamically configured . Or add buff items , For example, player acceleration , Reduce the player size to reduce the chance of being hit .
And it's more fun to play with friends than to play alone , You can add another player spirit to use wsad And direction key control , Then we can realize the local battle ( I have the impression that I did it four or five years ago , Two arrows collide and rotate for one second , Increase interactivity ).
You can also add a virtual rocker ️ Mobile compatible , And the game itself depends on one canvas, hold ui Make the interface more beautiful and transplant it to the applet , Maybe it will catch fire in minutes :-D
- Warehouse link :https://github.com/HZFE/dodger-game
- Other recommendations : From writing Loader To spy on the boss Debug Whole process
边栏推荐
- Global and Chinese markets of Leyte coin exchange 2022-2028: Research Report on technology, participants, trends, market size and share
- What is a framework?
- A new weapon to break the memory wall has become a "hot search" in the industry! Persistent memory enables workers to play with massive data + high-dimensional models
- Abnormal dockgeddon causes CPU 100%
- Goby+awvs realize attack surface detection
- What can Lu yuanjiu Jiao buy?
- Where is the most formal and safe account opening for speculation futures? How to open a futures account?
- One Minute! No code! Add [statistical analysis] to the website
- B. Terry sequence (thinking + greed) codeforces round 665 (Div. 2)
- 存在安全隐患 部分冒险家混动版将召回
猜你喜欢

B. Terry sequence (thinking + greed) codeforces round 665 (Div. 2)

Build go command line program tool chain
![[cloud native | kubernetes chapter] Introduction to kubernetes Foundation (III)](/img/21/503ed54a2fa14fbfd67f75a55ec286.png)
[cloud native | kubernetes chapter] Introduction to kubernetes Foundation (III)

Cognition and difference of service number, subscription number, applet and enterprise number (enterprise wechat)
MySQL Advanced Series: Locks - Locks in InnoDB

ZOJ——4104 Sequence in the Pocket(思维问题)

Cap: multiple attention mechanism, interesting fine-grained classification scheme | AAAI 2021
MySQL Advanced Series: locks - locks in InnoDB

Some adventurer hybrid versions with potential safety hazards will be recalled
Advanced programmers must know and master. This article explains in detail the principle of MySQL master-slave synchronization
随机推荐
Global and Chinese markets of Leyte coin exchange 2022-2028: Research Report on technology, participants, trends, market size and share
Load MySQL table data consumption quick installation configuration through kafka/flink
Dismantle the industrial chain of synthetic rubber industry, and the supply chain may become a sharp weapon for breakthrough
Wechat official account debugging and natapp environment building
山金期货安全么?期货开户都是哪些流程?期货手续费怎么降低?
ZOJ - 4104 sequence in the pocket
Annual contribution! Tencent cloud middleware product upgrade conference is in hot registration!
Funny! Pictures and texts give you a comprehensive understanding of the effects of dynamics and mass
Where is the most formal and safe account opening for speculation futures? How to open a futures account?
存在安全隐患 路虎召回部分混动揽运
Transpose convolution explanation
Memo list: useful commands for ffmpeg command line tools
The million bonus competition is about to start, and Ti-One will be upgraded to help you win the championship!
转置卷积详解
2021-04-28: force buckle 546, remove the box. Give some boxes of different colors
Cause analysis of the failure of web page live broadcast on demand RTMP streaming platform easydss streaming live broadcast
Find out the invisible assets -- use hosts collision to break through the boundary
My network relationship with "apifox"
Product level design of a project in SAP mm
Bitwise Operators