DOM+CSS3 realization of small game swingcopters

Source: Internet
Author: User

A few days ago saw a news, Flappybird original author will bring a new game swingcopters attack, ready to rely on this sister piece game to detonate the public eyeball. Is the following little game:

   

The legendary story of the former people have heard, as to whether the second game can be more hot that is something. But I read the author of the propaganda video after the stirring, so simple little game I cottage a Web version out how? Think about it a little bit and plan to use DOM+CSS3 to achieve one. One to strengthen a CSS3 knowledge, and secondly also explore the use of native DOM to do animation performance in the end.
Three or four days later, the original author of the Swingcopters seemingly not how fire up, it seems that the myth of Flappybird is just a coincidence ~ but my cottage version is a model has a kind of made, click here to view the demo, please open under Chrome, you understand. First of all, the overall idea, the basic animation effects, such as moving, rotating, with CSS3 transition, transform+keyframes to do, the basic animation unit into a CSS class, add the corresponding class for the element can let it move, delete, Changing the class allows the element to stop and toggle the animation. As for when to switch, on the one hand is based on the user's operation, on the other hand is based on the game's "main thread" to judge. The so-called "main thread", is to control the game screen constantly refreshed code, the game's main control logic is written here, including scene generation, collision detection and so on. We all know that the animation is produced by the continuous redrawing of the page, when the number of refreshes per second reached 60, the human eye will feel the smooth animation, which is the majority of the game pursuit of 60fps reasons. There are several ways to do frame refresh, see here (http://qingbob.com/javascript-high-performance-animation-and-page-rendering/).     I use requestanimationframe here, it is the advantage of allowing you to use the code to request a frame refresh, which avoids "drop frame", but the negative effect is that when the machine performance is not good, will reduce the frame rate, performance is you see the game animation is slow. Requestanimationframe in the PC side of the support is good, but on the mobile side is a bit down, Android4.4 only support, so it is necessary to do a compatibility deal, fortunately already has the great God to provide code, directly to use:
(function(){    varLasttime = 0; varVendors = [' ms ', ' Moz ', ' webkit ', ' O '];  for(varx = 0; x < vendors.length &&!window.requestanimationframe; ++x) {window.requestanimationframe= Window[vendors[x] + ' requestanimationframe ']; Window.cancelanimationframe= Window[vendors[x] + ' cancelanimationframe '] | | Window[vendors[x] + ' cancelrequestanimationframe ']; }    if(!window.requestanimationframe) Window.requestanimationframe =function(callback, Element) {varCurrtime =NewDate (). GetTime (); varTimetocall = Math.max (0, +-(Currtime-lasttime)); varid = window.settimeout (function() {Callback (Currtime+Timetocall);        }, Timetocall); Lasttime= Currtime +Timetocall; returnID; }    if(!window.cancelanimationframe) Window.cancelanimationframe =function(ID) {cleartimeout (ID); }}());

Below I put some technical details to introduce, between the younger brother is also the first time to do the game, some of the realization of the implementation inevitably go detours, or loss performance, have Daniel found out please be sure to enlighten ~

self-adapting containers
First of all, from the simplest to start, you need a div to do the whole game of the container, because the game to be able to play on the phone, so wide must be made adaptive, then the viewport setting is essential:
<name= "Viewport"  content= "width=device-width,initial-scale=1, Minimum-scale=1,maximum-scale=1,user-scalable=no "/>
That's not much to explain. div default width 100% so do not tube, height to do according to screen 100% display, we need to give the document root node such CSS code:
html, Body {     height: 100%;      position: relative;      margin: 0;      Overflow: hidden;      -webkit-user-select:none;}
Height 100%. Position the attribute relative so that the child element is positioned as a reference. Also overflow:hidden prevents scroll bars from appearing. Finally, User-select:none is added to prevent unsightly selections when users click Continuously.
Next is the style of the container container:
#container {     height: 100%;      position: relative;      Overflow: hidden;}
So the height can fill the whole screen.
In addition, in order to let the game in the PC browser can also play, I also use media query to do the following settings:
{     #container {          width: 360px;           Margin: 0 auto;     } }
Gives the container a width of 360 pixels and centers the alignment. This will not stretch in the PC browser is very difficult to see. Moving Background
    The game's container container has a background image, which requires continuous and infinite scrolling. First, the picture is tiled vertically, a background-repeat:repeat-y; Originally I think of such a simple exercise with CSS3 certainly can do, but after careful consideration found unexpectedly can't realize ... Suppose in the keyframes set Keyframe, change background-position to achieve background movement, moving is not a problem, the key is this continuous infinite scrolling is tricky, to continuous scrolling must give a large value to line, Background-position need to be set to how big is infinite? God knows how long the player can play, and it's obviously unreasonable to do so. or set the number of times the animation is played to infinite? This is not possible, because each cycle starts playing again from the beginning, so that the background flashes. So eventually the movement of the background is placed in the JS to operate, with a variable to record the position of the background, and then in the main thread continuously increment. The approximate code structure is this:
var game = {     function() {          + = 2;          Container.css (' background-position ', ' 0 ' +posmark+ ' px ');           = Requestanimationframe (game.bgmove);}     }
As long as the call to Game.bgmove (), the recursive call through the Requestanimationframe, with a global variable to mark the position of the background, each increment, so as to constantly modify the background position, to achieve infinite movement of the background. gradually play the animated propeller to achieve rotation      In the game, the head of the propeller is constantly rotating, how to achieve this animation? In fact, the principle is very simple, we just need to prepare a picture: This is the left and right to fly a few states, set it as a background image, and then constantly change the position of the background. Note that the background position is not a continuous change, but rather a "toggle" between several values.      CSS3 's KeyFrames + animation are animated by defining keyframes, like Flash, where the transitions between frames are done by the browser. But we don't want a transition here, we just want to play two frames. Here's a special value for animate-timing-function: Steps (), which controls how many steps the animation will take to complete. Here we need the first state in the picture and the second state to switch, so taking steps (2) is OK. Here's the code: first we define keyframes:
@-webkit-keyframes Flyr {     0%{          background-position: 0 0;     }      100%{        background-position: -108px 0;     } }
Then define a class that can be animated by adding the class to the element:
. Flyr {     -webkit-animation:flyr 200ms Steps (2) 0 infinite;}
I directly used the animation this mixed attribute, the meaning of the value is: Animation-name (animation name), Animation-duration (animation time), Animation-delay (start playing time), Animation-iteration-count (played), Animation-direction (play direction), Animation-fill-mode (post-play status), Animation-play-state (     Sets the state of the animation), without writing the default value. Let's take a look at the effect:Similarly to murmured animations, change the value of background-position.     We named Flyl, only need to let the class name of the element in flyl and flyr directly switch, you can change the direction of flight, is not very convenient. One thing to note here is that steps (2) controls the two-step playback, not the state when playing 0% and 100%, but based on the value of the specific CSS property to calculate what the final playback of the two frame is. You can write an example for yourself to see, there is not much to say. Start up Flying      The character is standing on the ground at first, and the game starts up to mid-air, and the vertical position no longer changes. This is better done, we just need to define an animation called up, as follows:
@-webkit-keyframes up {     0%{          bottom: 0;     }      100%{          bottom: 44%;     } }
Then a piece is added to the Flyl class, and multiple animations are separated by commas. So flyl became like this:
. Flyl {    -webkit-animation:flyl 200ms Steps (2) 0 infinite, up 4s linear 0 1 normal forwards;}
Here the value of Animation-iteration-count is 1, because it is only played once. It is also important to note that the animation should remain at the end of this time, so we need to set the Animation-fill-mod value to forwards. movement of characters around      When you change the direction of the flight by clicking on it, the character will move sideways in the direction, how does this work? At first I think simple, move around, and rise is not a reason? So take it for granted to define an animation like this:
@-webkit-keyframes Mover {     0%{          : 0;      }      100%{          : 100%;     } }
Just add a comma at the back of the flyl, plus movel.     or defined as a class that adds this class to the character to move to the left. But it turns out to be wrong. Because in practice, changing the direction of the flight can occur at any moment, and at this time the left value of the character may be 20, 50, or any other value. What we need is a change based on the current left, rather than having it zeroed in first.     So we can't use keyframes here, because we can't always determine how much this initial left is. This time CSS3 transition come in handy, its role is to automatically create tweened animation, but not animation so complex, just to indicate which properties need to transition. So, my flyl and Flyr became like this:
. Flyl {     left: 0!important;      -webkit-animation:flyl 200ms Steps (2) 0 infinite, up 4s linear 0 1 normal forwards;} . Flyr {     left: 100%!important;      -webkit-animation:flyr 200ms Steps (2) 0 infinite, up 4s linear 0 1 normal forwards;}   
At the same time, our player has to add this line:
-webkit-transition:left 1.5s 0 linear;
So we cleverly get rid of the previous predicament, just specify left can, tube it is from which value change, to transition transition to just fine. Now just listen for the click event and switch class for the character based on the player's click, so we can fly back and forth. The JS code is as follows:
function () {               if(++direction%2==0) {                    player[0].classname = ' flyl ';               }                Else {                    player[0].classname = ' Flyr ';               }          });
We use a variable direction to record the current direction, each click to increment it, and then change the classname according to the parity. The reason for using variables to record the current direction instead of using Hasclass is to reduce DOM access. the generation and movement of pendulum hammers      First of all, the pendulum of the swinging animation, this is actually not difficult, with transform:rotate control rotation of a certain angle can be. One thing to note is that transform's morph dot defaults to the center of the element, and our pendulum is not rotated in place, so the center of rotation should be controlled at the top of the element, and we use the Transform-origin to set the shape of the deform dot, the code is as follows:
-webkit-transform-origin:center 4px;
The pendulum is hung on the beam, the beam is moved from top to bottom, in the movement of the beam actually contains the main logic of our game: 1. Produces a length random beam 2. Detects the impact of the pendulum against the aircraft 3. Fly over a beam and score 1 4. The beam moves out of the screen visual range, remove node here with pure CSS to achieve the movement of the beam, there will be some logic can not be implemented, which must have JS to control.     So the beam/pendulum is placed in the "main thread" of our game.     A simple idea: there are two constants, which represent the horizontal and vertical distances between the beams, and we need to define the minimum and maximum lengths of the beams, create a random number between the two values as the length of the left beam, and then calculate the length of the right beam based on the horizontal distance.     As for the collision detection, I simply deal with it here (considering the pendulum is constantly swinging), directly with a circular model, that is, the distance of two centers is less than the sum of the radius is considered to have collided.     The calculation score is also relatively simple, as long as the top value of the beam is greater than the top value of the aircraft, it is believed to have crossed the beam, scored 1.     Finally, when the top value of the beam is greater than the height of the entire container, it shows that it has moved out of the visual range, removing the node directly, and avoiding the DOM node too many times after the game has been running. Here is the code for the main thread:
Bgmove:function() {Game.generatehand ();//Generating beamsPosmark + = 2; Container.css (' Background-position ', ' 0 ' +posmark+ ' px '); varHands = $ ('. hand_l,. Hand_r ')); Hands.each (function(index, Element) {var_this = $ ( This), Thistop= parseint (_this.css (' top '))); if(thistop>cheight)               {_this.remove (); }               Else{thistop+ = 2; _this.css (' Top ', thistop+ ' px '); }               if(Thistop>player.offset (). top+e1h) {                    //is already located below                    if(!_this.data (' Pass ') && index%2==0) {Scroec.text (++score); _this.data (' Pass ', 1); }               }               Else{                    //Collision Detection                    if(Game.impactcheck (Player, _this.find ('. T '))) {game.stop (); return false;          }               }                        }); Timmer=Requestanimationframe (Game.bgmove); }
You will find that there are a lot of bad places in it, for example, every time you refresh a frame you will use $ ('. hand_l,. Hand_r ') to fetch all the beam nodes on the page, so that scanning the DOM tree is quite time consuming. It is perfectly possible to put these nodes in an array.  When the beam is generated, push in the array is removed from the array when remove is required. At this point, the key part of this little game is all done. The rest is the control part of the game, stop, restart what, in fact, as long as the control game parameter variables and class reset, Cancelanimationframe, OK. pc and mobile compatibleThe compatibility here mainly refers to the Click event 300ms delay, because the game, even a little bit of delay will be uncomfortable. So I checked the device type, and if it's mobile, it binds the Touchstart event, and the code snippet is as follows:
IsMobile:function(){          varSuseragent=navigator.userAgent.toLowerCase (), Bisipad= Suseragent.match (/ipad/i) = = "ipad", Bisiphoneos= Suseragent.match (/iphone os/i) = = "iphone OS", BISMIDP= Suseragent.match (/midp/i) = = "MIDP", BIsUc7= Suseragent.match (/rv:1.2.3.4/i) = = "rv:1.2.3.4", Bisuc= Suseragent.match (/ucweb/i) = = "UCWeb", Bisandroid= Suseragent.match (/android/i) = = "Android", Bisce= Suseragent.match (/windows ce/i) = = "Windows CE", Biswm= Suseragent.match (/windows mobile/i) = = "Windows Mobile", Biswebview= Suseragent.match (/webview/i) = = "WebView"; return(Bisipad | | bisiphoneos | | bismidp | | bIsUc7 | | bisuc | | bisandroid | | bisce | |biswm); }varEventType = This. IsMobile ()? ' Touchstart ': ' Click '; $ (document). On (EventType,function(){               if(++direction%2==0) {player[0].classname = ' flyl '; }               Else{player[0].classname = ' Flyr '; }          });
share to WeiboIn order to make the game easy to spread, in the online search for a share to the microblog code, try to use, directly affixed to:
<id= "Share"  href= "javascript: (function () {window.open ('/HTTP/ v.t.sina.com.cn/share/share.php?title= Web version swingcopters, come on, see how much you have &url=idoube.com/proj/swingcopters&source =bookmark&pic=http%3a%2f%2fidoube.com%2fproj%2fswingcopters%2fswingcopters%2fshot.jpg ', ' _blank ', ' width=450 , height=400 ');}) () "> share to Weibo </a>
In fact, on the phone, but also should be added to share, but I played on the phone after the game, immediately felt no need. Because, on the phone, that card Ah!! FPS is estimated at around 20.  Well-configured Samsung even so, you can imagine what other Android opportunities are. Another welcome is that playing on the iphone is quite a process!  I also have to admire the processing of graphics rendering in iOS. However, if you do this kind of animation more games later, I would certainly not choose to use the DOM to do. SummaryThis is the first time the landlord to write a small game, although the final game smarty Pants can play, but write too hasty, some knowledge also did not delve into the middle of some pits, the overall code quality is not high. Let's make a list here: 1. Some of the animation is done with pure CSS3, some are written in JS, in the end how to classify the animation should be carefully considered 2. Without performance monitoring, my machine has a high configuration and can run close to 60fps in Chrome. But feeling the code is not very efficient in some places.  The card explodes directly on the Android machine. 3. The code is simple, JS uses a lot of global variables.  Because previously heard people said, simple program directly with the global variables on the line, high performance, but no proof of this statement, do not know the right or not, there are experts know please pointing. 4. For more animation of small games, using DOM to do is not a very good choice, because the phone card, can not be shared, the effect is directly discounted.  Next time try to write with canvas.   5. The entire code is also the operation of the DOM thinking, in fact, the game should be in object-oriented style to organize the code. Attach the game address again, welcome to experience: Http://idoube.com/proj/SwingCopters/finally recommended a document that I often refer to when I write CSS3 animation: http://ecd.tencent.com/css3/guide.html

DOM+CSS3 realization of small game swingcopters

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.